From 54cdf1c235c2985f3e25b78ef950db831cf1cefd Mon Sep 17 00:00:00 2001 From: erikmelin <31467290+erikmelin@users.noreply.github.com> Date: Wed, 30 Aug 2017 08:57:46 +0200 Subject: [PATCH] MeOS version 3.4.717 --- code/HTMLWriter.cpp | 522 + code/MeOSFeatures.cpp | 251 + code/MeOSFeatures.h | 103 + code/Printer.h | 116 + code/RunnerDB.cpp | 1232 + code/RunnerDB.h | 249 + code/SportIdent.cpp | 2341 ++ code/SportIdent.h | 227 + code/StdAfx.cpp | 12 + code/StdAfx.h | 55 + code/TabAuto.cpp | 1142 + code/TabAuto.h | 287 + code/TabBase.cpp | 211 + code/TabBase.h | 156 + code/TabClass.cpp | 3930 +++ code/TabClass.h | 161 + code/TabClub.cpp | 786 + code/TabClub.h | 63 + code/TabCompetition.cpp | 3853 +++ code/TabCompetition.h | 150 + code/TabControl.cpp | 529 + code/TabControl.h | 52 + code/TabCourse.cpp | 1158 + code/TabCourse.h | 77 + code/TabList.cpp | 2106 ++ code/TabList.h | 115 + code/TabMulti.cpp | 50 + code/TabMulti.h | 32 + code/TabRunner.cpp | 2744 ++ code/TabRunner.h | 114 + code/TabSI.cpp | 3584 +++ code/TabSI.h | 229 + code/TabSpeaker.cpp | 1048 + code/TabSpeaker.h | 117 + code/TabTeam.cpp | 1899 ++ code/TabTeam.h | 93 + code/Table.cpp | 2316 ++ code/Table.h | 374 + code/TimeStamp.cpp | 134 + code/TimeStamp.h | 49 + code/autotask.cpp | 338 + code/autotask.h | 74 + code/bitmap1.bmp | Bin 0 -> 8694 bytes code/classconfiginfo.cpp | 207 + code/classconfiginfo.h | 90 + code/cp1250.lng | 1 + code/cp1255.lng | 1 + code/csvparser.cpp | 1254 + code/csvparser.h | 139 + code/danish.lng | 2237 ++ code/download.cpp | 457 + code/download.h | 91 + code/english.lng | 2241 ++ code/french.lng | 2241 ++ code/gdiconstants.h | 44 + code/gdifonts.h | 78 + code/gdiimpl.h | 76 + code/gdioutput.cpp | 6544 ++++ code/gdioutput.h | 654 + code/gdistructures.h | 402 + code/generalresult.cpp | 1297 + code/generalresult.h | 221 + code/german.lng | 1027 + code/guihandler.h | 45 + code/importformats.cpp | 110 + code/importformats.h | 64 + code/infoserver.cpp | 688 + code/infoserver.h | 219 + code/inthashmap.h | 27 + code/intkeymap.hpp | 78 + code/intkeymapimpl.hpp | 374 + code/iof30interface.cpp | 3508 +++ code/iof30interface.h | 290 + code/lib/libhpdf.lib | Bin 0 -> 73406 bytes code/lib/mysqlpp.lib | Bin 0 -> 567206 bytes code/lib/mysqlpp_vc15.lib | Bin 0 -> 737200 bytes code/lib/zlibstat.lib | Bin 0 -> 205428 bytes code/lib_db/libhpdf.lib | Bin 0 -> 73406 bytes code/lib_db/mysqlpp.lib | Bin 0 -> 570796 bytes code/lib_db/mysqlpp_vc15.lib | Bin 0 -> 753726 bytes code/lib_db/zlibstat.lib | Bin 0 -> 383406 bytes code/lib_db/zlibstat_vc15.lib | Bin 0 -> 978270 bytes code/libharu/hpdf.h | 1562 + code/libharu/hpdf_3dmeasure.h | 57 + code/libharu/hpdf_annotation.h | 95 + code/libharu/hpdf_catalog.h | 93 + code/libharu/hpdf_conf.h | 85 + code/libharu/hpdf_config.h | 75 + code/libharu/hpdf_consts.h | 549 + code/libharu/hpdf_destination.h | 44 + code/libharu/hpdf_doc.h | 162 + code/libharu/hpdf_encoder.h | 318 + code/libharu/hpdf_encrypt.h | 159 + code/libharu/hpdf_encryptdict.h | 69 + code/libharu/hpdf_error.h | 203 + code/libharu/hpdf_exdata.h | 41 + code/libharu/hpdf_ext_gstate.h | 41 + code/libharu/hpdf_font.h | 115 + code/libharu/hpdf_fontdef.h | 406 + code/libharu/hpdf_gstate.h | 83 + code/libharu/hpdf_image.h | 99 + code/libharu/hpdf_info.h | 51 + code/libharu/hpdf_list.h | 88 + code/libharu/hpdf_mmgr.h | 85 + code/libharu/hpdf_namedict.h | 76 + code/libharu/hpdf_objects.h | 604 + code/libharu/hpdf_outline.h | 77 + code/libharu/hpdf_page_label.h | 38 + code/libharu/hpdf_pages.h | 131 + code/libharu/hpdf_pdfa.h | 43 + code/libharu/hpdf_streams.h | 280 + code/libharu/hpdf_types.h | 565 + code/libharu/hpdf_u3d.h | 52 + code/libharu/hpdf_utils.h | 165 + code/libharu/hpdf_version.h | 8 + code/license.txt | 688 + code/listeditor.cpp | 1201 + code/listeditor.h | 82 + code/liveresult.cpp | 435 + code/liveresult.h | 68 + code/localizer.cpp | 460 + code/localizer.h | 76 + code/meos.cpp | 1745 ++ code/meos.dsp | 293 + code/meos.h | 11 + code/meos.ico | Bin 0 -> 35670 bytes code/meos.rc | 177 + code/meos.sln | 29 + code/meos.vcproj | 1360 + code/meos.vcxproj | 470 + code/meos_util.cpp | 1857 ++ code/meos_util.h | 236 + code/meos_vc10.sln | 31 + code/meos_vc15.sln | 25 + code/meosdb/MeosSQL.cpp | 3664 +++ code/meosdb/MeosSQL.h | 184 + code/meosdb/dllmain.cpp | 19 + code/meosdb/meosdb.cpp | 266 + code/meosdb/meosdb.h | 29 + code/meosdb/meosdb.vcproj | 391 + code/meosdb/meosdb.vcxproj | 158 + code/meosdb/mysql++/Doxyfile.in | 1258 + code/meosdb/mysql++/autoflag.h | 57 + code/meosdb/mysql++/coldata.cpp | 37 + code/meosdb/mysql++/coldata.h | 386 + code/meosdb/mysql++/common.h | 161 + code/meosdb/mysql++/connection.cpp | 725 + code/meosdb/mysql++/connection.h | 579 + code/meosdb/mysql++/const_string.h | 258 + code/meosdb/mysql++/convert.h | 117 + code/meosdb/mysql++/custom-macros.h | 24938 ++++++++++++++++ code/meosdb/mysql++/custom.h | 98 + code/meosdb/mysql++/custom.pl | 924 + code/meosdb/mysql++/datetime.cpp | 219 + code/meosdb/mysql++/datetime.h | 384 + code/meosdb/mysql++/exceptions.h | 352 + code/meosdb/mysql++/field_names.cpp | 48 + code/meosdb/mysql++/field_names.h | 105 + code/meosdb/mysql++/field_types.cpp | 45 + code/meosdb/mysql++/field_types.h | 97 + code/meosdb/mysql++/fields.cpp | 44 + code/meosdb/mysql++/fields.h | 73 + code/meosdb/mysql++/lockable.h | 163 + code/meosdb/mysql++/manip.cpp | 546 + code/meosdb/mysql++/manip.h | 680 + code/meosdb/mysql++/myset.cpp | 35 + code/meosdb/mysql++/myset.h | 157 + code/meosdb/mysql++/mysql++.cpp | 38 + code/meosdb/mysql++/mysql++.h | 140 + code/meosdb/mysql++/mysql++.h.in | 140 + code/meosdb/mysql++/noexceptions.h | 138 + code/meosdb/mysql++/null.h | 278 + code/meosdb/mysql++/qparms.cpp | 69 + code/meosdb/mysql++/qparms.h | 255 + code/meosdb/mysql++/query.cpp | 656 + code/meosdb/mysql++/query.h | 930 + code/meosdb/mysql++/querydef.h | 118 + code/meosdb/mysql++/querydef.pl | 104 + code/meosdb/mysql++/resiter.h | 278 + code/meosdb/mysql++/result.cpp | 239 + code/meosdb/mysql++/result.h | 472 + code/meosdb/mysql++/row.cpp | 186 + code/meosdb/mysql++/row.h | 479 + code/meosdb/mysql++/sql_string.cpp | 178 + code/meosdb/mysql++/sql_string.h | 143 + code/meosdb/mysql++/sql_types.h | 85 + code/meosdb/mysql++/stream2string.h | 56 + code/meosdb/mysql++/string_util.cpp | 145 + code/meosdb/mysql++/string_util.h | 61 + code/meosdb/mysql++/tiny_int.h | 239 + code/meosdb/mysql++/transaction.cpp | 97 + code/meosdb/mysql++/transaction.h | 91 + code/meosdb/mysql++/type_info.cpp | 192 + code/meosdb/mysql++/type_info.h | 368 + code/meosdb/mysql++/vallist.cpp | 144 + code/meosdb/mysql++/vallist.h | 688 + code/meosdb/mysql50/config-win.h | 459 + code/meosdb/mysql50/decimal.h | 107 + code/meosdb/mysql50/errmsg.h | 102 + code/meosdb/mysql50/keycache.h | 138 + code/meosdb/mysql50/libmysql.def | 154 + code/meosdb/mysql50/m_ctype.h | 509 + code/meosdb/mysql50/m_string.h | 265 + code/meosdb/mysql50/my_alloc.h | 51 + code/meosdb/mysql50/my_attribute.h | 63 + code/meosdb/mysql50/my_dbug.h | 107 + code/meosdb/mysql50/my_dir.h | 105 + code/meosdb/mysql50/my_getopt.h | 76 + code/meosdb/mysql50/my_global.h | 1352 + code/meosdb/mysql50/my_list.h | 45 + code/meosdb/mysql50/my_net.h | 134 + code/meosdb/mysql50/my_no_pthread.h | 54 + code/meosdb/mysql50/my_pthread.h | 812 + code/meosdb/mysql50/my_sys.h | 924 + code/meosdb/mysql50/my_xml.h | 66 + code/meosdb/mysql50/mysql.h | 864 + code/meosdb/mysql50/mysql_com.h | 463 + code/meosdb/mysql50/mysql_embed.h | 31 + code/meosdb/mysql50/mysql_time.h | 55 + code/meosdb/mysql50/mysql_version.h | 29 + code/meosdb/mysql50/mysqld_ername.h | 474 + code/meosdb/mysql50/mysqld_error.h | 476 + code/meosdb/mysql50/raid.h | 158 + code/meosdb/mysql50/sql_common.h | 47 + code/meosdb/mysql50/sql_state.h | 201 + code/meosdb/mysql50/sslopt-case.h | 28 + code/meosdb/mysql50/sslopt-longopts.h | 45 + code/meosdb/mysql50/sslopt-vars.h | 31 + code/meosdb/mysql50/typelib.h | 36 + code/meosdb/mysql55/decimal.h | 107 + code/meosdb/mysql55/errmsg.h | 108 + code/meosdb/mysql55/keycache.h | 146 + code/meosdb/mysql55/m_ctype.h | 660 + code/meosdb/mysql55/m_string.h | 295 + code/meosdb/mysql55/my_alloc.h | 60 + code/meosdb/mysql55/my_attribute.h | 69 + code/meosdb/mysql55/my_compiler.h | 145 + code/meosdb/mysql55/my_config.h | 618 + code/meosdb/mysql55/my_dbug.h | 194 + code/meosdb/mysql55/my_dir.h | 109 + code/meosdb/mysql55/my_getopt.h | 123 + code/meosdb/mysql55/my_global.h | 1483 + code/meosdb/mysql55/my_list.h | 45 + code/meosdb/mysql55/my_net.h | 110 + code/meosdb/mysql55/my_pthread.h | 943 + code/meosdb/mysql55/my_sys.h | 959 + code/meosdb/mysql55/my_xml.h | 89 + code/meosdb/mysql55/mysql.h | 713 + code/meosdb/mysql55/mysql/client_plugin.h | 163 + code/meosdb/mysql55/mysql/innodb_priv.h | 36 + code/meosdb/mysql55/mysql/plugin.h | 633 + code/meosdb/mysql55/mysql/plugin_audit.h | 138 + code/meosdb/mysql55/mysql/plugin_auth.h | 125 + .../meosdb/mysql55/mysql/plugin_auth_common.h | 105 + code/meosdb/mysql55/mysql/plugin_ftparser.h | 211 + code/meosdb/mysql55/mysql/psi/mysql_file.h | 1434 + code/meosdb/mysql55/mysql/psi/mysql_thread.h | 1071 + code/meosdb/mysql55/mysql/psi/psi.h | 1312 + code/meosdb/mysql55/mysql/psi/psi_abi_v1.h | 26 + code/meosdb/mysql55/mysql/psi/psi_abi_v2.h | 26 + .../mysql55/mysql/service_my_snprintf.h | 101 + code/meosdb/mysql55/mysql/service_thd_alloc.h | 130 + code/meosdb/mysql55/mysql/service_thd_wait.h | 83 + .../mysql55/mysql/service_thread_scheduler.h | 65 + code/meosdb/mysql55/mysql/services.h | 32 + code/meosdb/mysql55/mysql_com.h | 572 + code/meosdb/mysql55/mysql_embed.h | 31 + code/meosdb/mysql55/mysql_time.h | 55 + code/meosdb/mysql55/mysql_version.h | 30 + code/meosdb/mysql55/mysqld_ername.h | 708 + code/meosdb/mysql55/mysqld_error.h | 710 + code/meosdb/mysql55/plugin.h | 633 + code/meosdb/mysql55/plugin_audit.h | 138 + code/meosdb/mysql55/plugin_ftparser.h | 211 + code/meosdb/mysql55/sql_common.h | 113 + code/meosdb/mysql55/sql_state.h | 220 + code/meosdb/mysql55/sslopt-case.h | 32 + code/meosdb/mysql55/sslopt-longopts.h | 49 + code/meosdb/mysql55/sslopt-vars.h | 35 + code/meosdb/mysql55/typelib.h | 44 + code/meosdb/sqltypes.h | 59 + code/meosdb/stdafx.cpp | 14 + code/meosdb/stdafx.h | 29 + code/meosdb/targetver.h | 48 + code/meosexception.h | 31 + code/meoslang.rc | 19 + code/meosvc15.vcxproj | 477 + code/meosversion.cpp | 172 + code/metalist.cpp | 2499 ++ code/metalist.h | 411 + code/methodeditor.cpp | 1067 + code/methodeditor.h | 75 + code/minizip/crc32.h | 441 + code/minizip/crypt.h | 131 + code/minizip/deflate.h | 342 + code/minizip/gzguts.h | 132 + code/minizip/inffast.h | 11 + code/minizip/inffixed.h | 94 + code/minizip/inflate.h | 122 + code/minizip/inftrees.h | 62 + code/minizip/ioapi.h | 200 + code/minizip/iowin32.h | 28 + code/minizip/mztools.h | 31 + code/minizip/trees.h | 128 + code/minizip/unzip.h | 437 + code/minizip/zconf.h | 428 + code/minizip/zip.h | 362 + code/minizip/zlib.h | 1613 + code/minizip/zutil.h | 274 + code/mysqldaemon.cpp | 169 + code/newcompetition.cpp | 394 + code/oBase.cpp | 190 + code/oBase.h | 179 + code/oCard.cpp | 780 + code/oCard.h | 145 + code/oClass.cpp | 4154 +++ code/oClass.h | 571 + code/oClub.cpp | 1152 + code/oClub.h | 193 + code/oControl.cpp | 1000 + code/oControl.h | 236 + code/oCourse.cpp | 1389 + code/oCourse.h | 239 + code/oDataContainer.cpp | 1323 + code/oDataContainer.h | 378 + code/oEvent.cpp | 6443 ++++ code/oEvent.h | 1288 + code/oEventDraw.cpp | 1435 + code/oEventDraw.h | 121 + code/oEventResult.cpp | 513 + code/oEventSQL.cpp | 975 + code/oEventSpeaker.cpp | 1874 ++ code/oFreeImport.cpp | 1852 ++ code/oFreeImport.h | 255 + code/oFreePunch.cpp | 720 + code/oFreePunch.h | 97 + code/oImportExport.cpp | 2713 ++ code/oListInfo.cpp | 4240 +++ code/oListInfo.h | 500 + code/oPunch.cpp | 184 + code/oPunch.h | 109 + code/oReport.cpp | 685 + code/oRunner.cpp | 5559 ++++ code/oRunner.h | 755 + code/oTeam.cpp | 2162 ++ code/oTeam.h | 221 + code/oTeamEvent.cpp | 723 + code/onlineinput.cpp | 386 + code/onlineinput.h | 75 + code/onlineresults.cpp | 516 + code/onlineresults.h | 69 + code/ospeaker.h | 89 + code/parser.cpp | 1632 + code/parser.h | 301 + code/pdfwriter.cpp | 313 + code/pdfwriter.h | 60 + code/prefseditor.cpp | 185 + code/prefseditor.h | 50 + code/printer.cpp | 833 + code/progress.cpp | 229 + code/progress.h | 54 + code/random.cpp | 322 + code/random.h | 30 + code/recorder.cpp | 74 + code/recorder.h | 47 + code/resource.h | 25 + code/russian.lng | 1890 ++ code/small.ico | Bin 0 -> 1718 bytes code/socket.cpp | 183 + code/socket.h | 72 + code/speakermonitor.cpp | 790 + code/speakermonitor.h | 141 + code/swedish.lng | 2241 ++ code/testmeos.cpp | 453 + code/testmeos.h | 147 + code/tests.cpp | 14 + code/thirdpartylicense.txt | 114 + code/toolbar.cpp | 321 + code/toolbar.h | 67 + code/xmlparser.cpp | 766 + code/xmlparser.h | 223 + code/zip.cpp | 460 + 382 files changed, 211285 insertions(+) create mode 100644 code/HTMLWriter.cpp create mode 100644 code/MeOSFeatures.cpp create mode 100644 code/MeOSFeatures.h create mode 100644 code/Printer.h create mode 100644 code/RunnerDB.cpp create mode 100644 code/RunnerDB.h create mode 100644 code/SportIdent.cpp create mode 100644 code/SportIdent.h create mode 100644 code/StdAfx.cpp create mode 100644 code/StdAfx.h create mode 100644 code/TabAuto.cpp create mode 100644 code/TabAuto.h create mode 100644 code/TabBase.cpp create mode 100644 code/TabBase.h create mode 100644 code/TabClass.cpp create mode 100644 code/TabClass.h create mode 100644 code/TabClub.cpp create mode 100644 code/TabClub.h create mode 100644 code/TabCompetition.cpp create mode 100644 code/TabCompetition.h create mode 100644 code/TabControl.cpp create mode 100644 code/TabControl.h create mode 100644 code/TabCourse.cpp create mode 100644 code/TabCourse.h create mode 100644 code/TabList.cpp create mode 100644 code/TabList.h create mode 100644 code/TabMulti.cpp create mode 100644 code/TabMulti.h create mode 100644 code/TabRunner.cpp create mode 100644 code/TabRunner.h create mode 100644 code/TabSI.cpp create mode 100644 code/TabSI.h create mode 100644 code/TabSpeaker.cpp create mode 100644 code/TabSpeaker.h create mode 100644 code/TabTeam.cpp create mode 100644 code/TabTeam.h create mode 100644 code/Table.cpp create mode 100644 code/Table.h create mode 100644 code/TimeStamp.cpp create mode 100644 code/TimeStamp.h create mode 100644 code/autotask.cpp create mode 100644 code/autotask.h create mode 100644 code/bitmap1.bmp create mode 100644 code/classconfiginfo.cpp create mode 100644 code/classconfiginfo.h create mode 100644 code/cp1250.lng create mode 100644 code/cp1255.lng create mode 100644 code/csvparser.cpp create mode 100644 code/csvparser.h create mode 100644 code/danish.lng create mode 100644 code/download.cpp create mode 100644 code/download.h create mode 100644 code/english.lng create mode 100644 code/french.lng create mode 100644 code/gdiconstants.h create mode 100644 code/gdifonts.h create mode 100644 code/gdiimpl.h create mode 100644 code/gdioutput.cpp create mode 100644 code/gdioutput.h create mode 100644 code/gdistructures.h create mode 100644 code/generalresult.cpp create mode 100644 code/generalresult.h create mode 100644 code/german.lng create mode 100644 code/guihandler.h create mode 100644 code/importformats.cpp create mode 100644 code/importformats.h create mode 100644 code/infoserver.cpp create mode 100644 code/infoserver.h create mode 100644 code/inthashmap.h create mode 100644 code/intkeymap.hpp create mode 100644 code/intkeymapimpl.hpp create mode 100644 code/iof30interface.cpp create mode 100644 code/iof30interface.h create mode 100644 code/lib/libhpdf.lib create mode 100644 code/lib/mysqlpp.lib create mode 100644 code/lib/mysqlpp_vc15.lib create mode 100644 code/lib/zlibstat.lib create mode 100644 code/lib_db/libhpdf.lib create mode 100644 code/lib_db/mysqlpp.lib create mode 100644 code/lib_db/mysqlpp_vc15.lib create mode 100644 code/lib_db/zlibstat.lib create mode 100644 code/lib_db/zlibstat_vc15.lib create mode 100644 code/libharu/hpdf.h create mode 100644 code/libharu/hpdf_3dmeasure.h create mode 100644 code/libharu/hpdf_annotation.h create mode 100644 code/libharu/hpdf_catalog.h create mode 100644 code/libharu/hpdf_conf.h create mode 100644 code/libharu/hpdf_config.h create mode 100644 code/libharu/hpdf_consts.h create mode 100644 code/libharu/hpdf_destination.h create mode 100644 code/libharu/hpdf_doc.h create mode 100644 code/libharu/hpdf_encoder.h create mode 100644 code/libharu/hpdf_encrypt.h create mode 100644 code/libharu/hpdf_encryptdict.h create mode 100644 code/libharu/hpdf_error.h create mode 100644 code/libharu/hpdf_exdata.h create mode 100644 code/libharu/hpdf_ext_gstate.h create mode 100644 code/libharu/hpdf_font.h create mode 100644 code/libharu/hpdf_fontdef.h create mode 100644 code/libharu/hpdf_gstate.h create mode 100644 code/libharu/hpdf_image.h create mode 100644 code/libharu/hpdf_info.h create mode 100644 code/libharu/hpdf_list.h create mode 100644 code/libharu/hpdf_mmgr.h create mode 100644 code/libharu/hpdf_namedict.h create mode 100644 code/libharu/hpdf_objects.h create mode 100644 code/libharu/hpdf_outline.h create mode 100644 code/libharu/hpdf_page_label.h create mode 100644 code/libharu/hpdf_pages.h create mode 100644 code/libharu/hpdf_pdfa.h create mode 100644 code/libharu/hpdf_streams.h create mode 100644 code/libharu/hpdf_types.h create mode 100644 code/libharu/hpdf_u3d.h create mode 100644 code/libharu/hpdf_utils.h create mode 100644 code/libharu/hpdf_version.h create mode 100644 code/license.txt create mode 100644 code/listeditor.cpp create mode 100644 code/listeditor.h create mode 100644 code/liveresult.cpp create mode 100644 code/liveresult.h create mode 100644 code/localizer.cpp create mode 100644 code/localizer.h create mode 100644 code/meos.cpp create mode 100644 code/meos.dsp create mode 100644 code/meos.h create mode 100644 code/meos.ico create mode 100644 code/meos.rc create mode 100644 code/meos.sln create mode 100644 code/meos.vcproj create mode 100644 code/meos.vcxproj create mode 100644 code/meos_util.cpp create mode 100644 code/meos_util.h create mode 100644 code/meos_vc10.sln create mode 100644 code/meos_vc15.sln create mode 100644 code/meosdb/MeosSQL.cpp create mode 100644 code/meosdb/MeosSQL.h create mode 100644 code/meosdb/dllmain.cpp create mode 100644 code/meosdb/meosdb.cpp create mode 100644 code/meosdb/meosdb.h create mode 100644 code/meosdb/meosdb.vcproj create mode 100644 code/meosdb/meosdb.vcxproj create mode 100644 code/meosdb/mysql++/Doxyfile.in create mode 100644 code/meosdb/mysql++/autoflag.h create mode 100644 code/meosdb/mysql++/coldata.cpp create mode 100644 code/meosdb/mysql++/coldata.h create mode 100644 code/meosdb/mysql++/common.h create mode 100644 code/meosdb/mysql++/connection.cpp create mode 100644 code/meosdb/mysql++/connection.h create mode 100644 code/meosdb/mysql++/const_string.h create mode 100644 code/meosdb/mysql++/convert.h create mode 100644 code/meosdb/mysql++/custom-macros.h create mode 100644 code/meosdb/mysql++/custom.h create mode 100644 code/meosdb/mysql++/custom.pl create mode 100644 code/meosdb/mysql++/datetime.cpp create mode 100644 code/meosdb/mysql++/datetime.h create mode 100644 code/meosdb/mysql++/exceptions.h create mode 100644 code/meosdb/mysql++/field_names.cpp create mode 100644 code/meosdb/mysql++/field_names.h create mode 100644 code/meosdb/mysql++/field_types.cpp create mode 100644 code/meosdb/mysql++/field_types.h create mode 100644 code/meosdb/mysql++/fields.cpp create mode 100644 code/meosdb/mysql++/fields.h create mode 100644 code/meosdb/mysql++/lockable.h create mode 100644 code/meosdb/mysql++/manip.cpp create mode 100644 code/meosdb/mysql++/manip.h create mode 100644 code/meosdb/mysql++/myset.cpp create mode 100644 code/meosdb/mysql++/myset.h create mode 100644 code/meosdb/mysql++/mysql++.cpp create mode 100644 code/meosdb/mysql++/mysql++.h create mode 100644 code/meosdb/mysql++/mysql++.h.in create mode 100644 code/meosdb/mysql++/noexceptions.h create mode 100644 code/meosdb/mysql++/null.h create mode 100644 code/meosdb/mysql++/qparms.cpp create mode 100644 code/meosdb/mysql++/qparms.h create mode 100644 code/meosdb/mysql++/query.cpp create mode 100644 code/meosdb/mysql++/query.h create mode 100644 code/meosdb/mysql++/querydef.h create mode 100644 code/meosdb/mysql++/querydef.pl create mode 100644 code/meosdb/mysql++/resiter.h create mode 100644 code/meosdb/mysql++/result.cpp create mode 100644 code/meosdb/mysql++/result.h create mode 100644 code/meosdb/mysql++/row.cpp create mode 100644 code/meosdb/mysql++/row.h create mode 100644 code/meosdb/mysql++/sql_string.cpp create mode 100644 code/meosdb/mysql++/sql_string.h create mode 100644 code/meosdb/mysql++/sql_types.h create mode 100644 code/meosdb/mysql++/stream2string.h create mode 100644 code/meosdb/mysql++/string_util.cpp create mode 100644 code/meosdb/mysql++/string_util.h create mode 100644 code/meosdb/mysql++/tiny_int.h create mode 100644 code/meosdb/mysql++/transaction.cpp create mode 100644 code/meosdb/mysql++/transaction.h create mode 100644 code/meosdb/mysql++/type_info.cpp create mode 100644 code/meosdb/mysql++/type_info.h create mode 100644 code/meosdb/mysql++/vallist.cpp create mode 100644 code/meosdb/mysql++/vallist.h create mode 100644 code/meosdb/mysql50/config-win.h create mode 100644 code/meosdb/mysql50/decimal.h create mode 100644 code/meosdb/mysql50/errmsg.h create mode 100644 code/meosdb/mysql50/keycache.h create mode 100644 code/meosdb/mysql50/libmysql.def create mode 100644 code/meosdb/mysql50/m_ctype.h create mode 100644 code/meosdb/mysql50/m_string.h create mode 100644 code/meosdb/mysql50/my_alloc.h create mode 100644 code/meosdb/mysql50/my_attribute.h create mode 100644 code/meosdb/mysql50/my_dbug.h create mode 100644 code/meosdb/mysql50/my_dir.h create mode 100644 code/meosdb/mysql50/my_getopt.h create mode 100644 code/meosdb/mysql50/my_global.h create mode 100644 code/meosdb/mysql50/my_list.h create mode 100644 code/meosdb/mysql50/my_net.h create mode 100644 code/meosdb/mysql50/my_no_pthread.h create mode 100644 code/meosdb/mysql50/my_pthread.h create mode 100644 code/meosdb/mysql50/my_sys.h create mode 100644 code/meosdb/mysql50/my_xml.h create mode 100644 code/meosdb/mysql50/mysql.h create mode 100644 code/meosdb/mysql50/mysql_com.h create mode 100644 code/meosdb/mysql50/mysql_embed.h create mode 100644 code/meosdb/mysql50/mysql_time.h create mode 100644 code/meosdb/mysql50/mysql_version.h create mode 100644 code/meosdb/mysql50/mysqld_ername.h create mode 100644 code/meosdb/mysql50/mysqld_error.h create mode 100644 code/meosdb/mysql50/raid.h create mode 100644 code/meosdb/mysql50/sql_common.h create mode 100644 code/meosdb/mysql50/sql_state.h create mode 100644 code/meosdb/mysql50/sslopt-case.h create mode 100644 code/meosdb/mysql50/sslopt-longopts.h create mode 100644 code/meosdb/mysql50/sslopt-vars.h create mode 100644 code/meosdb/mysql50/typelib.h create mode 100644 code/meosdb/mysql55/decimal.h create mode 100644 code/meosdb/mysql55/errmsg.h create mode 100644 code/meosdb/mysql55/keycache.h create mode 100644 code/meosdb/mysql55/m_ctype.h create mode 100644 code/meosdb/mysql55/m_string.h create mode 100644 code/meosdb/mysql55/my_alloc.h create mode 100644 code/meosdb/mysql55/my_attribute.h create mode 100644 code/meosdb/mysql55/my_compiler.h create mode 100644 code/meosdb/mysql55/my_config.h create mode 100644 code/meosdb/mysql55/my_dbug.h create mode 100644 code/meosdb/mysql55/my_dir.h create mode 100644 code/meosdb/mysql55/my_getopt.h create mode 100644 code/meosdb/mysql55/my_global.h create mode 100644 code/meosdb/mysql55/my_list.h create mode 100644 code/meosdb/mysql55/my_net.h create mode 100644 code/meosdb/mysql55/my_pthread.h create mode 100644 code/meosdb/mysql55/my_sys.h create mode 100644 code/meosdb/mysql55/my_xml.h create mode 100644 code/meosdb/mysql55/mysql.h create mode 100644 code/meosdb/mysql55/mysql/client_plugin.h create mode 100644 code/meosdb/mysql55/mysql/innodb_priv.h create mode 100644 code/meosdb/mysql55/mysql/plugin.h create mode 100644 code/meosdb/mysql55/mysql/plugin_audit.h create mode 100644 code/meosdb/mysql55/mysql/plugin_auth.h create mode 100644 code/meosdb/mysql55/mysql/plugin_auth_common.h create mode 100644 code/meosdb/mysql55/mysql/plugin_ftparser.h create mode 100644 code/meosdb/mysql55/mysql/psi/mysql_file.h create mode 100644 code/meosdb/mysql55/mysql/psi/mysql_thread.h create mode 100644 code/meosdb/mysql55/mysql/psi/psi.h create mode 100644 code/meosdb/mysql55/mysql/psi/psi_abi_v1.h create mode 100644 code/meosdb/mysql55/mysql/psi/psi_abi_v2.h create mode 100644 code/meosdb/mysql55/mysql/service_my_snprintf.h create mode 100644 code/meosdb/mysql55/mysql/service_thd_alloc.h create mode 100644 code/meosdb/mysql55/mysql/service_thd_wait.h create mode 100644 code/meosdb/mysql55/mysql/service_thread_scheduler.h create mode 100644 code/meosdb/mysql55/mysql/services.h create mode 100644 code/meosdb/mysql55/mysql_com.h create mode 100644 code/meosdb/mysql55/mysql_embed.h create mode 100644 code/meosdb/mysql55/mysql_time.h create mode 100644 code/meosdb/mysql55/mysql_version.h create mode 100644 code/meosdb/mysql55/mysqld_ername.h create mode 100644 code/meosdb/mysql55/mysqld_error.h create mode 100644 code/meosdb/mysql55/plugin.h create mode 100644 code/meosdb/mysql55/plugin_audit.h create mode 100644 code/meosdb/mysql55/plugin_ftparser.h create mode 100644 code/meosdb/mysql55/sql_common.h create mode 100644 code/meosdb/mysql55/sql_state.h create mode 100644 code/meosdb/mysql55/sslopt-case.h create mode 100644 code/meosdb/mysql55/sslopt-longopts.h create mode 100644 code/meosdb/mysql55/sslopt-vars.h create mode 100644 code/meosdb/mysql55/typelib.h create mode 100644 code/meosdb/sqltypes.h create mode 100644 code/meosdb/stdafx.cpp create mode 100644 code/meosdb/stdafx.h create mode 100644 code/meosdb/targetver.h create mode 100644 code/meosexception.h create mode 100644 code/meoslang.rc create mode 100644 code/meosvc15.vcxproj create mode 100644 code/meosversion.cpp create mode 100644 code/metalist.cpp create mode 100644 code/metalist.h create mode 100644 code/methodeditor.cpp create mode 100644 code/methodeditor.h create mode 100644 code/minizip/crc32.h create mode 100644 code/minizip/crypt.h create mode 100644 code/minizip/deflate.h create mode 100644 code/minizip/gzguts.h create mode 100644 code/minizip/inffast.h create mode 100644 code/minizip/inffixed.h create mode 100644 code/minizip/inflate.h create mode 100644 code/minizip/inftrees.h create mode 100644 code/minizip/ioapi.h create mode 100644 code/minizip/iowin32.h create mode 100644 code/minizip/mztools.h create mode 100644 code/minizip/trees.h create mode 100644 code/minizip/unzip.h create mode 100644 code/minizip/zconf.h create mode 100644 code/minizip/zip.h create mode 100644 code/minizip/zlib.h create mode 100644 code/minizip/zutil.h create mode 100644 code/mysqldaemon.cpp create mode 100644 code/newcompetition.cpp create mode 100644 code/oBase.cpp create mode 100644 code/oBase.h create mode 100644 code/oCard.cpp create mode 100644 code/oCard.h create mode 100644 code/oClass.cpp create mode 100644 code/oClass.h create mode 100644 code/oClub.cpp create mode 100644 code/oClub.h create mode 100644 code/oControl.cpp create mode 100644 code/oControl.h create mode 100644 code/oCourse.cpp create mode 100644 code/oCourse.h create mode 100644 code/oDataContainer.cpp create mode 100644 code/oDataContainer.h create mode 100644 code/oEvent.cpp create mode 100644 code/oEvent.h create mode 100644 code/oEventDraw.cpp create mode 100644 code/oEventDraw.h create mode 100644 code/oEventResult.cpp create mode 100644 code/oEventSQL.cpp create mode 100644 code/oEventSpeaker.cpp create mode 100644 code/oFreeImport.cpp create mode 100644 code/oFreeImport.h create mode 100644 code/oFreePunch.cpp create mode 100644 code/oFreePunch.h create mode 100644 code/oImportExport.cpp create mode 100644 code/oListInfo.cpp create mode 100644 code/oListInfo.h create mode 100644 code/oPunch.cpp create mode 100644 code/oPunch.h create mode 100644 code/oReport.cpp create mode 100644 code/oRunner.cpp create mode 100644 code/oRunner.h create mode 100644 code/oTeam.cpp create mode 100644 code/oTeam.h create mode 100644 code/oTeamEvent.cpp create mode 100644 code/onlineinput.cpp create mode 100644 code/onlineinput.h create mode 100644 code/onlineresults.cpp create mode 100644 code/onlineresults.h create mode 100644 code/ospeaker.h create mode 100644 code/parser.cpp create mode 100644 code/parser.h create mode 100644 code/pdfwriter.cpp create mode 100644 code/pdfwriter.h create mode 100644 code/prefseditor.cpp create mode 100644 code/prefseditor.h create mode 100644 code/printer.cpp create mode 100644 code/progress.cpp create mode 100644 code/progress.h create mode 100644 code/random.cpp create mode 100644 code/random.h create mode 100644 code/recorder.cpp create mode 100644 code/recorder.h create mode 100644 code/resource.h create mode 100644 code/russian.lng create mode 100644 code/small.ico create mode 100644 code/socket.cpp create mode 100644 code/socket.h create mode 100644 code/speakermonitor.cpp create mode 100644 code/speakermonitor.h create mode 100644 code/swedish.lng create mode 100644 code/testmeos.cpp create mode 100644 code/testmeos.h create mode 100644 code/tests.cpp create mode 100644 code/thirdpartylicense.txt create mode 100644 code/toolbar.cpp create mode 100644 code/toolbar.h create mode 100644 code/xmlparser.cpp create mode 100644 code/xmlparser.h create mode 100644 code/zip.cpp diff --git a/code/HTMLWriter.cpp b/code/HTMLWriter.cpp new file mode 100644 index 0000000..e026f46 --- /dev/null +++ b/code/HTMLWriter.cpp @@ -0,0 +1,522 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "gdioutput.h" +#include +#include +#include +#include +#include +#include "meos_util.h" +#include "Localizer.h" +#include "gdiconstants.h" + +double getLocalScale(const string &fontName, string &faceName); +string getMeosCompectVersion(); + +static void generateStyles(ostream &fout, bool withTbl, const list &TL, + map< pair, pair > &styles) { + fout << "\n"; +} + +static void getStyle(const map< pair, pair > &styles, + gdiFonts font, const string &face, const string &extraStyle, string &starttag, string &endtag) { + starttag.clear(); + endtag.clear(); + string extra; + switch (font) { + case boldText: + case boldSmall: + extra = "b"; + break; + case italicSmall: + case italicText: + case italicMediumPlus: + extra = "i"; + break; + } + + pair key(font, face); + map< pair, pair >::const_iterator res = styles.find(key); + + if (res != styles.end()) { + const pair &stylePair = res->second; + + if (!stylePair.first.empty()) { + starttag = "<" + stylePair.first; + if (!stylePair.second.empty()) + starttag += " class=\"" + stylePair.second + "\""; + starttag += extraStyle; + starttag += ">"; + } + + if (!extra.empty()) { + starttag += "<" + extra + ">"; + endtag = ""; + } + + if (!stylePair.first.empty()) { + endtag += ""; + } + } + else { + string element; + switch(font) { + case boldHuge: + element="h1"; + break; + case boldLarge: + element="h2"; + break; + case fontLarge: + element="h2"; + break; + case fontMedium: + element="h3"; + break; + } + + if (!extraStyle.empty() && element.empty()) + element = "div"; + + if (element.size()>0) { + starttag = "<" + element + extraStyle + ">"; + } + + if (!extra.empty()) { + starttag += "<" + extra + ">"; + endtag = ""; + } + + if (element.size()>0) { + endtag += ""; + } + } +} + +bool gdioutput::writeHTML(const wstring &file, const string &title, int refreshTimeOut) const +{ + ofstream fout(file.c_str()); + + if (fout.bad()) + return false; + + + fout << "\n\n"; + + fout << "\n\n"; + fout << "\n"; + if (refreshTimeOut > 0) + fout << "\n"; + + + fout << "" << toUTF8(title) << "\n"; + + map< pair, pair > styles; + generateStyles(fout, false, TL, styles); + + fout << "\n"; + + fout << "\n"; + + list::const_iterator it = TL.begin(); + + double yscale = 1.3; + double xscale = 1.2; + int offsetY = 0; + while (it!=TL.end()) { + if (skipTextRender(it->format)) { + ++it; + continue; + } + + string yp = itos(int(yscale*it->yp) + offsetY); + string xp = itos(int(xscale *it->xp)); + + string estyle; + if (it->format!=1 && it->format!=boldSmall) { + if (it->format & textRight) + estyle = " style=\"position:absolute;left:" + + xp + "px;top:" + yp + "px\""; + else + estyle = " style=\"position:absolute;left:" + + xp + "px;top:" + yp + "px\""; + + } + else { + if (it->format & textRight) + estyle = " style=\"font-weight:bold;position:absolute;left:" + + xp + "px;top:" + yp + "px\""; + else + estyle = " style=\"font-weight:bold;position:absolute;left:" + + xp + "px;top:" + yp + "px\""; + } + string starttag, endtag; + getStyle(styles, it->getGdiFont(), it->font, estyle, starttag, endtag); + + if (!it->text.empty()) + fout << starttag << toUTF8(encodeXML(it->text)) << endtag << endl; + + if (it->format == boldLarge) { + list::const_iterator next = it; + ++next; + if (next == TL.end() || next->yp != it->yp) + offsetY += 7; + } + ++it; + } + + fout << "

"; + + char bf1[256]; + char bf2[256]; + GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256); + GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256); + //fout << "Skapad av MeOS: " << bf1 << " "<< bf2 << "\n"; + fout << toUTF8(lang.tl("Skapad av ")) + "MeOS: " << bf1 << " "<< bf2 << "\n"; + fout << "

\n"; + + fout << "\n"; + fout << "\n"; + + return false; +} + +string html_table_code(const string &in) +{ + if (in.size()==0) + return " "; + else { + return encodeXML(in); + } +} + +bool sortTL_X(const TextInfo *a, const TextInfo *b) +{ + return a->xp < b->xp; +} + + +bool gdioutput::writeTableHTML(const wstring &file, + const string &title, int refreshTimeOut) const +{ + ofstream fout(file.c_str()); + + if (fout.bad()) + return false; + + return writeTableHTML(fout, title, false, refreshTimeOut); +} + +bool gdioutput::writeTableHTML(ostream &fout, + const string &title, + bool simpleFormat, + int refreshTimeOut) const { + + fout << "\n\n"; + + fout << "\n\n"; + fout << "\n"; + if (refreshTimeOut > 0) + fout << "\n"; + fout << "" << toUTF8(title) << "\n"; + + map< pair, pair > styles; + generateStyles(fout, true, TL, styles); + + fout << "\n"; + + fout << "\n"; + + list::const_iterator it = TL.begin(); + map tableCoordinates; + + //Get x-coordinates + while (it!=TL.end()) { + tableCoordinates[it->xp]=0; + ++it; + } + + map::iterator mit=tableCoordinates.begin(); + int k=0; + + while (mit!=tableCoordinates.end()) { + mit->second=k++; + ++mit; + } + tableCoordinates[MaxX]=k; + + vector sizeSet(k+1, false); + + fout << "\n"; + + int linecounter=0; + it=TL.begin(); + + vector< pair > > rows; + rows.reserve(TL.size() / 3); + vector ypRow; + int minHeight = 100000; + + while (it!=TL.end()) { + int y=it->yp; + vector row; + + int subnormal = 0; + int normal = 0; + int header = 0; + int mainheader = 0; + while (it!=TL.end() && it->yp==y) { + if (!gdioutput::skipTextRender(it->format)) { + row.push_back(&*it); + switch (it->getGdiFont()) { + case fontLarge: + case boldLarge: + case boldHuge: + mainheader++; + break; + case boldText: + case italicMediumPlus: + case fontMediumPlus: + header++; + break; + case fontSmall: + case italicSmall: + subnormal++; + break; + default: + normal++; + } + } + ++it; + } + + if (row.empty()) + continue; + + bool isMainHeader = mainheader > normal; + bool isHeader = (header + mainheader) > normal; + bool isSub = subnormal > normal; + + sort(row.begin(), row.end(), sortTL_X); + rows.resize(rows.size() + 1); + rows.back().first = isMainHeader ? 1 : (isHeader ? 2 : (isSub ? 3 : 0)); + rows.back().second.swap(row); + int last = ypRow.size(); + ypRow.push_back(y); + if (last > 0) { + minHeight = min(minHeight, ypRow[last] - ypRow[last-1]); + } + } + int numMin = 0; + for (size_t gCount = 1; gCount < rows.size(); gCount++) { + int h = ypRow[gCount] - ypRow[gCount-1]; + if (h == minHeight) + numMin++; + } + if (numMin == 0) + numMin = 1; + + int hdrLimit = (rows.size() / numMin) <= 4 ? int(minHeight * 1.2) : int(minHeight * 1.5); + for (size_t gCount = 1; gCount + 1 < rows.size(); gCount++) { + int type = rows[gCount].first; + int lastType = gCount > 0 ? rows[gCount-1].first : 0; + int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0; + if (type == 0 && (lastType == 1 || lastType == 2) && (nextType == 1 || nextType == 2)) + continue; // No reclassify + + int h = ypRow[gCount] - ypRow[gCount-1]; + if (h > hdrLimit && rows[gCount].first == 0) + rows[gCount].first = 2; + } + + ypRow.clear(); + string lineclass; + for (size_t gCount = 0; gCount < rows.size(); gCount++) { + vector &row = rows[gCount].second; + int type = rows[gCount].first; + int lastType = gCount > 0 ? rows[gCount-1].first : 0; + int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0; + + vector::iterator rit; + fout << "" << endl; + + if (simpleFormat) { + } + else if (type == 1) { + lineclass = " class=\"freeheader\""; + linecounter = 0; + } + else if (type == 2) { + linecounter = 0; + lineclass = " valign=\"bottom\" class=\"header\""; + } + else { + if (type == 3) + linecounter = 1; + + if ((lastType == 1 || lastType == 2) && (nextType == 1 || nextType == 2) && row.size() < 3) { + lineclass = ""; + } + else + lineclass = (linecounter&1) ? " class=\"e1\"" : " class=\"e0\""; + + linecounter++; + } + + for (size_t k=0;kxp]; + + if (k==0 && thisCol!=0) + fout << " "; + + int nextCol; + if (row.size()==k+1) + nextCol=tableCoordinates.rbegin()->second; + else + nextCol=tableCoordinates[row[k+1]->xp]; + + int colspan=nextCol-thisCol; + + assert(colspan>0); + + string style; + + if (row[k]->format&textRight) + style=" style=\"text-align:right\""; + + if (colspan==1 && !sizeSet[thisCol]) { + fout << " xp - row[k]->xp) : (MaxX-row[k]->xp)) << "\">"; + sizeSet[thisCol]=true; + } + else if (colspan>1) + fout << " "; + else + fout << " "; + + gdiFonts font = row[k]->getGdiFont(); + string starttag, endtag; + getStyle(styles, font, row[k]->font, "", starttag, endtag); + + fout << starttag << toUTF8(html_table_code(row[k]->text)) << endtag << "" << endl; + + } + fout << "\n"; + + row.clear(); + } + + fout << "
\n"; + + if (!simpleFormat) { + fout << "

"; + char bf1[256]; + char bf2[256]; + GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256); + GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256); + string meos = getMeosCompectVersion(); + fout << toUTF8(lang.tl("Skapad av ")) + "MeOS " + << meos << ": " << bf1 << " "<< bf2 << "\n"; + fout << "


\n"; + } + fout << "\n"; + fout << "\n"; + + return true; +} \ No newline at end of file diff --git a/code/MeOSFeatures.cpp b/code/MeOSFeatures.cpp new file mode 100644 index 0000000..eeb5b0a --- /dev/null +++ b/code/MeOSFeatures.cpp @@ -0,0 +1,251 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "oEvent.h" +#include "MeOSFeatures.h" +#include "meosexception.h" +#include "meos_util.h" +#include +#include "classconfiginfo.h" + +MeOSFeatures::MeOSFeatures(void) +{ + addHead("General"); + add(DrawStartList, "SL", "Prepare start lists"); + add(Bib, "BB", "Bibs"); + add(Clubs, "CL", "Clubs"); + add(EditClub, "CC", "Edit Clubs").require(Clubs); + + add(InForest, "RF", "Track runners in forest"); + add(Network, "NW", "Several MeOS Clients in a network"); + + addHead("MeOS Features"); + add(Speaker, "SP", "Använd speakerstöd"); + add(SeveralStages, "ST", "Several stages"); + add(Economy, "EC", "Economy and fees").require(EditClub).require(Clubs); + add(Vacancy, "VA", "Vacancies and entry cancellations").require(DrawStartList); + add(TimeAdjust, "TA", "Manual time penalties and adjustments"); + add(RunnerDb, "RD", "Club and runner database").require(Clubs); + addHead("Teams and forking"); + add(ForkedIndividual, "FO", "Forked individual courses"); + add(Patrol, "PT", "Patrols"); + add(Relay, "RL", "Relays"); + add(MultipleRaces, "MR", "Several races for a runner").require(Relay); + + addHead("Rogaining"); + add(Rogaining, "RO", "Rogaining"); + add(PointAdjust, "PA", "Manual point reductions and adjustments").require(Rogaining); +} + +MeOSFeatures::FeatureDescriptor &MeOSFeatures::add(Feature feat, const char *code, const char *descr) { + assert(codeToIx.count(code) == 0); + assert(featureToIx.count(feat) == 0); + + featureToIx[feat] = desc.size(); + string codeS = code; + codeToIx[codeS] = desc.size(); + desc.push_back(FeatureDescriptor(feat, codeS, descr)); + return desc.back(); +} + +MeOSFeatures::FeatureDescriptor &MeOSFeatures::addHead(const char *descr) { + desc.push_back(FeatureDescriptor(_Head, "-", descr)); + return desc.back(); +} + +bool MeOSFeatures::isHead(int featureIx) const { + return getFeature(featureIx) == _Head; +} + +const string &MeOSFeatures::getHead(int featureIx) const { + if (isHead(featureIx)) + return desc[featureIx].desc; + else + isHead(-1);//Throws + return _EmptyString; +} + +MeOSFeatures::FeatureDescriptor::FeatureDescriptor(Feature featIn, + string codeIn, + string descIn) : + feat(featIn), code(codeIn), desc(descIn) +{ +} + +MeOSFeatures::~MeOSFeatures(void) +{ +} + +bool MeOSFeatures::hasFeature(Feature f) const { + return features.count(f) != 0; +} + +void MeOSFeatures::useFeature(Feature f, bool use, oEvent &oe) { + if (use) { + const set &dep = desc[getIndex(f)].dependsOn; + features.insert(f); + features.insert(dep.begin(), dep.end()); + } + else { + if (!isRequiredInternal(f)) + features.erase(f); + } + oe.getDI().setString("Features", serialize()); +} + +bool MeOSFeatures::isRequiredInternal(Feature f) const { + for (set::const_iterator it = features.begin(); it != features.end(); ++it) { + if (desc[getIndex(*it)].dependsOn.count(f)) + return true; + } + return false; +} + +bool MeOSFeatures::isRequired(Feature f, const oEvent &oe) const { + if (isRequiredInternal(f)) + return true; + + if (f == Rogaining && oe.hasRogaining() && hasFeature(Rogaining)) + return true; + + return false; +} + +int MeOSFeatures::getNumFeatures() const { + return desc.size(); +} + +MeOSFeatures::Feature MeOSFeatures::getFeature(int featureIx) const { + if (size_t(featureIx) < desc.size()) + return desc[featureIx].feat; + else + throw meosException("Index out of bounds"); +} + +const string &MeOSFeatures::getDescription(Feature f) const { + return desc[getIndex(f)].desc; +} + +const string &MeOSFeatures::getCode(Feature f) const { + return desc[getIndex(f)].code; +} + +int MeOSFeatures::getIndex(Feature f) const { + map::const_iterator res = featureToIx.find(f); + if (res == featureToIx.end()) + throw meosException("Index out of bounds"); + return res->second; +} + +string MeOSFeatures::serialize() const { + if (features.empty()) + return "NONE"; + + string st; + for (set::const_iterator it = features.begin(); it != features.end(); ++it) { + if (!st.empty()) + st += "+"; + st += getCode(*it); + } + return st; +} + +void MeOSFeatures::deserialize(const string &input, oEvent &oe) { + features.clear(); + + if (input == "NONE") + return; + else if (input.empty()) { + loadDefaults(oe); + } + + vector ff; + split(input, "+", ff); + for (size_t k = 0; k < ff.size(); k++) { + map::iterator res = codeToIx.find(ff[k]); + if (res != codeToIx.end()) + features.insert(desc[res->second].feat); + } + + set iF; + for (set::iterator it = features.begin(); it != features.end(); ++it) { + int ix = getIndex(*it); + iF.insert(desc[ix].dependsOn.begin(), desc[ix].dependsOn.end()); + } + + features.insert(iF.begin(), iF.end()); +} + +void MeOSFeatures::loadDefaults(oEvent &oe) { + if (oe.getDCI().getInt("UseEconomy") != 0) { + features.insert(Economy); + features.insert(EditClub); + } + + if (oe.getDCI().getInt("UseSpeaker") != 0) + features.insert(Speaker); + + if (oe.hasRogaining()) + features.insert(Rogaining); + + if (oe.getDCI().getInt("SkipRunnerDb") == 0 ) + features.insert(RunnerDb); + + ClassConfigInfo cnf; + oe.getClassConfigurationInfo(cnf); + if (cnf.hasPatrol()) + features.insert(Patrol); + + if (cnf.hasRelay()) + features.insert(Relay); + + if (cnf.raceNStart.size() > 0) { + features.insert(Relay); + features.insert(MultipleRaces); + } + + if (cnf.isMultiStageEvent()) + features.insert(SeveralStages); + + features.insert(Clubs); + features.insert(Network); + features.insert(ForkedIndividual); + + features.insert(Vacancy); + features.insert(InForest); + features.insert(DrawStartList); + features.insert(Bib); +} + +void MeOSFeatures::useAll(oEvent &oe) { + for (size_t k = 0; k < desc.size(); k++) { + if (desc[k].feat != _Head) + features.insert(desc[k].feat); + } + oe.getDI().setString("Features", serialize()); +} + +void MeOSFeatures::clear(oEvent &oe) { + features.clear(); + oe.getDI().setString("Features", serialize()); +} diff --git a/code/MeOSFeatures.h b/code/MeOSFeatures.h new file mode 100644 index 0000000..6b03a08 --- /dev/null +++ b/code/MeOSFeatures.h @@ -0,0 +1,103 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include + +class oEvent; + +class MeOSFeatures +{ +public: + enum Feature { + _Head = -1, + Speaker = 0, + Economy, + Clubs, + EditClub, + SeveralStages, + Network, + TimeAdjust, + PointAdjust, + ForkedIndividual, + Patrol, + Relay, + MultipleRaces, + Rogaining, + Vacancy, + InForest, + DrawStartList, + Bib, + RunnerDb, + }; + +private: + struct FeatureDescriptor { + Feature feat; + string code; + string desc; + set dependsOn; + FeatureDescriptor &require(Feature f) { + dependsOn.insert(f); + return *this; + } + FeatureDescriptor(Feature feat, string code, string desc); + }; + + vector desc; + map featureToIx; + map codeToIx; + FeatureDescriptor &add(Feature feat, const char *code, const char *desc); + FeatureDescriptor &addHead(const char *desc); + + set features; + + int getIndex(Feature f) const; + + void loadDefaults(oEvent &oe); + + bool isRequiredInternal(Feature f) const; + +public: + MeOSFeatures(void); + ~MeOSFeatures(void); + + bool hasFeature(Feature f) const; + void useFeature(Feature f, bool use, oEvent &oe); + bool isRequired(Feature f, const oEvent &oe) const; + + void useAll(oEvent &oe); + void clear(oEvent &oe); + + int getNumFeatures() const; + Feature getFeature(int featureIx) const; + bool isHead(int featureIx) const; + const string &getHead(int featureIx) const; + const string &getDescription(Feature f) const; + const string &getCode(Feature f) const; + + string serialize() const; + void deserialize(const string &input, oEvent &oe); +}; + diff --git a/code/Printer.h b/code/Printer.h new file mode 100644 index 0000000..83ae356 --- /dev/null +++ b/code/Printer.h @@ -0,0 +1,116 @@ +// printer.h: printing utilities. + +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "gdistructures.h" + +/** Data structure describing text to print.*/ +struct PrintTextInfo { + float xp; + float yp; + float width; + TextInfo ti; + PrintTextInfo(const TextInfo &ti_) : xp(0), yp(0), width(0), ti(ti_) {}; + PrintTextInfo() : xp(0), yp(0), width(0) {}; +}; + +/** Data structure describing page to print*/ +struct PageInfo { + float topMargin; + float bottomMargin; + float pageY; + float leftMargin; + float scaleX; + float scaleY; + + bool printHeader; + bool noPrintMargin; + int nPagesTotal; //Total number of pages to print + + // Transfer mm to local printing coordinates: cLocalX = cx + m, cLocalX = cy + m. + double xMM2PrintC; + double xMM2PrintK; + + double yMM2PrintC; + double yMM2PrintK; + + void renderPages(const list &tl, + const list &rects, + bool invertHeightY, + vector &pages); + + string pageInfo(const RenderedPage &page) const; +}; + +/** A rendered page ready to print. */ +struct RenderedPage { + int nPage; // This page number + string info; + vector text; + vector rectangles; + __int64 checkSum; + + RenderedPage() : checkSum(0) {} + void calculateCS(const TextInfo &text); +}; + +struct PrinterObject { + //Printing + HDC hDC; + HGLOBAL hDevMode; + HGLOBAL hDevNames; + + void freePrinter(); + + string Device; + string Driver; + DEVMODE DevMode; + set<__int64> printedPages; + int nPagesPrinted; + int nPagesPrintedTotal; + bool onlyChanged; + + struct DATASET { + int pWidth_mm; + int pHeight_mm; + double pMgBottom; + double pMgTop; + double pMgRight; + double pMgLeft; + + int MarginX; + int MarginY; + int PageX; + int PageY; + double Scale; + bool LastPage; + } ds; + + void operator=(const PrinterObject &po); + + PrinterObject(); + ~PrinterObject(); + PrinterObject(const PrinterObject &po); +}; diff --git a/code/RunnerDB.cpp b/code/RunnerDB.cpp new file mode 100644 index 0000000..8714eaf --- /dev/null +++ b/code/RunnerDB.cpp @@ -0,0 +1,1232 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "RunnerDB.h" +#include "xmlparser.h" +#include "oRunner.h" +#include "Table.h" + +#include "io.h" +#include "fcntl.h" +#include "sys/stat.h" +#include "meos_util.h" +#include "oDataContainer.h" +#include "meosException.h" + +#include +#include +#include "intkeymapimpl.hpp" + +#include "oEvent.h" + +RunnerDB::RunnerDB(oEvent *oe_): oe(oe_) +{ + loadedFromServer = false; + dataDate = 20100201; + dataTime = 222222; + runnerTable = 0; + clubTable = 0; +} + +RunnerDB::~RunnerDB(void) +{ + releaseTables(); +} + +RunnerDBEntry::RunnerDBEntry() +{ + memset(this, 0, sizeof(RunnerDBEntry)); +} + +RunnerDBEntryV1::RunnerDBEntryV1() +{ + memset(this, 0, sizeof(RunnerDBEntryV1)); +} + + +void RunnerDBEntry::getName(string &n) const +{ + n=name; +} + +void RunnerDBEntry::setName(const char *n) +{ + memcpy(name, n, min(strlen(n)+1, baseNameLength)); + name[baseNameLength-1]=0; +} + +string RunnerDBEntry::getNationality() const +{ + if (national[0] < 30) + return _EmptyString; + + string n(" "); + n[0] = national[0]; + n[1] = national[1]; + n[2] = national[2]; + return n; +} + +string RunnerDBEntry::getSex() const +{ + if (sex == 0) + return _EmptyString; + string n("W"); + n[0] = sex; + return n; +} +string RunnerDBEntry::getGivenName() const +{ + return ::getGivenName(name); +} + +string RunnerDBEntry::getFamilyName() const +{ + return ::getFamilyName(name); +} + +__int64 RunnerDBEntry::getExtId() const +{ + return extId; +} + +void RunnerDBEntry::setExtId(__int64 id) +{ + extId = id; +} + +void RunnerDBEntry::init(const RunnerDBEntryV1 &dbe) +{ + memcpy(this, &dbe, sizeof(RunnerDBEntryV1)); + extId = 0; +} + + +RunnerDBEntry *RunnerDB::addRunner(const char *name, + __int64 extId, + int club, int card) +{ + rdb.push_back(RunnerDBEntry()); + RunnerDBEntry &e=rdb.back(); + e.cardNo = card; + e.clubNo = club; + e.setName(name); + e.extId = extId; + + if (!check(e) ) { + rdb.pop_back(); + return 0; + } else { + if (card>0) + rhash[card]=rdb.size()-1; + if (!idhash.empty()) + idhash[extId] = rdb.size()-1; + if (!nhash.empty()) + nhash.insert(pair(canonizeName(e.name), rdb.size()-1)); + } + return &e; +} + +int RunnerDB::addClub(oClub &c, bool createNewId) { + //map::iterator it = chash.find(c.getId()); + //if (it == chash.end()) { + if (createNewId) { + oDBClubEntry ce(c, cdb.size(), this); + cdb.push_back(ce); + int b = 0; + while(++b<0xFFFF) { + int newId = 10000 + rand() & 0xFFFF; + int dummy; + if (!chash.lookup(newId, dummy)) { + cdb.back().Id = newId; + chash[c.getId()]=cdb.size()-1; + return newId; + } + } + cdb.pop_back(); + throw meosException("Internal database error"); + } + + int value; + if (!chash.lookup(c.getId(), value)) { + oDBClubEntry ce(c, cdb.size(), this); + cdb.push_back(ce); + chash[c.getId()]=cdb.size()-1; + } + else { + oDBClubEntry ce(c, value, this); + cdb[value] = ce; + } + return c.getId(); +} + +void RunnerDB::importClub(oClub &club, bool matchName) +{ + pClub pc = getClub(club.getId()); + + if (pc && !pc->sameClub(club)) { + //The new id is used by some other club. + //Remap old club first + + int oldId = pc->getId(); + int newId = chash.size() + 1;//chash.rbegin()->first + 1; + + for (size_t k=0; kgetId(); + int newId = club.getId(); + + for (size_t k=0; k clubmap; + for (size_t k=0;k compacted; + for (size_t j=k+1;jba) { + best = &cdb[compacted[j]]; + ba=nba; + } + } + swap(ref, *best); + + //Update map + for (size_t j=0;j= rdb.size()) + throw meosException("Index out of bounds"); + + return (RunnerDBEntry *)&rdb[index]; +} + + +RunnerDBEntry *RunnerDB::getRunnerById(__int64 extId) const +{ + if (extId == 0) + return 0; + + setupIdHash(); + + int value; + + if (idhash.lookup(extId, value)) + return (RunnerDBEntry *)&rdb[value]; + + return 0; +} + +RunnerDBEntry *RunnerDB::getRunnerByName(const string &name, int clubId, + int expectedBirthYear) const +{ + if (expectedBirthYear>0 && expectedBirthYear<100) + expectedBirthYear = extendYear(expectedBirthYear); + + setupNameHash(); + vector ix; + string cname(canonizeName(name.c_str())); + multimap::const_iterator it = nhash.find(cname); + + while (it != nhash.end() && cname == it->first) { + ix.push_back(it->second); + ++it; + } + + if (ix.empty()) + return 0; + + if (clubId == 0) { + if (ix.size() == 1) + return (RunnerDBEntry *)&rdb[ix[0]]; + else + return 0; // Not uniquely defined. + } + + // Filter on club + vector ix2; + for (size_t k = 0;k 0) { + int bestMatch = 0; + int bestYear = 0; + for (size_t k = 0;k0) + return (RunnerDBEntry *)&rdb[bestMatch]; + } + + return 0; +} + +void RunnerDB::setupIdHash() const +{ + if (!idhash.empty()) + return; + + for (size_t k=0; k(canonizeName(rdb[k].name), k)); + } +} + +void RunnerDB::setupCNHash() const +{ + if (!cnhash.empty()) + return; + + vector split; + for (size_t k=0; k(split[j], k)); + } +} + +static bool isVowel(int c) { + return c=='a' || c=='e' || c=='i' || + c=='o' || c=='u' || c=='y' || + c=='å' || c=='ä' || c=='ö'; +} + +void RunnerDB::canonizeSplitName(const string &name, vector &split) +{ + split.clear(); + const char *cname = name.c_str(); + int k = 0; + for (k=0; cname[k]; k++) + if (cname[k] != ' ') + break; + + char out[128]; + int outp; + while (cname[k]) { + outp = 0; + while(cname[k] != ' ' && cname[k] && outp<(sizeof(out)-1) ) { + if (cname[k] == '-') { + k++; + break; + } + out[outp++] = toLowerStripped(cname[k]); + k++; + } + out[outp] = 0; + if (outp > 0) { + for (int j=1; j4 && out[outp-1]=='s') + out[outp-1] = 0; // Identify Linköping och Linköpings + split.push_back(out); + } + while(cname[k] == ' ') + k++; + } +} + +bool RunnerDB::getClub(int clubId, string &club) const +{ + //map::const_iterator it = chash.find(clubId); + + int value; + if (chash.lookup(clubId, value)) { + //if (it!=chash.end()) { + // int i=it->second; + club=cdb[value].getName(); + return true; + } + return false; +} + +oClub *RunnerDB::getClub(int clubId) const +{ + //map::const_iterator it = chash.find(clubId); + + //if (it!=chash.end()) + int value; + if (chash.lookup(clubId, value)) + return pClub(&cdb[value]); + + return 0; +} + +oClub *RunnerDB::getClub(const string &name) const +{ + setupCNHash(); + vector names; + canonizeSplitName(name, names); + vector< vector > ix(names.size()); + set iset; + + for (size_t k = 0; k::const_iterator it = cnhash.find(names[k]); + + while (it != cnhash.end() && names[k] == it->first) { + ix[k].push_back(it->second); + ++it; + } + + if (ix[k].size() == 1 && names[k].length()>3) + return pClub(&cdb[ix[k][0]]); + + if (iset.empty()) + iset.insert(ix[k].begin(), ix[k].end()); + else { + set im; + for (size_t j = 0; j::iterator it = iset.begin(); it != iset.end(); ++it) { + pClub pc = pClub(&cdb[*it]); + if (_stricmp(pc->getName().c_str(), name.c_str())==0) + return pc; + } + + string cname = canonizeName(name.c_str()); + // Looser compare + for (set::iterator it = iset.begin(); it != iset.end(); ++it) { + pClub pc = pClub(&cdb[*it]); + if (strcmp(canonizeName(pc->getName().c_str()), cname.c_str()) == 0 ) + return pc; + } + + double best = 1; + double secondBest = 1; + int bestIndex = -1; + for (set::iterator it = iset.begin(); it != iset.end(); ++it) { + pClub pc = pClub(&cdb[*it]); + + double d = stringDistance(cname.c_str(), canonizeName(pc->getName().c_str())); + + if (d0.4) + return pClub(&cdb[bestIndex]); + + return 0; +} + +void RunnerDB::saveClubs(const char *file) +{ + xmlparser xml(0); + + xml.openOutputT(file, true, "meosclubs"); + + vector::iterator it; + + xml.startTag("ClubList"); + + for (it=cdb.begin(); it != cdb.end(); ++it) + it->write(xml); + + xml.endTag(); + + xml.closeOut(); +} + +string RunnerDB::getDataDate() const +{ + char bf[128]; + if (dataTime<=0 && dataDate>0) + sprintf_s(bf, "%04d-%02d-%02d", dataDate/10000, + (dataDate/100)%100, + dataDate%100); + else if (dataDate>0) + sprintf_s(bf, "%04d-%02d-%02d %02d:%02d:%02d", dataDate/10000, + (dataDate/100)%100, + dataDate%100, + (dataTime/3600)%24, + (dataTime/60)%60, + (dataTime)%60); + else + return "2011-01-01 00:00:00"; + + return bf; +} + +void RunnerDB::setDataDate(const string &date) +{ + int d = convertDateYMS(date.substr(0, 10), false); + int t = date.length()>11 ? convertAbsoluteTimeHMS(date.substr(11), -1) : 0; + + if (d<=0) + throw std::exception("Felaktigt datumformat"); + + dataDate = d; + if (t>0) + dataTime = t; + else + dataTime = 0; +} + +void RunnerDB::saveRunners(const char *file) +{ + int f=-1; + _sopen_s(&f, file, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, + _SH_DENYWR, _S_IREAD|_S_IWRITE); + + if (f!=-1) { + int version = 5460002; + _write(f, &version, 4); + _write(f, &dataDate, 4); + _write(f, &dataTime, 4); + if (!rdb.empty()) + _write(f, &rdb[0], rdb.size()*sizeof(RunnerDBEntry)); + _close(f); + } + else throw std::exception("Could not save runner database."); +} + +void RunnerDB::loadClubs(const char *file) +{ + xmlparser xml(0); + + xml.read(file); + + xmlobject xo; + + //Get clubs + xo=xml.getObject("ClubList"); + if (xo) { + clearClubs(); + loadedFromServer = false; + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + cdb.clear(); + chash.clear(); + freeCIx = 0; + cdb.reserve(xl.size()); + for (it=xl.begin(); it != xl.end(); ++it) { + if (it->is("Club")){ + oDBClubEntry c(oe, cdb.size(), this); + c.set(*it); + int value; + //if (chash.find(c.getId()) == chash.end()) { + if (!chash.lookup(c.getId(), value)) { + chash[c.getId()]=cdb.size(); + cdb.push_back(c); + } + } + } + } + + bool checkClubs = false; + + if (checkClubs) { + vector problems; + + for (size_t k=0; kgetName()); + if (!pc2) + problems.push_back(pc->getName()); + else if (pc != pc2) + problems.push_back(pc->getName() + "-" + pc2->getName()); + } + problems.begin(); + } +} + +void RunnerDB::loadRunners(const char *file) +{ + string ex=string("Bad runner database. ")+file; + int f=-1; + _sopen_s(&f, file, _O_BINARY|_O_RDONLY, + _SH_DENYWR, _S_IREAD|_S_IWRITE); + + if (f!=-1) { + clearRunners(); + loadedFromServer = false; + + int len = _filelength(f); + if ( (len%sizeof(RunnerDBEntryV1) != 0) && (len % sizeof(RunnerDBEntry) != 12)) { + _close(f); + return;//Failed + } + int nentry = 0; + + if (len % sizeof(RunnerDBEntry) == 12) { + nentry = (len-12) / sizeof(RunnerDBEntry); + + rdb.resize(nentry); + if (rdb.empty()) { + _close(f); + return; + } + int version; + _read(f, &version, 4); + _read(f, &dataDate, 4); + _read(f, &dataTime, 4); + _read(f, &rdb[0], len-12); + _close(f); + for (int k=0;k rdbV1(nentry); + + _read(f, &rdbV1[0], len); + _close(f); + for (int k=0;k0) + ncard++; + + rhash.resize(ncard); + + for (int k=0;k0 && !rdb[k].isRemoved()) { + rhash[rdb[k].cardNo]=k; + } + } + } + else throw std::exception(ex.c_str()); +} + +bool RunnerDB::check(const RunnerDBEntry &rde) const +{ + if (rde.cardNo<0 || rde.cardNo>99999999 + || rde.name[baseNameLength-1]!=0 || rde.clubNo<0) + return false; + return true; +} + +void RunnerDB::updateAdd(const oRunner &r, map &clubIdMap) +{ + if (r.getExtIdentifier() > 0) { + RunnerDBEntry *dbe = getRunnerById(int(r.getExtIdentifier())); + if (dbe) { + dbe->cardNo = r.CardNo; + return; // Do not change too much in runner from national database + } + } + + const pClub pc = r.Club; + int localClubId = r.getClubId(); + + if (pc) { + if (clubIdMap.count(localClubId)) + localClubId = clubIdMap[localClubId]; + + pClub dbClub = getClub(localClubId); + bool wrongId = false; + if (dbClub) { + if (dbClub->getName() != pc->getName()) { + dbClub = 0; // Wrong club! + wrongId = true; + } + } + + if (dbClub == 0) { + dbClub = getClub(r.getClub()); + if (dbClub) { + localClubId = dbClub->getId(); + clubIdMap[pc->getId()] = localClubId; + } + } + + if (dbClub == 0) { + localClubId = addClub(*pc, wrongId); + if (wrongId) + clubIdMap[pc->getId()] = localClubId; + } + } + + RunnerDBEntry *dbe = getRunnerByCard(r.getCardNo()); + + if (dbe == 0) { + dbe = addRunner(r.getName().c_str(), 0, localClubId, r.getCardNo()); + if (dbe) + dbe->birthYear = r.getDCI().getInt("BirthYear"); + } + else { + if (dbe->getExtId() == 0) { // Only update entries not in national db. + dbe->setName(r.getName().c_str()); + dbe->clubNo = localClubId; + dbe->birthYear = r.getDCI().getInt("BirthYear"); + } + } +} + +void RunnerDB::getAllNames(vector &givenName, vector &familyName) +{ + givenName.reserve(rdb.size()); + familyName.reserve(rdb.size()); + for (size_t k=0;kclear(); + +} + +void RunnerDB::clearRunners() +{ + nhash.clear(); + idhash.clear(); + rhash.clear(); + rdb.clear(); + if (runnerTable) + runnerTable->clear(); +} + +const vector &RunnerDB::getClubDB() const { + return cdb; +} + +const vector &RunnerDB::getRunnerDB() const { + return rdb; +} + +void RunnerDB::prepareLoadFromServer(int nrunner, int nclub) { + loadedFromServer = true; + clearClubs(); // Implicitly clears runners + cdb.reserve(nclub); + rdb.reserve(nrunner); +} + +void RunnerDB::fillClubs(vector< pair > &out) const { + out.reserve(cdb.size()); + for (size_t k = 0; kgetDBRunnersInEvent(runnerInEvent); + if (addEntry) { + addEntry->addTableRow(table); + return; + } + + table.reserve(rdb.size()); + oRDB.resize(rdb.size(), oDBRunnerEntry(oe)); + for (size_t k = 0; kreloadRow(value + 1); + } + catch (const std::exception &) { + // Ignore any problems with the table. + } + } + } +} + +void RunnerDB::refreshTables() { + if (runnerTable) + refreshRunnerTableData(*runnerTable); + + if (clubTable) + refreshClubTableData(*clubTable); +} + +void RunnerDB::releaseTables() { + if (runnerTable) + runnerTable->releaseOwnership(); + runnerTable = 0; + + if (clubTable) + clubTable->releaseOwnership(); + clubTable = 0; +} + +Table *RunnerDB::getRunnerTB()//Table mode +{ + if (runnerTable == 0) { + Table *table=new Table(oe, 20, "Löpardatabasen", "runnerdb"); + + table->addColumn("Index", 70, true, true); + table->addColumn("Id", 70, true, true); + table->addColumn("Namn", 200, false); + table->addColumn("Klubb", 200, false); + table->addColumn("SI", 70, true, true); + table->addColumn("Nationalitet", 70, false, true); + table->addColumn("Kön", 50, false, true); + table->addColumn("Födelseår", 70, true, true); + table->addColumn("Anmäl", 70, false, true); + + table->setTableProp(Table::CAN_INSERT|Table::CAN_DELETE|Table::CAN_PASTE); + table->setClearOnHide(false); + table->addOwnership(); + runnerTable = table; + } + int nr = 0; + for (size_t k = 0; k < rdb.size(); k++) { + if (!rdb[k].isRemoved()) + nr++; + } + + if (runnerTable->getNumDataRows() != nr) + runnerTable->update(); + return runnerTable; +} + +void RunnerDB::generateClubTableData(Table &table, oClub *addEntry) +{ + if (addEntry) { + addEntry->addTableRow(table); + return; + } + + table.reserve(cdb.size()); + for (size_t k = 0; ksetObject(cdb[k]); + } + } +} + +void RunnerDB::refreshRunnerTableData(Table &table) { + for (size_t k = 0; ksetObject(oRDB[k]); + } + } +} + +Table *RunnerDB::getClubTB()//Table mode +{ + bool canEdit = !oe->isClient(); + + if (clubTable == 0) { + Table *table = new Table(oe, 20, "Klubbdatabasen", "clubdb"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 200, false); + oClub::buildTableCol(oe, table); + + if (canEdit) + table->setTableProp(Table::CAN_DELETE|Table::CAN_INSERT|Table::CAN_PASTE); + else + table->setTableProp(0); + + table->setClearOnHide(false); + table->addOwnership(); + clubTable = table; + } + + int nr = 0; + for (size_t k = 0; k < cdb.size(); k++) { + if (!cdb[k].isRemoved()) + nr++; + } + + if (clubTable->getNumDataRows() != nr) + clubTable->update(); + return clubTable; +} + + +void oDBRunnerEntry::addTableRow(Table &table) const { + bool canEdit = !oe->isClient(); + + oDBRunnerEntry &it = *(oDBRunnerEntry *)(this); + table.addRow(index+1, &it); + if (!db) + throw meosException("Not initialized"); + + RunnerDBEntry &r = db->rdb[index]; + int row = 0; + table.set(row++, it, TID_INDEX, itos(index+1), false, cellEdit); + + char bf[16]; + oBase::converExtIdentifierString(r.extId, bf); + table.set(row++, it, TID_ID, bf, false, cellEdit); + table.set(row++, it, TID_NAME, r.name, canEdit, cellEdit); + + const pClub pc = db->getClub(r.clubNo); + if (pc) + table.set(row++, it, TID_CLUB, pc->getName(), canEdit, cellSelection); + else + table.set(row++, it, TID_CLUB, "", canEdit, cellSelection); + + table.set(row++, it, TID_CARD, r.cardNo > 0 ? itos(r.cardNo) : "", canEdit, cellEdit); + char nat[4] = {r.national[0],r.national[1],r.national[2], 0}; + + table.set(row++, it, TID_NATIONAL, nat, canEdit, cellEdit); + char sex[2] = {r.sex, 0}; + table.set(row++, it, TID_SEX, sex, canEdit, cellEdit); + table.set(row++, it, TID_YEAR, itos(r.birthYear), canEdit, cellEdit); + + oClass *val = 0; + bool found = false; + + if (r.extId != 0) + found = db->runnerInEvent.lookup(r.extId, val); + + if (canEdit) + table.setTableProp(Table::CAN_DELETE|Table::CAN_INSERT|Table::CAN_PASTE); + else + table.setTableProp(0); + + if (!found) + table.set(row++, it, TID_ENTER, "@+", false, cellAction); + else + table.set(row++, it, TID_ENTER, val ? val->getName() : "", false, cellEdit); +} + +const RunnerDBEntry &oDBRunnerEntry::getRunner() const { + if (!db) + throw meosException("Not initialized"); + return db->rdb[index]; +} + +bool oDBRunnerEntry::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + if (!db) + throw meosException("Not initialized"); + RunnerDBEntry &r = db->rdb[index]; + + switch(id) { + case TID_NAME: + r.setName(input.c_str()); + r.getName(output); + db->nhash.clear(); + return true; + case TID_CARD: + db->rhash.remove(r.cardNo); + r.cardNo = atoi(input.c_str()); + db->rhash.insert(r.cardNo, index); + if (r.cardNo) + output = itos(r.cardNo); + else + output = ""; + return true; + case TID_NATIONAL: + if (input.empty()) { + r.national[0] = 0; + r.national[1] = 0; + r.national[2] = 0; + } + else if (input.size() >= 2) + memcpy(r.national, input.c_str(), 3); + + output = r.getNationality(); + break; + case TID_SEX: + r.sex = input[0]; + output = r.getSex(); + break; + case TID_YEAR: + r.birthYear = short(atoi(input.c_str())); + output = itos(r.getBirthYear()); + break; + + case TID_CLUB: + r.clubNo = inputId; + output = input; + break; + } + return false; +} + +void oDBRunnerEntry::fillInput(int id, vector< pair > &out, size_t &selected) +{ + RunnerDBEntry &r = db->rdb[index]; + if (id==TID_CLUB) { + db->fillClubs(out); + out.push_back(make_pair("-", 0)); + selected = r.clubNo; + } +} + +void oDBRunnerEntry::remove() { + RunnerDBEntry &r = db->rdb[index]; + r.remove(); + db->idhash.remove(r.extId); + string cname(canonizeName(r.name)); + multimap::const_iterator it = db->nhash.find(cname); + + while (it != db->nhash.end() && cname == it->first) { + if (it->second == index) { + db->nhash.erase(it); + break; + } + ++it; + } + + if (r.cardNo > 0) { + int ix = -1; + if (db->rhash.lookup(r.cardNo, ix) && ix == index) { + db->rhash.remove(r.cardNo); + } + } +} + +bool oDBRunnerEntry::canRemove() const { + return true; +} + +oDBRunnerEntry *RunnerDB::addRunner() { + rdb.push_back(RunnerDBEntry()); + oRDB.push_back(oDBRunnerEntry(oe)); + oRDB.back().init(this, rdb.size() - 1); + + return &oRDB.back(); +} + +oClub *RunnerDB::addClub() { + freeCIx = max(freeCIx + 1, cdb.size()); + while (chash.count(freeCIx)) + freeCIx++; + + cdb.push_back(oDBClubEntry(oe, freeCIx, cdb.size(), this)); + chash.insert(freeCIx, cdb.size()-1); + cnhash.clear(); + + return &cdb.back(); +} + +oDataContainer &oDBRunnerEntry::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + throw meosException("Not implemented"); +} + +oDBClubEntry::oDBClubEntry(oEvent *oe, int id, int ix, RunnerDB *dbin) : oClub(oe, id) { + index = ix; + db = dbin; +} + +oDBClubEntry::oDBClubEntry(const oClub &c, int ix, RunnerDB *dbin) : oClub(c) { + index = ix; + db = dbin; +} + +oDBClubEntry::~oDBClubEntry() { +} + +void oDBClubEntry::remove() { + Removed = true; + db->chash.remove(getId()); + + vector split; + db->canonizeSplitName(getName(), split); + for (size_t j = 0; j::const_iterator it = db->cnhash.find(split[j]); + while (it != db->cnhash.end() && split[j] == it->first) { + if (it->second == index) { + db->cnhash.erase(it); + break; + } + ++it; + } + } +} + +bool oDBClubEntry::canRemove() const { + return true; +} + +int oDBClubEntry::getTableId() const { + return index + 1; +} + \ No newline at end of file diff --git a/code/RunnerDB.h b/code/RunnerDB.h new file mode 100644 index 0000000..1b57b0d --- /dev/null +++ b/code/RunnerDB.h @@ -0,0 +1,249 @@ +#pragma once + +#include +#include +#include "inthashmap.h" +#include "oclub.h" +#include +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +const int baseNameLength=32; + +//Has 0-clearing constructor. Must not contain any +//dynamic data etc. +struct RunnerDBEntryV1 { + RunnerDBEntryV1(); + + char name[baseNameLength]; + int cardNo; + int clubNo; + char national[3]; + char sex; + short int birthYear; + short int reserved; +}; + +struct RunnerDBEntry { + // Init from old struct + void init(const RunnerDBEntryV1 &dbe); + RunnerDBEntry(); + + /** Binary compatible with V1*/ + char name[baseNameLength]; + int cardNo; + int clubNo; + char national[3]; + char sex; + short int birthYear; + short int reserved; + /** End of V1*/ + + __int64 extId; + + void getName(string &name) const; + void setName(const char *name); + + string getGivenName() const; + string getFamilyName() const; + + string getNationality() const; + int getBirthYear() const {return birthYear;} + string getSex() const; + + __int64 getExtId() const; + void setExtId(__int64 id); + + bool isRemoved() const {return (reserved & 1) == 1;} + void remove() {reserved |= 1;} +}; + +typedef vector RunnerDBVector; + +class oDBRunnerEntry; +class oClass; +class oDBClubEntry; + +class RunnerDB { +private: + oEvent *oe; + + Table *runnerTable; + Table *clubTable; + + bool check(const RunnerDBEntry &rde) const; + + intkeymap runnerInEvent; + + /** Init name hash lazy */ + void setupNameHash() const; + void setupIdHash() const; + void setupCNHash() const; + + vector rdb; + vector cdb; + vector oRDB; + + // Runner card hash + inthashmap rhash; + + // Runner id hash + mutable intkeymap idhash; + + // Club id hash + inthashmap chash; + + // Last known free index + int freeCIx; + + // Name hash + mutable multimap nhash; + + // Club name hash + mutable multimap cnhash; + + static void canonizeSplitName(const string &name, vector &split); + + bool loadedFromServer; + + /** Date when database was updated. The format is YYYYMMDD */ + int dataDate; + + /** Time when database was updated. The format is HH:MM:SS */ + int dataTime; + + void fillClubs(vector< pair > &out) const; + +public: + + void generateRunnerTableData(Table &table, oDBRunnerEntry *addEntry); + void generateClubTableData(Table &table, oClub *addEntry); + + void refreshRunnerTableData(Table &table); + void refreshClubTableData(Table &table); + void refreshTables(); + + Table *getRunnerTB(); + Table *getClubTB(); + + void hasEnteredCompetition(__int64 extId); + + void releaseTables(); + + /** Get the date, YYYY-MM-DD HH:MM:SS when database was updated */ + string getDataDate() const; + /** Set the date YYYY-MM-DD HH:MM:SS when database was updated */ + void setDataDate(const string &date); + + + /** Returns true if the database was loaded from server */ + bool isFromServer() const {return loadedFromServer;} + + /** Prepare for loading runner from server*/ + void prepareLoadFromServer(int nrunner, int nclub); + + const vector& getRunnerDB() const; + const vector& getClubDB() const; + + void clearRunners(); + void clearClubs(); + + /** Add a club. Create a new Id if necessary*/ + int addClub(oClub &c, bool createNewId); + RunnerDBEntry *addRunner(const char *name, __int64 extId, + int club, int card); + + oDBRunnerEntry *addRunner(); + oClub *addClub(); + + RunnerDBEntry *getRunnerByIndex(size_t index) const; + RunnerDBEntry *getRunnerById(__int64 extId) const; + RunnerDBEntry *getRunnerByCard(int card) const; + RunnerDBEntry *getRunnerByName(const string &name, int clubId, + int expectedBirthYear) const; + + bool getClub(int clubId, string &club) const; + oClub *getClub(int clubId) const; + + oClub *getClub(const string &name) const; + + void saveClubs(const char *file); + void saveRunners(const char *file); + void loadRunners(const char *file); + void loadClubs(const char *file); + + void updateAdd(const oRunner &r, map &clubIdMap); + + void importClub(oClub &club, bool matchName); + void compactifyClubs(); + + void getAllNames(vector &givenName, vector &familyName); + RunnerDB(oEvent *); + ~RunnerDB(void); + friend class oDBRunnerEntry; + friend class oDBClubEntry; +}; + +class oDBRunnerEntry : public oBase { +private: + RunnerDB *db; + int index; +protected: + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + int getDISize() const {return 0;} + void changedObject() {} +public: + + int getIndex() const {return index;} + void init(RunnerDB *db_, int index_) {db=db_, index=index_; Id = index;} + + const RunnerDBEntry &getRunner() const; + + void addTableRow(Table &table) const; + bool inputData(int id, const string &input, + int inputId, string &output, bool noUpdate); + void fillInput(int id, vector< pair > &out, size_t &selected); + + oDBRunnerEntry(oEvent *oe); + virtual ~oDBRunnerEntry(); + + void remove(); + bool canRemove() const; + + string getInfo() const {return "Database Runner";} +}; + + +class oDBClubEntry : public oClub { +private: + int index; + RunnerDB *db; +public: + oDBClubEntry(oEvent *oe, int id, int index, RunnerDB *db); + oDBClubEntry(const oClub &c, int index, RunnerDB *db); + + int getTableId() const; + virtual ~oDBClubEntry(); + void remove(); + bool canRemove() const; +}; diff --git a/code/SportIdent.cpp b/code/SportIdent.cpp new file mode 100644 index 0000000..8b2d9f5 --- /dev/null +++ b/code/SportIdent.cpp @@ -0,0 +1,2341 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// SportIdent.cpp: implementation of the SportIdent class. +// +////////////////////////////////////////////////////////////////////// + +// Check implementation r56. + +#include "stdafx.h" +#include "meos.h" +#include "SportIdent.h" +#include +#include +#include +#include "localizer.h" +#include "meos_util.h" +#include "oPunch.h" +#include + +#include +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +//#define DEBUG_SI + +SI_StationData::SI_StationData() { + stationNumber=0; + stationMode=0; + extended=false; + handShake=false; + autoSend=false; + radioChannel = 0; +} + +SI_StationInfo::SI_StationInfo() +{ + ThreadHandle=0; + hComm=0; + memset(&TimeOuts, 0, sizeof(TimeOuts)); + + tcpPort=0; + localZeroTime=0; +} + +SportIdent::SportIdent(HWND hWnd, DWORD Id) +{ + ClassId=Id; + hWndNotify=hWnd; + + //hComm=0; + //ThreadHandle=0; + n_SI_Info=0; + + ZeroTime=0; + InitializeCriticalSection(&SyncObj); + + tcpPortOpen=0; + serverSocket=0; +} + +SportIdent::~SportIdent() +{ + CloseCom(0); + DeleteCriticalSection(&SyncObj); +} + +// CRC algoritm used by SPORTIdent GmbH +// implemented for MeOS in C++ +WORD SportIdent::CalcCRC(BYTE *data, DWORD count) +{ + // Return 0 for no or one data byte + if (count<2) + return 0; + + size_t index=0; + WORD crc = (WORD(data[index])<<8) + WORD(data[index+1]); + index +=2; + // Return crc for two data bytes + if (count==2) + return crc; + + WORD value; + for (size_t k = count>>1; k>0; k--) { + if (k>1) { + value = (WORD(data[index])<<8) + WORD(data[index+1]); + index +=2; + } + else // If the number of bytes is odd, complete with 0. + value = (count&1) ? data[index]<<8 : 0; + + for (int j = 0; j<16; j++) { + if (crc & 0x8000) { + crc <<= 1; + if (value & 0x8000) + crc++; + crc ^= 0x8005; + } + else { + crc <<= 1; + if (value & 0x8000) + crc++; + } + value <<= 1; + } + } + return crc; +} + +void SportIdent::SetCRC(BYTE *bf) +{ + DWORD len=bf[1]; + WORD crc=CalcCRC(bf, len+2); + bf[len+2]=HIBYTE(crc); + bf[len+3]=LOBYTE(crc); +} + +bool SportIdent::CheckCRC(BYTE *bf) +{ + DWORD len=bf[1]; + WORD crc=CalcCRC(bf, len+2); + + return bf[len+2]==HIBYTE(crc) && bf[len+3]==LOBYTE(crc); +} + +bool SportIdent::ReadSystemData(SI_StationInfo *si, int retry) +{ + BYTE c[16]; + BYTE buff[256]; + + c[0]=STX; + c[1]=0x83; + c[2]=0x02; + c[3]=0x70; //Request address 0x70 + c[4]=0x06; //And 6 bytes + //Address 0x74 = protocoll settings + //Address 0x71 = Programming ctrl/readout/finish etc. + SetCRC(c+1); + c[7]=ETX; + + DWORD written=0; + WriteFile(si->hComm, c, 8, &written, NULL); + Sleep(100); + memset((void *)buff, 0, 30); + DWORD offset = 0; + ReadBytes_delay(buff, sizeof(buff), 15, si->hComm); + if (buff[0] == 0xFF && buff[1] == STX) + offset++; + if (1){ + if (CheckCRC(LPBYTE(buff+1 + offset))){ + si->data.resize(1); + SI_StationData &da = si->data[0]; + da.stationNumber=511 & MAKEWORD(buff[4 + offset], buff[3 + offset]); + BYTE PR=buff[6+4 + offset]; + BYTE MO=buff[6+1 + offset]; + da.extended = (PR&0x1)!=0; + da.handShake = (PR&0x4)!=0; + da.autoSend = (PR&0x2)!=0; + da.stationMode = MO & 0xf; + } + else if (retry>0) + return ReadSystemData(si, retry-1); + else return false; + } + else if (retry>0) + return ReadSystemData(si, retry-1); + else + return false; + + return true; +} + +bool SportIdent::ReadSystemDataV2(SI_StationInfo &si) +{ + BYTE c[16]; + BYTE buff[4096]; + + int maxbytes = 256; + while (ReadByte(c[0], si.hComm) == 1 && maxbytes> 0) { + maxbytes--; + } + + // 02 83 01 00 80 bf 17 03 + + c[0]=STX; + c[1]=0x83; + c[2]=0x02; + c[3]=0; + c[4]=0x80; + c[5]=0xbf; + c[6]=0x17; + SetCRC(c+1); + c[7]=ETX; + + DWORD written=0; + WriteFile(si.hComm, c, 8, &written, NULL); + Sleep(100); + memset((void *)buff, 0, sizeof(buff) ); +// DWORD offset = 0; + int consumed = 0; + int read = ReadBytes_delay(buff, sizeof(buff), -1, si.hComm); + const int requested = 0x80; + while ( (read - consumed) >= requested) { + while (consumed < read && buff[consumed] != STX) + consumed++; + + BYTE *db = buff + consumed; + if ((read - consumed) >= requested && db[0] == STX) { + si.data.push_back(SI_StationData()); + int used = analyzeStation(db, si.data.back()); + if (used == 0) { + si.data.pop_back(); // Not valid + break; + } + else consumed += used; + + // Test duplicate units: si.data.push_back(si.data.back()); + } + else break; + } + + return si.data.size() > 0; +} + +int SportIdent::analyzeStation(BYTE *db, SI_StationData &si) { + DWORD size = 0; + DWORD addr = 0x70; + if (CheckCRC(LPBYTE(db+1))) { + size = DWORD(db[2]) + 6; + + bool dongle = db[0x11] == 0x6f && db[0x12] == 0x21; + + if (dongle) { + BYTE PR=db[69]; + BYTE MO=db[6+1+addr]; + si.extended=(PR&0x1)!=0; + si.handShake = false; + si.autoSend=db[68] == 1; + si.stationMode=MO & 0xf; + si.radioChannel = db[58] & 0x1; + si.stationNumber = 0; + } + else { + si.stationNumber=511 & MAKEWORD(db[4], db[3]); + BYTE PR=db[6+4+addr]; + BYTE MO=db[6+1+addr]; + si.extended=(PR&0x1)!=0; + si.handShake=(PR&0x4)!=0; + si.autoSend=(PR&0x2)!=0; + si.stationMode=MO & 0xf; + si.radioChannel = 0; + } + } + + return size; +} + +string decode(BYTE *bf, int read) +{ + string st; + for(int k=0;k<=read;k++){ + if (bf[k]==STX) + st+="STX "; + else if (bf[k]==ETX) + st+="ETX "; + else if (bf[k]==ACK) + st+="ACK "; + else if (bf[k]==DLE) + st+="DLE "; + else{ + char d[10]; + sprintf_s(d, "%02X ", bf[k]); + st+=d; + } + } + return st; +} + +bool SportIdent::OpenComListen(const char *com, DWORD BaudRate) { + CloseCom(com); + + SI_StationInfo *si = findStation(com); + + if (!si) { + SI_Info[n_SI_Info].ComPort=com; + SI_Info[n_SI_Info].ThreadHandle=0; + si=&SI_Info[n_SI_Info]; + n_SI_Info++; + } + si->data.clear(); + + string comfile=string("//./")+com; + si->hComm = CreateFile( comfile.c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + 0, + 0); + + if (si->hComm == INVALID_HANDLE_VALUE) { + si->hComm=0; + return false; // error opening port; abort + } + + //Store comport + //ComPort=com; + + GetCommTimeouts(si->hComm, &si->TimeOuts); + COMMTIMEOUTS MyTimeOuts=si->TimeOuts; + MyTimeOuts.ReadIntervalTimeout=50; + MyTimeOuts.ReadTotalTimeoutMultiplier = 10; + MyTimeOuts.ReadTotalTimeoutConstant = 300; + MyTimeOuts.WriteTotalTimeoutMultiplier = 10; + MyTimeOuts.WriteTotalTimeoutConstant = 300; + + SetCommTimeouts(si->hComm, &MyTimeOuts); + + DCB dcb; + memset(&dcb, 0, sizeof(dcb)); + dcb.DCBlength=sizeof(dcb); + dcb.BaudRate=BaudRate; + dcb.fBinary=TRUE; + dcb.fDtrControl=DTR_CONTROL_DISABLE; + dcb.fRtsControl=RTS_CONTROL_DISABLE; + dcb.Parity=NOPARITY; + dcb.StopBits=ONESTOPBIT; + dcb.ByteSize =8; + + SetCommState(si->hComm, &dcb); + return true; +} + +bool SportIdent::tcpAddPort(int port, DWORD zeroTime) +{ + CloseCom("TCP"); + + SI_StationInfo *si = findStation("TCP"); + + if (!si) { + SI_Info[n_SI_Info].ComPort="TCP"; + SI_Info[n_SI_Info].ThreadHandle=0; + si=&SI_Info[n_SI_Info]; + n_SI_Info++; + } + + si->tcpPort=port; + si->localZeroTime=zeroTime; + si->hComm=0; + return true; +} + +bool SportIdent::OpenCom(const char *com) +{ + CloseCom(com); + + SI_StationInfo *si = findStation(com); + + if (!si) { + SI_Info[n_SI_Info].ComPort=com; + SI_Info[n_SI_Info].ThreadHandle=0; + si=&SI_Info[n_SI_Info]; + n_SI_Info++; + } + + si->data.clear(); + + string comfile=string("//./")+com; + si->hComm = CreateFile( comfile.c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + 0,//FILE_FLAG_OVERLAPPED, + 0); + + if (si->hComm == INVALID_HANDLE_VALUE) { + si->hComm=0; + return false; // error opening port; abort + } + + GetCommTimeouts(si->hComm, &si->TimeOuts); + COMMTIMEOUTS MyTimeOuts=si->TimeOuts; + MyTimeOuts.ReadIntervalTimeout=50; + MyTimeOuts.ReadTotalTimeoutMultiplier = 10; + MyTimeOuts.ReadTotalTimeoutConstant = 300; + MyTimeOuts.WriteTotalTimeoutMultiplier = 10; + MyTimeOuts.WriteTotalTimeoutConstant = 300; + + SetCommTimeouts(si->hComm, &MyTimeOuts); + + DCB dcb; + memset(&dcb, 0, sizeof(dcb)); + dcb.DCBlength=sizeof(dcb); + dcb.BaudRate=CBR_38400; + dcb.fBinary=TRUE; + dcb.fDtrControl=DTR_CONTROL_DISABLE; + dcb.fRtsControl=RTS_CONTROL_DISABLE; + dcb.Parity=NOPARITY; + dcb.StopBits=ONESTOPBIT; + dcb.ByteSize =8; + + SetCommState(si->hComm, &dcb); + + BYTE c[128]; + + c[0]=WAKEUP; + c[1]=STX; + c[2]=STX; + c[3]=0xF0; + c[4]=0x01; + c[5]=0x4D; + SetCRC(c+3); + + c[8]=ETX; + + DWORD written; + + WriteFile(si->hComm, c, 9, &written, NULL); + Sleep(700); + //c[6]= + DWORD read; + BYTE buff[128]; + memset(buff, 0, sizeof(buff)); + read = ReadBytes(buff, 1, si->hComm); + + if (read == 1 && buff[0] == 0xFF){ + Sleep(100); + read = ReadBytes(buff, 1, si->hComm); + } + + if (read==1 && buff[0]==STX) { + ReadFile(si->hComm, buff, 8, &read, NULL); + + if (!ReadSystemDataV2(*si)) + ReadSystemData(si, 1); + } + else { + dcb.BaudRate=CBR_4800; + SetCommState(si->hComm, &dcb); + + WriteFile(si->hComm, c, 9, &written, NULL); + Sleep(600); + //c[6]= + DWORD read; + BYTE buff[128]; + + read=ReadByte(*buff, si->hComm); + + if (read==1 && buff[0]==STX) { + ReadFile(si->hComm, buff, 8, &read, NULL); + ReadSystemData(si); + } + else { + BYTE cold[8]; + cold[0]=STX; + cold[1]=0x70; + cold[2]=0x4D; + cold[3]=ETX; + + WriteFile(si->hComm, cold, 4, &written, NULL); + + Sleep(500); + + read=ReadByte(*buff, si->hComm); + + if (read!=1 || buff[0]!=STX) { + CloseCom(si->ComPort.c_str()); + return false; + } + + read=ReadBytesDLE_delay(buff, sizeof(buff), 4, si->hComm); + if (read==4) { + si->data.resize(1); + if (buff[1]>30) + si->data[0].stationNumber = buff[1]; + else{ + si->data[0].stationNumber = buff[2]; + + } + if (buff[3]!=ETX) + ReadByte(buff[4], si->hComm); + } + } + } + + return true; +} + + +SI_StationInfo *SportIdent::findStation(const string &com) +{ + for(int i=0;iComPort=="TCP") { + if (tcpPortOpen) { + EnterCriticalSection(&SyncObj); + shutdown(SOCKET(serverSocket), SD_BOTH); + LeaveCriticalSection(&SyncObj); + + Sleep(300); + + EnterCriticalSection(&SyncObj); + closesocket(SOCKET(serverSocket)); + tcpPortOpen = 0; + serverSocket = 0; + LeaveCriticalSection(&SyncObj); + } + } + else if (si && si->hComm) + { + if (si->ThreadHandle) + { + EnterCriticalSection(&SyncObj); + TerminateThread(si->ThreadHandle, 0); + LeaveCriticalSection(&SyncObj); + + CloseHandle(si->ThreadHandle); + si->ThreadHandle=0; + } + SetCommTimeouts(si->hComm, &si->TimeOuts); //Restore + CloseHandle(si->hComm); + si->hComm=0; + } + } +} + + +int SportIdent::ReadByte_delay(BYTE &byte, HANDLE hComm) +{ + byte=0; + return ReadBytes_delay(&byte, 1, 1, hComm); +} + + +int SportIdent::ReadByte(BYTE &byte, HANDLE hComm) +{ + byte=0; + + if (!hComm) + return -1; + + DWORD dwRead; + + if (ReadFile(hComm, &byte, 1, &dwRead, NULL)) + { +#ifdef DEBUG_SI2 + char t[64]; + sprintf_s(t, 64, "read=%02X\n", (int)byte); + OutputDebugString(t); +#endif + if (dwRead) + return 1; + else return 0; + } + else return -1; +} + + + +int SportIdent::ReadBytes_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm) { + int read=0; + int d; + bool autoLen = false; + if (len == -1) { + len = min(buffSize, 10); + autoLen = true; + } + int toread=len; + + for(d=0;d<7 && read(buffSize - read, len); + if (maxToRead <= 0) + return read; + + int r = ReadBytes(byte+read, maxToRead, hComm); + + if (r==-1) { + if (read > 0) + return read; + return -1; + } + read+=r; + if (read == 1 && byte[0] == NAK) + return read; + + if (autoLen && r == len) { + int rloop; + Sleep(100); + while (read < int(buffSize) && (rloop = ReadBytes(byte+read, min(16, buffSize-read), hComm)) > 0) { + read += rloop; + } + } + + if (read < toread) { + len = toread - read; + Sleep(100); + } + } +#ifdef DEBUG_SI2 + char t[64]; + sprintf_s(t, 64, "retry=%d\n", d); + OutputDebugString(t); + + for (int k = 0; k < read; k++) { + char t[64]; + sprintf_s(t, 64, "mreadd=%02X\n", (int)byte[k]); + OutputDebugString(t); + } +#endif + + return read; +} + +int SportIdent::ReadBytes(BYTE *byte, DWORD len, HANDLE hComm) +{ + if (!hComm) + return -1; + + DWORD dwRead; + + if (ReadFile(hComm, byte, len, &dwRead, NULL)) + { +#ifdef DEBUG_SI2 + for (int k = 0; k < dwRead; k++) { + char t[64]; + sprintf_s(t, 64, "mread=%02X\n", (int)byte[k]); + OutputDebugString(t); + } +#endif + return dwRead; + } + else return -1; +} + + +int SportIdent::ReadBytesDLE_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm) +{ + int read=0; + int toread=len; + int d; + + for(d=0;d<15 && read 0) + { + DWORD ip=0; + DWORD op=0; + + for (ip=0;ip 10) { + if (GetTickCount() > timeout) { + break; + } + else + iter = 0; + } + Sleep(0); + } + + r=recv(client, temp, 15, 0); + + if (r==15) { + //BYTE c[15]={0, 0x64,0,0x48, 0xa4, 0x07, 00, 0x05, 00, 00, 00, 0x8d, 0x16, 0x06, 0x00}; + //memcpy(temp, c, 15); + op.Type=temp[0]; + op.CodeNo=*(WORD*)(&temp[1]); + op.SICardNo=*(DWORD *)(&temp[3]); + op.CodeDay=*(DWORD *)(&temp[7]); + op.CodeTime=*(DWORD *)(&temp[11]); + + if (op.Type == 64 && op.CodeNo>1 && op.CodeNo<=192 && op.CodeTime == 0) { + // Recieved card + int nPunch = op.CodeNo; + vector punches(nPunch); + r = recv(client, (char*)&punches[0], 8 * nPunch, 0); + if (r == 8 * nPunch) { + SICard card; + card.CheckPunch.Code = -1; + card.StartPunch.Code = -1; + card.FinishPunch.Code = -1; + card.CardNumber = op.SICardNo; + for (int k = 0; k < nPunch; k++) { + punches[k].Time /= 10; + if (punches[k].Code == oPunch::PunchStart) + card.StartPunch = punches[k]; + else if (punches[k].Code == oPunch::PunchFinish) + card.FinishPunch = punches[k]; + else if (punches[k].Code == oPunch::PunchCheck) + card.CheckPunch = punches[k]; + else + card.Punch[card.nPunch++] = punches[k]; + } + addCard(card); + } + } + else + AddPunch(op.CodeTime/10, op.CodeNo, op.SICardNo, 0); + } + else r=-1; + + } + //close the client socket + closesocket(client); + } + else { + int err=WSAGetLastError(); + + if (err==WSAESHUTDOWN || err==WSAECONNABORTED) { + tcpPortOpen=0; + serverSocket=0; + closesocket(server); + //MessageBox(0, "TCP CLOSE", 0, MB_OK); + return 0; + } + } + } + + //MessageBox(0, "TCP CLOSE BYE", 0, MB_OK); + + //closesocket() closes the socket and releases the socket descriptor + closesocket(server); + + WSACleanup(); + return 1; +} + +bool SportIdent::MonitorSI(SI_StationInfo &si) +{ + HANDLE hComm=si.hComm; + + if (!hComm) + return false; + + DWORD dwCommEvent; + DWORD dwRead; + BYTE chRead; + + if (!SetCommMask(hComm, EV_RXCHAR)) + { + // Error setting communications event mask. + //Sleep(1000); + return false; + } + else + { + for ( ; ; ) { + if (WaitCommEvent(hComm, &dwCommEvent, NULL)) { + if (dwCommEvent & EV_RXCHAR) do{ + if ( (dwRead=ReadByte(chRead, hComm))!=-1) + { + // A byte has been read; process it. + if (chRead==STX && ReadByte(chRead, hComm)) + { + switch(chRead) + { + case 0xD3:{//Control Punch, extended mode. + BYTE bf[32]; + bf[0]=chRead; + ReadBytes(bf+1, 17, hComm); + if (CheckCRC(LPBYTE(bf))) + { + WORD Station=MAKEWORD(bf[3], bf[2]); + + DWORD ShortCard=MAKEWORD(bf[7], bf[6]); + DWORD Series=bf[5]; + + + DWORD Card=MAKELONG(MAKEWORD(bf[7], bf[6]), MAKEWORD(bf[5], bf[4])); + + if (Series<=4 && Series>=1) + Card=ShortCard+100000*Series; + + DWORD Time=0; + if (bf[8]&0x1) Time=3600*12; + Time+=MAKEWORD(bf[10], bf[9]); +#ifdef DEBUG_SI + char str[128]; + sprintf_s(str, "EXTENDED: Card = %d, Station = %d, StationMode = %d", Card, Station, si.StationMode); + MessageBox(NULL, str, NULL, MB_OK); +#endif + AddPunch(Time, Station & 511, Card & 0x00FFFFFF, si.stationMode()); + } + break; + } + case 0x53:{ //Control Punch, old mode + BYTE bf[32]; + bf[0]=chRead; + //Sleep(200); + ReadBytesDLE(bf+1, 30, hComm); + + BYTE Station=bf[2]; + BYTE Series=bf[3]; + WORD Card=MAKEWORD(bf[5], bf[4]); + + + DWORD DCard; + + if (Series==1) + DCard=Card; + else if (Series<=4) + DCard=Card+100000*Series; + else + DCard=MAKELONG(Card, Series); + + //if (Series!=1) + // Card+=100000*Series; + + DWORD Time=MAKEWORD(bf[8], bf[7]); + BYTE p=bf[1]; + if (p&0x1) Time+=3600*12; + +#ifdef DEBUG_SI + char str[128]; + sprintf_s(str, "OLD: Card = %d, Station = %d, StationMode = %d", DCard, Station, si.StationMode); + MessageBox(NULL, str, NULL, MB_OK); +#endif + AddPunch(Time, Station, DCard, si.stationMode()); + break; + } + case 0xE7:{//SI5/6 removed + BYTE bf[32]; + ReadBytes(bf+1, 10, hComm); + break; + } + + case 0xE6:{ + BYTE bf[32]; + bf[0]=0xE6; + ReadBytes(bf+1, 10, hComm); + + //ReadByte(chRead); //ETX! + if (CheckCRC(LPBYTE(bf))) + GetSI6DataExt(hComm); + + break; + } + case 0xE5:{ + BYTE bf[32]; + bf[0]=0xE5; + ReadBytes(bf+1, 10, hComm); + + if (CheckCRC(LPBYTE(bf))) + GetSI5DataExt(hComm); + + break; + } + case 0x46: + ReadByte(chRead, hComm); //0x49?! + ReadByte(chRead, hComm); //ETX! + GetSI5Data(hComm); + break; + case 0x66:{ //STX, 66h, CSI, TI, TP, CN3, CN2, CN1, CN0, ETX + BYTE bf[32]; + //SICard5Detect si5; + //si5.code=0xE5; + bf[0]=0xE6; + ReadBytesDLE(bf+1, 8, hComm); + + GetSI6Data(hComm); + + break; + } + case 0xB1:{ + BYTE bf[200]; + bf[0]=chRead; + ReadBytes(bf+1, 200, hComm); + //GetSI5DataExt(hComm); + MessageBox(NULL, "Programmera stationen utan AUTOSEND!", NULL, MB_OK); + } + break; + + case 0xE1:{ + BYTE bf[200]; + bf[0]=chRead; + ReadBytes(bf+1, 200, hComm); + MessageBox(NULL, "Programmera stationen utan AUTOSEND!", NULL, MB_OK); + } + break; + case 0xE8:{ + BYTE bf[32]; + bf[0]=0xE8; + ReadBytes(bf+1, 10, hComm); + + //ReadByte(chRead); //ETX! + if (CheckCRC(LPBYTE(bf))) + GetSI9DataExt(hComm); + + break; + } + // MessageBox(NULL, "SI-card not supported", NULL, MB_OK); + // break; + default: + + BYTE bf[128]; + bf[0]=chRead; + int rb=ReadBytes(bf+1, 120, hComm); + + string st; + for(int k=0;k<=rb;k++){ + if (bf[k]==STX) + st+="STX "; + else if (bf[k]==ETX) + st+="ETX "; + else if (bf[k]==ACK) + st+="ACK "; + else if (bf[k]==DLE) + st+="DLE "; + else{ + char d[10]; + sprintf_s(d, "%02X (%d) ", bf[k], bf[k]); + st+=d; + } + } + //MessageBox(NULL, st.c_str(), "Unknown SI response", MB_OK); + } + } + } + else + { + // An error occurred in the ReadFile call. + return false; + } + } while (dwRead); + else + { + // MessageBox(hWndNotify, "EXIT 1", NULL, MB_OK); + // Error in WaitCommEvent + // return false; + } + } + else + { + for(int i=0;i2) + compact = true; + } + } + + if (compact) { + BYTE b2[128*7]; + // 192 punches, sicard6 star + for (int k = 0; k<128*8; k++) { + if (k<128) + b2[k] = b[k]; + else if (k>=256 && k<128*6) + b2[k+128] = b[k]; + else if (k>=128*6) + b2[k-128*5] = b[k]; + } + memcpy(b, b2, sizeof(b2)); + } + + c[0]=ACK; + WriteFile(hComm, c, 1, &written, NULL); + + OutputDebugString("-ACK-"); + SICard card; + GetCard6Data(b, card); + + addCard(card); +} + +void SportIdent::GetSI5Data(HANDLE hComm) +{ + BYTE c[128]; + + c[0]=STX; + c[1]=0x31; + c[2]=ETX; + + DWORD written=0; + WriteFile(hComm, c, 3, &written, NULL); + + if (written==3) + { + Sleep(900); + BYTE bf[256]; + memset(bf, 0, 256); + + int read=ReadBytesDLE(bf, 3, hComm); + + if (read==0) + { + Sleep(1000); + read=ReadBytesDLE(bf, 3, hComm); + } + + if (bf[0]==STX && bf[1]==0x31) + { + + BYTE sum=bf[2]; //Start calc checksum + + read=ReadBytesDLE(bf, 128, hComm); + BYTE cs, etx; + ReadBytesDLE(&cs, 1, hComm); + ReadByte(etx, hComm); + + for(int i=0;i<128;i++) + sum+=bf[i]; + + if (sum==cs) + { + c[0]=ACK; + WriteFile(hComm, c, 1, &written, NULL); + + //BYTE *Card5Data=bf+5; + SICard card; + GetCard5Data(bf, card); + + addCard(card); + } + } + } +} + + + +bool SportIdent::GetCard5Data(BYTE *data, SICard &card) +{ +/* ofstream fout("si.txt"); + + for(int m=0;m<128;m++) + { + if (m%16==0) fout << endl; + + char bf[16]; + sprintf(bf, "%02x ", (DWORD)data[m]); + fout << bf; + } + + fout << endl; + return 0; +*/ + memset(&card, 0, sizeof(card)); + + DWORD number=MAKEWORD(data[5], data[4]); + + if (data[6]==1) + card.CardNumber=number; + else + card.CardNumber=100000*data[6]+number; + + data+=16; + + + AnalyseSI5Time(data+3, card.StartPunch.Time, card.StartPunch.Code); + AnalyseSI5Time(data+5, card.FinishPunch.Time, card.FinishPunch.Code); + AnalyseSI5Time(data+9, card.CheckPunch.Time, card.CheckPunch.Code); + +// card.StartPunch=MAKEWORD(data[4], data[3]); +// card.FinishPunch=MAKEWORD(data[6], data[5]); + card.nPunch=data[7]-1; + + data+=16; + + for (DWORD k=0;k> 2) & 0x0F; +// BYTE month = ((dt1 & 0x03) << 2) + (dt0 >> 6); +// BYTE day = (dt0 >> 1) & 0x1F; + + control=cn; + time=MAKEWORD(ptl, pth)+3600*12*(dt0&0x1); + } + else { + control=-1; + time=0; + } +} + +bool SportIdent::GetCard6Data(BYTE *data, SICard &card) +{ + /*ofstream fout("si.txt"); + + for(int m=0;m<128*3;m++) + { + if (m%16==0) fout << endl; + + char bf[16]; + sprintf_s(bf, 16, "%02x ", (DWORD)data[m]); + fout << bf; + } + + fout << endl;*/ + //return 0; + + memset(&card, 0, sizeof(card)); + + WORD hi=MAKEWORD(data[11], data[10]); + WORD lo=MAKEWORD(data[13], data[12]); + + card.CardNumber=MAKELONG(lo, hi); + + data+=16; + +// DWORD control; +// DWORD time; + + AnalysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code); + AnalysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code); + AnalysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code); + card.nPunch=min(int(data[2]), 192); + + int i; + + memcpy(card.LastName, data+32, 20); + for(i=19;i>0 && card.LastName[i]==0x20;i--) + card.LastName[i]=0; + + memcpy(card.FirstName, data+32+20, 20); + for(i=19;i>0 && card.FirstName[i]==0x20;i--) + card.FirstName[i]=0; + + data+=128-16; + + for(unsigned k=0;k>6)&0x3); + time=MAKEWORD(ptl, pth)+3600*12*(ptd&0x1); + return true; + } + else + { + control=-1; + time=0; + return false; + } +} + +void SportIdent::AnalyseSI5Time(BYTE *data, DWORD &time, DWORD &control) +{ + if (*LPWORD(data)!=0xEEEE) { + time=MAKEWORD(data[1], data[0]); + + if (ZeroTime<12*3600) { + //Förmiddag + if ( time < ZeroTime ) + time+=12*3600; //->Eftermiddag + } + else { + //Eftermiddag + + if ( time >= ZeroTime%(12*3600) ) { + //Eftermiddag + time+=12*3600; + } + // else Efter midnatt OK. + } + control=0; + } + else { + control=-1; + time=0; + } +} + + +void SportIdent::EnumrateSerialPorts(list &ports) +{ + //Make sure we clear out any elements which may already be in the array + ports.clear(); + + //Determine what OS we are running on + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + BOOL bGetVer = GetVersionEx(&osvi); + + //On NT use the QueryDosDevice API + if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) + { + //Use QueryDosDevice to look for all devices of the form COMx. This is a better + //solution as it means that no ports have to be opened at all. + TCHAR szDevices[65535]; + DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535); + if (dwChars) + { + int i=0; + + for (;;) + { + //Get the current device name + TCHAR* pszCurrentDevice = &szDevices[i]; + + //If it looks like "COMX" then + //add it to the array which will be returned + int nLen = _tcslen(pszCurrentDevice); + if (nLen > 3 && _tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0) + { + //Work out the port number + int nPort = _ttoi(&pszCurrentDevice[3]); + ports.push_front(nPort); + } + + // Go to next NULL character + while(szDevices[i] != _T('\0')) + i++; + + // Bump pointer to the next string + i++; + + // The list is double-NULL terminated, so if the character is + // now NULL, we're at the end + if (szDevices[i] == _T('\0')) + break; + } + } + //else + // TRACE(_T("Failed in call to QueryDosDevice, GetLastError:%d\n"), GetLastError()); + } + else + { + //On 95/98 open up each port to determine their existence + + //Up to 255 COM ports are supported so we iterate through all of them seeing + //if we can open them or if we fail to open them, get an access denied or general error error. + //Both of these cases indicate that there is a COM port at that number. + for (UINT i=1; i<256; i++) + { + //Form the Raw device name + char sPort[256]; + + sprintf_s(sPort, 256, "\\\\.\\COM%d", i); + + //Try to open the port + BOOL bSuccess = FALSE; + HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if (hPort == INVALID_HANDLE_VALUE) + { + DWORD dwError = GetLastError(); + + //Check to see if the error was because some other app had the port open or a general failure + if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE) + bSuccess = TRUE; + } + else + { + //The port was opened successfully + bSuccess = TRUE; + + //Don't forget to close the port, since we are going to do nothing with it anyway + CloseHandle(hPort); + } + + //Add the port number to the array which will be returned + if (bSuccess) + ports.push_front(i); + } + } +} + + + +void SportIdent::addCard(const SICard &sic) +{ + EnterCriticalSection(&SyncObj); + try { + ReadCards.push_front(sic); + } + catch(...) { + LeaveCriticalSection(&SyncObj); + throw; + } + LeaveCriticalSection(&SyncObj); + + PostMessage(hWndNotify, WM_USER, ClassId, 0); +} + +void SportIdent::AddPunch(DWORD Time, int Station, int Card, int Mode) +{ + SICard sic; + memset(&sic, 0, sizeof(sic)); + sic.CardNumber=Card; + sic.StartPunch.Code = -1; + sic.CheckPunch.Code = -1; + sic.FinishPunch.Code = -1; + + if (Mode==0 || Mode == 11){ // 11 is dongle + if (Station>30){ + sic.Punch[0].Code=Station; + sic.Punch[0].Time=Time; + sic.nPunch=1; + } + else if (Station == oPunch::PunchStart) { + sic.StartPunch.Time = Time; + sic.StartPunch.Code = oPunch::PunchStart; + } + else if (Station == oPunch::PunchCheck) { + sic.CheckPunch.Time = Time; + sic.CheckPunch.Code = oPunch::PunchCheck; + } + else{ + sic.FinishPunch.Time=Time; + sic.FinishPunch.Code = oPunch::PunchFinish; + } + } + else{ + if (Mode==0x02 || Mode == 50){ + sic.Punch[0].Code=Station; + sic.Punch[0].Time=Time; + sic.nPunch=1; + } + else if (Mode == 3) { + sic.StartPunch.Time=Time; + sic.StartPunch.Code = oPunch::PunchStart; + } + else if (Mode == 10) { + sic.CheckPunch.Time=Time; + sic.CheckPunch.Code = oPunch::PunchCheck; + } + else{ + sic.FinishPunch.Time=Time; + sic.FinishPunch.Code = oPunch::PunchFinish; + } + } + sic.PunchOnly=true; + + addCard(sic); +} + + +bool SportIdent::GetCard(SICard &sic) +{ + bool ret=false; + + EnterCriticalSection(&SyncObj); + + if (!ReadCards.empty()) { + sic=ReadCards.front(); + ReadCards.pop_front(); + ret=true; + } + + LeaveCriticalSection(&SyncObj); + + return ret; +} + +void start_si_thread(void *ptr) +{ + SportIdent *si=(SportIdent *)ptr; + + if (!si->Current_SI_Info) + return; + + EnterCriticalSection(&si->SyncObj); + SI_StationInfo si_info=*si->Current_SI_Info; //Copy data. + si->Current_SI_Info=0; + LeaveCriticalSection(&si->SyncObj); + + if (si_info.ComPort=="TCP") { + si->MonitorTCPSI(si_info.tcpPort, si_info.localZeroTime); + } + else { + if (!si_info.hComm) MessageBox(NULL, "ERROR", 0, MB_OK); + si->MonitorSI(si_info); + } +} + +void SportIdent::StartMonitorThread(const char *com) +{ + SI_StationInfo *si = findStation(com); + + if (si && (si->hComm || si->ComPort=="TCP")) + { + if (si->ComPort=="TCP") + tcpPortOpen=0; + + Current_SI_Info=si; + si->ThreadHandle=(HANDLE)_beginthread(start_si_thread, 0, this); + + while((volatile void *)Current_SI_Info) + Sleep(0); + + if (si->ComPort=="TCP") { + DWORD ec=0; + while( (GetExitCodeThread(si->ThreadHandle, &ec)!=0 && ec==STILL_ACTIVE && tcpPortOpen==0)) + Sleep(0); + } + } + else MessageBox(NULL, "ERROR", 0, MB_OK); +} + +void checkport_si_thread(void *ptr) +{ + int *port=(int *)ptr; + char bf[16]; + sprintf_s(bf, 16, "COM%d", *port); + SportIdent si(NULL, *port); + + if (!si.OpenCom(bf)) + *port=0; //No SI found here + else { + bool valid = true; + SI_StationInfo *sii = si.findStation(bf); + if (sii) { + if (sii->data.empty() || sii->data[0].stationNumber>=1024 || sii->data[0].stationMode>15 || + !(sii->data[0].autoSend || sii->data[0].handShake)) + valid = false; + } + if (valid) + *port = -(*port); + else + *port = 0; + } + si.CloseCom(0); + //_endthread(); +} + + +bool SportIdent::AutoDetect(list &ComPorts) +{ + list Ports; + + EnumrateSerialPorts(Ports); + + int array[128]; + //memset(array, 0, 128*sizeof(int)); + int i=0; + + while(!Ports.empty() && i<128) + { + array[i]=Ports.front(); + Ports.pop_front(); + (HANDLE)_beginthread(checkport_si_thread, 0, &array[i]); + i++; + //Sleep(0); + } + + int maxel=1; + while(maxel>0) + { + Sleep(300); + maxel=0; + + for(int k=0;kComPort=="TCP") + return tcpPortOpen && serverSocket; + else + return si!=0 && si->hComm && si->ThreadHandle; +} + +void SportIdent::getInfoString(const string &com, vector &infov) +{ + infov.clear(); + SI_StationInfo *si = findStation(com); + + if (com=="TCP") { + if (!si || !tcpPortOpen || !serverSocket) { + infov.push_back("TCP: "+lang.tl("ej aktiv.")); + return; + } + + char bf[128]; + sprintf_s(bf, lang.tl("TCP: Port %d, Nolltid: %s").c_str(), tcpPortOpen, "00:00:00"); + infov.push_back(bf); + return; + } + + if (!(si!=0 && si->hComm && si->ThreadHandle)) { + infov.push_back(com+": "+lang.tl("ej aktiv.")); + return; + } + + for (size_t k = 0; k < si->data.size(); k++) { + string info = si->ComPort; + + if (si->data.size() > 1) + info += MakeDash("-") + itos(k+1); + + const SI_StationData &da = si->data[k]; + if (da.extended) info+=lang.tl(": Utökat protokoll. "); + else info+=lang.tl(": Äldre protokoll. "); + + switch(da.stationMode){ + case 2: + case 50: + info+=lang.tl("Kontrol"); + break; + case 4: + info+=lang.tl("Mål"); + break; + case 3: + info+=lang.tl("Start"); + break; + case 5: + info+=lang.tl("Läs brickor"); + break; + case 7: + info+=lang.tl("Töm"); + break; + case 10: + info+=lang.tl("Check"); + break; + case 11: + info+=lang.tl("SRR Dongle ") + (da.radioChannel == 0? lang.tl("red channel.") : lang.tl("blue channel.")); + break; + default: + info+=lang.tl("Okänd funktion"); + } + + if (da.stationNumber) { + char bf[16]; + sprintf_s(bf, " (%d).", da.stationNumber); + info+=bf; + } + + info += lang.tl(" Kommunikation: "); + if (da.autoSend) info+=lang.tl("skicka stämplar."); + else if (da.handShake) info+=lang.tl("handskakning."); + else info+=lang.tl("[VARNING] ingen/okänd."); + + infov.push_back(info); + } +} + +vector SICard::codeLogData(int row) const +{ + vector log; + + log.push_back(itos(row)); + if (readOutTime[0] == 0) + log.push_back(getLocalTime()); + else + log.push_back(readOutTime); + log.push_back(itos(CardNumber)); + log.push_back(""); + log.push_back(""); + log.push_back(FirstName); + log.push_back(LastName); + log.push_back(Club); + log.push_back(""); + log.push_back(""); + log.push_back(""); + log.push_back(""); //email + log.push_back(""); + log.push_back(""); + log.push_back(""); + log.push_back(""); //zip + + log.push_back(""); //CLR_NO + log.push_back(""); + log.push_back(""); + + //We set monday on every punch, since this is our way of + //saying that we have 24-h clock. + if (signed(CheckPunch.Code) >= 0) { + log.push_back(itos(CheckPunch.Code)); + log.push_back("MO"); + log.push_back(formatTime(CheckPunch.Time)); + } + else { + log.push_back(""); //CHCK_NO + log.push_back(""); + log.push_back(""); + } + + if (signed(StartPunch.Code) >= 0) { + log.push_back(itos(StartPunch.Code)); + log.push_back("MO"); + log.push_back(formatTime(StartPunch.Time)); + } + else { + log.push_back(""); //START_NO + log.push_back(""); + log.push_back(""); + } + + if (signed(FinishPunch.Code) >= 0) { + log.push_back(itos(FinishPunch.Code)); + log.push_back("MO"); + log.push_back(formatTime(FinishPunch.Time)); + } + else { + log.push_back(""); //FINISH_NO + log.push_back(""); + log.push_back(""); + } + log.push_back(itos(nPunch)); + + for (int k=0;k<192;k++) { + if (k0) { + log.push_back("MO"); + log.push_back(formatTime(Punch[k].Time)); + } + else { + log.push_back(""); + log.push_back(""); + } + } + else { + log.push_back(""); + log.push_back(""); + log.push_back(""); + } + } + return log; +} + +vector SICard::logHeader() +{ + vector log; + + log.push_back("No."); + log.push_back("read at"); + log.push_back("SI-Card"); + log.push_back("St no"); + log.push_back("cat"); + log.push_back("First name"); + log.push_back("name"); + log.push_back("club"); + log.push_back("country"); + log.push_back("sex"); + log.push_back("year-op"); + log.push_back("EMail"); + log.push_back("mobile"); + log.push_back("city"); + log.push_back("street"); + log.push_back("zip"); + + log.push_back("CLR_CN"); + log.push_back("CLR_DOW"); + log.push_back("clear time"); + + log.push_back("CHK_CN"); + log.push_back("CHK_DOW"); + log.push_back("check time"); + + log.push_back("ST_CN"); + log.push_back("ST_DOW"); + log.push_back("start time"); + + log.push_back("FI_CN"); + log.push_back("FO_DOW"); + log.push_back("Finish time"); + + log.push_back("No. of punches"); + + for (int k=0;k<192;k++) { + string pf = itos(k+1); + log.push_back(pf+".CN"); + log.push_back(pf+".DOW"); + log.push_back(pf+".Time"); + } + return log; +} + +unsigned SICard::calculateHash() const { + unsigned h = nPunch * 100000 + FinishPunch.Time; + for (unsigned i = 0; i < nPunch; i++) { + h = h * 31 + Punch[i].Code; + h = h * 31 + Punch[i].Time; + } + h += StartPunch.Time; + return h; +} + +string SICard::serializePunches() const { + string ser; + if (CheckPunch.Code != -1) + ser += "C-" + itos(CheckPunch.Time); + + if (StartPunch.Code != -1) { + if (!ser.empty()) ser += ";"; + ser += "S-" + itos(StartPunch.Time); + } + for (DWORD i = 0; i < nPunch; i++) { + if (!ser.empty()) ser += ";"; + ser += itos(Punch[i].Code) + "-" + itos(Punch[i].Time); + } + + if (FinishPunch.Code != -1) { + if (!ser.empty()) ser += ";"; + ser += "F-" + itos(FinishPunch.Time); + } + return ser; +} + +void SICard::deserializePunches(const string &arg) { + FinishPunch.Code = -1; + StartPunch.Code = -1; + CheckPunch.Code = -1; + vector out; + split(arg, ";", out); + nPunch = 0; + for (size_t k = 0; k< out.size(); k++) { + vector mark; + split(out[k], "-", mark); + if (mark.size() != 2) + throw std::exception("Invalid string"); + DWORD *tp = 0; + if (mark[0] == "F") { + FinishPunch.Code = 1; + tp = &FinishPunch.Time; + } + else if (mark[0] == "S") { + StartPunch.Code = 1; + tp = &StartPunch.Time; + } + else if (mark[0] == "C") { + CheckPunch.Code = 1; + tp = &CheckPunch.Time; + } + else { + Punch[nPunch].Code = atoi(mark[0].c_str()); + tp = &Punch[nPunch++].Time; + } + + *tp = atoi(mark[1].c_str()); + } + if (out.size() == 1) + PunchOnly = true; +} diff --git a/code/SportIdent.h b/code/SportIdent.h new file mode 100644 index 0000000..bd4acf0 --- /dev/null +++ b/code/SportIdent.h @@ -0,0 +1,227 @@ +// SportIdent.h: interface for the SportIdent class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_) +#define AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +const BYTE STX=0x02; +const BYTE ETX=0x03; +const BYTE ACK=0x06; +const BYTE DLE=0x10; +const BYTE WAKEUP=0xFF; +const BYTE NAK=0x15; + +// This is taken from r56 and checked in on r63 +#include + +struct SICard5Detect +{ + BYTE code;//Code; + BYTE len; + SHORT station; + DWORD number; + WORD crc; +}; + +struct SIPunch +{ + DWORD Code; + DWORD Time; +}; + +struct SICard +{ + SICard() { + clear(0); + convertedTime = false; + } + // Clears the card if this == condition or condition is 0 + void clear(const SICard *condition) { + if (this==condition || condition==0) + memset(this, 0, sizeof(SICard)); + } + bool empty() const {return CardNumber==0;} + DWORD CardNumber; + SIPunch StartPunch; + SIPunch FinishPunch; + SIPunch CheckPunch; + DWORD nPunch; + SIPunch Punch[192]; + char FirstName[21]; + char LastName[21]; + char Club[41]; + char readOutTime[32]; + bool PunchOnly; + bool convertedTime; + // Used for manual time input + int runnerId; + int relativeFinishTime; + bool statusOK; + bool statusDNF; + + vector codeLogData(int row) const; + static vector logHeader(); + + unsigned calculateHash() const; + bool isManualInput() const {return runnerId != 0;} + + string serializePunches() const; + void deserializePunches(const string &arg); +}; + +struct SI_StationData { + SI_StationData(); + + int stationNumber; + int stationMode; + bool extended; + bool handShake; + bool autoSend; + int radioChannel; +}; + +struct SI_StationInfo +{ + SI_StationInfo(); + HANDLE ThreadHandle; + string ComPort; + HANDLE hComm; + COMMTIMEOUTS TimeOuts; + + vector data; + + int stationMode() const { + if (data.empty()) + return 0; + else + return data[0].stationMode; + } + + bool extended() const { + if (data.empty()) + return false; + bool ext = true; + for (size_t k = 0; k < data.size(); k++) { + if (!data[k].extended) + ext = false; + } + return ext; + } + //Used for TCP ports + WORD tcpPort; + int localZeroTime; +}; + + +class SportIdent +{ +protected: + bool ReadSI6Block(HANDLE hComm, BYTE *data); + bool ReadSystemData(SI_StationInfo *si, int retry=2); + bool ReadSystemDataV2(SI_StationInfo &si); + CRITICAL_SECTION SyncObj; + + DWORD ZeroTime; //Used to analyse times. Seconds 0-24h (0-24*3600) + int ReadByte_delay(BYTE &byte, HANDLE hComm); + int ReadBytes_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm); + int ReadBytesDLE_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm); + + int ReadByte(BYTE &byte, HANDLE hComm); + int ReadBytes(BYTE *byte, DWORD len, HANDLE hComm); + int ReadBytesDLE(BYTE *byte, DWORD len, HANDLE hComm); + + // Returns zero on failure, number of bytes used on success. + int analyzeStation(BYTE *db, SI_StationData &si); + + SI_StationInfo SI_Info[32]; + int n_SI_Info; //Number of structures.. + SI_StationInfo *Current_SI_Info; //Current SI_Info in use (for thread startup); + + WORD CalcCRC(BYTE *data, DWORD length); + bool CheckCRC(BYTE *bf); + void SetCRC(BYTE *bf); + + bool GetCard5Data(BYTE *data, SICard &card); + bool GetCard6Data(BYTE *data, SICard &card); + bool GetCard9Data(BYTE *data, SICard &card); + + DWORD GetExtCardNumber(BYTE *data) const; + + void GetSI5Data(HANDLE hComm); + void GetSI5DataExt(HANDLE hComm); + + void GetSI6Data(HANDLE hComm); + void GetSI6DataExt(HANDLE hComm); + void GetSI9DataExt(HANDLE hComm); + + void AnalyseSI5Time(BYTE *data, DWORD &time, DWORD &control); + bool AnalysePunch(BYTE *data, DWORD &time, DWORD &control); + void AnalyseTPunch(BYTE *data, DWORD &time, DWORD &control); + + //Card read waiting to be processed. + list ReadCards; + HWND hWndNotify; + DWORD ClassId; + + volatile int tcpPortOpen; + volatile unsigned int serverSocket; + + bool MonitorSI(SI_StationInfo &si); + int MonitorTCPSI(WORD port, int localZeroTime); + +public: + SI_StationInfo *findStation(const string &com); + + void getInfoString(const string &com, vector &info); + bool IsPortOpen(const string &com); + void SetZeroTime(DWORD zt); + bool AutoDetect(list &ComPorts); + void StopMonitorThread(); + + void StartMonitorThread(const char *com); + bool GetCard(SICard &sic); + void addCard(const SICard &sic); + void AddPunch(DWORD Time, int Station, int Card, int Mode=0); + + + void EnumrateSerialPorts(list &ports); + + void CloseCom(const char *com); + bool OpenCom(const char *com); + bool tcpAddPort(int port, DWORD zeroTime); + + bool OpenComListen(const char *com, DWORD BaudRate); + + SportIdent(HWND hWnd, DWORD Id); + virtual ~SportIdent(); + friend void start_si_thread(void *ptr); + +}; + +#endif // !defined(AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_) diff --git a/code/StdAfx.cpp b/code/StdAfx.cpp new file mode 100644 index 0000000..a1655bc --- /dev/null +++ b/code/StdAfx.cpp @@ -0,0 +1,12 @@ +// stdafx.cpp : source file that includes just the standard includes +//meos.pch will be the pre-compiled header +//stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +const string _EmptyString=""; +const string _VacantName="Vakant"; +const string _UnkownName="N.N."; + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/code/StdAfx.h b/code/StdAfx.h new file mode 100644 index 0000000..431715c --- /dev/null +++ b/code/StdAfx.h @@ -0,0 +1,55 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) +#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define NOMINMAX +// Windows Header Files: +#include +#include + +// C RunTime Header Files + +#define _CRTDBG_MAP_ALLOC +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace std; +bool getUserFile(char *fileNamePath, const char *fileName); +bool getDesktopFile(char *fileNamePath, const char *fileName, const char *subFolder = 0); +bool getMeOSFile(char *FileNamePath, const char *FileName); + +class gdioutput; +gdioutput *createExtraWindow(const string &tag, const string &title, int max_x = 0, int max_y = 0); +gdioutput *getExtraWindow(const string &tag, bool toForeGround); +string uniqueTag(const char *base); + +void LoadPage(const string &name); + +string getTempFile(); +string getTempPath(); +void removeTempFile(const string &file); // Delete a temporyary +void registerTempFile(const string &tempFile); //Register a file/folder as temporary => autmatic removal on exit. + +const extern string _EmptyString; +const extern string _VacantName; +const extern string _UnkownName; + +#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/code/TabAuto.cpp b/code/TabAuto.cpp new file mode 100644 index 0000000..1ac1487 --- /dev/null +++ b/code/TabAuto.cpp @@ -0,0 +1,1142 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include "classconfiginfo.h" +#include "onlineresults.h" +#include "onlineinput.h" + +#include "TabAuto.h" +#include "TabSI.h" +#include "meos_util.h" +#include + +#include "gdiconstants.h" +#include "meosexception.h" + +static TabAuto *tabAuto = 0; +int AutoMachine::uniqueId = 1; + +extern HWND hWndMain; +extern HWND hWndWorkspace; + +TabAuto::TabAuto(oEvent *poe):TabBase(poe) +{ + synchronize=false; + synchronizePunches=false; +} + +AutoMachine *AutoMachine::getMachine(int id) { + if (tabAuto) + return tabAuto->getMachine(id); + throw meosException("Internal error"); +} + +AutoMachine* AutoMachine::construct(Machines ms) { + switch(ms) { + case mPrintResultsMachine: + return new PrintResultMachine(0); + case mSplitsMachine: + return new SplitsMachine(); + case mPrewarningMachine: + return new PrewarningMachine(); + case mPunchMachine: + return new PunchMachine(); + case mOnlineInput: + return new OnlineInput(); + case mOnlineResults: + return new OnlineResults(); + case mSaveBackup: + return new SaveMachine(); + } + throw meosException("Invalid machine"); +} + +AutoMachine *TabAuto::getMachine(int id) { + if (id == 0) + return 0; + list::iterator it; + for (it=machines.begin(); it!=machines.end(); ++it) { + if (*it != 0 && (*it)->getId() == id) { + return *it; + } + } + throw meosException("Service X not found.#" + itos(id)); +} + +TabAuto::~TabAuto(void) +{ + list::iterator it; + for (it=machines.begin(); it!=machines.end(); ++it) { + delete *it; + *it=0; + } + tabAuto=0; +} + + +void tabAutoKillMachines() +{ + if (tabAuto) + tabAuto->killMachines(); +} + +void tabAutoRegister(TabAuto *ta) +{ + tabAuto=ta; +} + +void tabAutoAddMachinge(const AutoMachine &am) +{ + if (tabAuto) { + tabAuto->addMachine(am); + } +} + +void tabForceSync(gdioutput &gdi, pEvent oe) +{ + if (tabAuto) + tabAuto->syncCallback(gdi); +} + +int AutomaticCB(gdioutput *gdi, int type, void *data) +{ + if (!tabAuto) + throw std::exception("tabAuto undefined."); + + switch(type){ + case GUI_BUTTON: { + //Make a copy + ButtonInfo bu=*static_cast(data); + return tabAuto->processButton(*gdi, bu); + } + case GUI_LISTBOX:{ + ListBoxInfo lbi=*static_cast(data); + return tabAuto->processListBox(*gdi, lbi); + } + } + return 0; +} + +void TabAuto::syncCallback(gdioutput &gdi) +{ + string msg; + try { + list::iterator it; + for (it=machines.begin(); it!=machines.end(); ++it) { + AutoMachine *am=*it; + if (am && am->synchronize && !am->isEditMode()) + am->process(gdi, oe, SyncDataUp); + } + } + catch(std::exception &ex) { + msg=ex.what(); + } + catch(...) { + msg="Ett okänt fel inträffade."; + } + if (!msg.empty()) { + gdi.alert(msg); + gdi.setWaitCursor(false); + } + +} + +void TabAuto::updateSyncInfo() +{ + list::iterator it; + synchronize=false; + synchronizePunches=false; + + for (it=machines.begin(); it!=machines.end(); ++it) { + AutoMachine *am=*it; + if (am){ + am->synchronize= am->synchronize || am->synchronizePunches; + synchronize=synchronize || am->synchronize; + synchronizePunches=synchronizePunches || am->synchronizePunches; + } + } +} + +void TabAuto::timerCallback(gdioutput &gdi) +{ + DWORD tc=GetTickCount(); + + list::iterator it; + bool reload=false; + + for (it=machines.begin(); it!=machines.end(); ++it) { + AutoMachine *am=*it; + if (am && am->interval && tc >= am->timeout && !am->isEditMode()) { + am->process(gdi, oe, SyncTimer); + setTimer(am); + reload=true; + } + } + + DWORD d=0; + if (reload && !editMode && gdi.getData("AutoPage", d) && d) + loadPage(gdi); + } + +void TabAuto::setTimer(AutoMachine *am) +{ + DWORD tc=GetTickCount(); + + if (am->interval>0) { + DWORD to=am->interval*1000+tc; + + if (tointerval=0; + } + + am->timeout=to; + } +} + +int TabAuto::processButton(gdioutput &gdi, const ButtonInfo &bu) +{ + + if (bu.id=="GenerateCMP") { +#ifndef MEOSDB + int nClass=gdi.getTextNo("nClass"); + int nRunner=gdi.getTextNo("nRunner"); + + if (nRunner>0 && + gdi.ask("Vill du dumpa aktuellt tävling och skapa en testtävling?")) { + oe->generateTestCompetition(nClass, nRunner, gdi.isChecked("UseRelay")); + gdi.getTabs().get(TCmpTab)->loadPage(gdi); + return 0; + } +#endif + } + else if (bu.id == "BrowseFolder") { + const char *edit = bu.getExtra(); + string currentPath = gdi.getText(edit); + string newPath = gdi.browseForFolder(currentPath, 0); + if (!newPath.empty()) + gdi.setText(edit, newPath); + } + else if (bu.id == "StartBackup") { + SaveMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + if (sm) + sm->saveSettings(gdi); + updateSyncInfo(); + loadPage(gdi); + } + else if (bu.id=="Result") { + PrintResultMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mPrintResultsMachine); + } + else if (bu.id == "BrowseFile") { + static int index = 0; + vector< pair > ext; + ext.push_back(make_pair("Webbdokument", "*.html;*.htm")); + + string file = gdi.browseForSave(ext, "html", index); + if (!file.empty()) + gdi.setText("ExportFile", file); + } + else if (bu.id == "BrowseScript") { + vector< pair > ext; + ext.push_back(make_pair("Skript", "*.bat;*.exe;*.js")); + + string file = gdi.browseForOpen(ext, "bat"); + if (!file.empty()) + gdi.setText("ExportScript", file); + } + else if (bu.id == "DoExport") { + bool stat = gdi.isChecked(bu.id); + gdi.setInputStatus("ExportFile", stat); + gdi.setInputStatus("ExportScript", stat); + gdi.setInputStatus("BrowseFile", stat); + gdi.setInputStatus("BrowseScript", stat); + gdi.setInputStatus("HTMLRefresh", stat); + gdi.setInputStatus("StructuredExport", stat); + } + else if (bu.id == "DoPrint") { + bool stat = gdi.isChecked(bu.id); + gdi.setInputStatus("PrinterSetup", stat); + } + else if (bu.id=="Splits") { + SplitsMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mSplitsMachine); + } + else if (bu.id=="Prewarning") { + PrewarningMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mPrewarningMachine); + } + else if (bu.id=="Punches") { + PunchMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mPunchMachine); + } + else if (bu.id=="OnlineResults") { + OnlineResults *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mOnlineResults); + } + else if (bu.id=="OnlineInput") { + OnlineInput *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mOnlineInput); + } + else if (bu.id=="SaveBackup") { + SaveMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + settings(gdi, sm, mSaveBackup); + } + else if (bu.id=="StartResult") { +#ifndef MEOSDB + string minute=gdi.getText("Interval"); + int t=convertAbsoluteTimeMS(minute); + + if (t<2 || t>7200) { + gdi.alert("Intervallet måste anges på formen MM:SS."); + } + else { + PrintResultMachine *prm=dynamic_cast(getMachine(bu.getExtraInt())); + + if (prm) { + prm->interval = t; + prm->doExport = gdi.isChecked("DoExport"); + prm->doPrint = gdi.isChecked("DoPrint"); + prm->exportFile = gdi.getText("ExportFile"); + prm->exportScript = gdi.getText("ExportScript"); + prm->structuredExport = gdi.isChecked("StructuredExport"); + prm->htmlRefresh = gdi.isChecked("HTMLRefresh") ? t : 0; + if (!prm->readOnly) { + gdi.getSelection("Classes", prm->classesToPrint); + + ListBoxInfo lbi; + if (gdi.getSelectedItem("ListType", lbi)) { + oListParam par; + par.selection=prm->classesToPrint; + par.listCode = EStdListType(lbi.data); + par.pageBreak = gdi.isChecked("PageBreak"); + par.showInterTimes = gdi.isChecked("ShowInterResults"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + int legNr = gdi.getSelectedItem("LegNumber").first; + if (legNr >= 0) + par.setLegNumberCoded(legNr); + else + par.setLegNumberCoded(0); + + oe->generateListInfo(par, gdi.getLineHeight(), prm->listInfo); + } + } + prm->po.onlyChanged = gdi.isChecked("OnlyChanged"); + prm->pageBreak = gdi.isChecked("PageBreak"); + prm->showInterResult = gdi.isChecked("ShowInterResults"); + prm->splitAnalysis = gdi.isChecked("SplitAnalysis"); + prm->synchronize=true; //To force continuos data sync. + setTimer(prm); + } + updateSyncInfo(); + loadPage(gdi); + } +#endif + } + else if (bu.id=="StartSplits") { + + string ivt = gdi.getText("Interval"); + + int iv = gdi.getTextNo("Interval"); + const string &file=gdi.getText("FileName"); + + if (!ivt.empty() && (iv < 1 || iv > 7200)) { + throw meosException("Ogiltigt antal sekunder: X#" + gdi.getText("Interval")); + } + + if (file.empty()) { + throw meosException("Filnamnet får inte vara tomt"); + } + + //Try exporting. + oe->exportIOFSplits(oEvent::IOF20, file.c_str(), true, false, + set(), -1, false, true, true, false); + SplitsMachine *sm=dynamic_cast(getMachine(bu.getExtraInt())); + + if (sm) { + sm->interval=iv; + + sm->file=file; + sm->synchronize=true; + setTimer(sm); + } + updateSyncInfo(); + loadPage(gdi); + } + else if (bu.id=="Save") { // General save + AutoMachine *sm=getMachine(bu.getExtraInt()); + if (sm) { + sm->save(*oe, gdi); + setTimer(sm); + } + updateSyncInfo(); + loadPage(gdi); + } + else if (bu.id=="StartPrewarning") { + PrewarningMachine *pwm=dynamic_cast(getMachine(bu.getExtraInt())); + + if (pwm) { + pwm->waveFolder=gdi.getText("WaveFolder"); + gdi.getSelection("Controls", pwm->controls); + + oe->synchronizeList(oLPunchId); + oe->clearPrewarningSounds(); + + pwm->synchronizePunches=true; + pwm->controlsSI.clear(); + for (set::iterator it=pwm->controls.begin();it!=pwm->controls.end();++it) { + pControl pc=oe->getControl(*it, false); + + if (pc) + pwm->controlsSI.insert(pc->Numbers, pc->Numbers+pc->nNumbers); + } + } + updateSyncInfo(); + loadPage(gdi); + } + else if (bu.id=="StartPunch") { + + string minute=gdi.getText("Interval"); + int t=atoi(minute.c_str()); + + if (t<1 || t>7200) { + throw meosException("Ogiltigt antal sekunder: X#" + minute); + } + else { + PunchMachine *pm=dynamic_cast(getMachine(bu.getExtraInt())); + + if (pm) { + pm->interval=t; + pm->radio=gdi.getTextNo("Radio"); + setTimer(pm); + } + } + updateSyncInfo(); + loadPage(gdi); + } + else if (bu.id == "Cancel") { + loadPage(gdi); + } + else if (bu.id == "Stop") { + if (bu.getExtraInt()) + stopMachine(getMachine(bu.getExtraInt())); + + updateSyncInfo(); + loadPage(gdi); + } + else if (bu.id == "PrinterSetup") { + PrintResultMachine *prm = + dynamic_cast(getMachine(bu.getExtraInt())); + + if (prm) { + gdi.printSetup(prm->po); + } + } + else if (bu.id == "PrintNow") { + PrintResultMachine *prm = + dynamic_cast(getMachine(bu.getExtraInt())); + + if (prm) { + prm->process(gdi, oe, SyncNone); + setTimer(prm); + loadPage(gdi); + } + } + else if (bu.id == "SelectAll") { + const char *ctrl = bu.getExtra(); + set lst; + lst.insert(-1); + gdi.setSelection(ctrl, lst); + } + else if (bu.id == "SelectNone") { + const char *ctrl= bu.getExtra(); + set lst; + gdi.setSelection(ctrl, lst); + } + else if (bu.id == "TestVoice") { + PrewarningMachine *pwm=dynamic_cast(getMachine(bu.getExtraInt())); + + if (pwm) + oe->tryPrewarningSounds(pwm->waveFolder, rand()%400+1); + } + else if ( bu.id == "WaveBrowse") { + string wf=gdi.browseForFolder(gdi.getText("WaveFolder"), 0); + + if (wf.length()>0) + gdi.setText("WaveFolder", wf); + } + else if ( bu.id == "BrowseSplits") { + int index=0; + vector< pair > ext; + ext.push_back(make_pair("Sträcktider", "*.xml")); + + string wf = gdi.browseForSave(ext, "xml", index); + + if (!wf.empty()) + gdi.setText("FileName", wf); + } + + return 0; +} + +int TabAuto::processListBox(gdioutput &gdi, const ListBoxInfo &bu) +{ + return 0; +} + +bool TabAuto::stopMachine(AutoMachine *am) +{ + list::iterator it; + for (it=machines.begin(); it!=machines.end(); ++it) + if (am==*it) { + if (am->stop()) { + delete am; + machines.erase(it); + return true; + } + } + return false; +} + +void TabAuto::settings(gdioutput &gdi, AutoMachine *sm, Machines ms) { + editMode=true; + bool createNew = (sm==0); + if (!sm) { + sm = AutoMachine::construct(ms); + machines.push_back(sm); + } + + gdi.restore("", false); + gdi.dropLine(); + int cx = gdi.getCX(); + int cy = gdi.getCY(); + int d = gdi.scaleLength(6); + gdi.setCX(cx + d); + sm->setEditMode(true); + sm->settings(gdi, *oe, createNew); + int w = gdi.getWidth(); + int h = gdi.getHeight(); + + RECT rc; + rc.top = cy - d; + rc.bottom = h + d; + rc.left = cx - d; + rc.right = w + d; + gdi.addRectangle(rc, colorLightBlue, true, true); + gdi.refresh(); +} + +void TabAuto::killMachines() +{ + while(!machines.empty()) { + machines.back()->stop(); + delete machines.back(); + machines.pop_back(); + } + AutoMachine::resetGlobalId(); +} + +bool TabAuto::loadPage(gdioutput &gdi) +{ + oe->checkDB(); + tabAuto=this; + editMode=false; + gdi.selectTab(tabId); + DWORD isAP = 0; + gdi.getData("AutoPage", isAP); + int storedOY = 0; + int storedOX = 0; + if (isAP) { + storedOY = gdi.GetOffsetY(); + storedOX = gdi.GetOffsetX(); + } + + gdi.clearPage(false); + gdi.setData("AutoPage", 1); + gdi.addString("", boldLarge, "Automater"); + gdi.setRestorePoint(); + + gdi.addString("", 10, "help:10000"); + + gdi.dropLine(); + gdi.addString("", fontMediumPlus, "Tillgängliga automater").setColor(colorDarkBlue); + gdi.dropLine(); + gdi.fillRight(); + gdi.pushX(); + gdi.addButton("Result", "Resultatutskrift / export", AutomaticCB, "tooltip:resultprint"); + gdi.addButton("OnlineResults", "Resultat online", AutomaticCB, "Publicera resultat direkt på nätet"); + gdi.addButton("OnlineInput", "Inmatning online", AutomaticCB, "Hämta stämplingar m.m. från nätet"); + gdi.popX(); + gdi.dropLine(2.5); + gdi.addButton("Splits", "Sträcktider (WinSplits)", AutomaticCB, "Spara sträcktider till en fil för automatisk synkronisering med WinSplits"); + gdi.addButton("Prewarning", "Förvarningsröst", AutomaticCB, "tooltip:voice"); + gdi.addButton("Punches", "Stämplingstest", AutomaticCB, "Simulera inläsning av stämplar"); + gdi.popX(); + gdi.dropLine(2.5); + gdi.addButton("SaveBackup", "Säkerhetskopiering", AutomaticCB); + + gdi.fillDown(); + gdi.dropLine(3); + gdi.popX(); + + if (!machines.empty()) { + gdi.addString("", fontMediumPlus, "Startade automater").setColor(colorDarkBlue);; + list::iterator it; + + int baseX = gdi.getCX(); + int dx = gdi.scaleLength(6); + + for (it=machines.begin(); it!=machines.end(); ++it) { + AutoMachine *am=*it; + if (am) { + RECT rc; + rc.left = baseX; + rc.right = gdi.scaleLength(500); + rc.top = gdi.getCY(); + gdi.dropLine(0.5); + gdi.setCX(baseX+dx); + am->setEditMode(false); + am->status(gdi); + gdi.setCX(baseX); + gdi.dropLine(0.5); + rc.bottom = gdi.getCY(); + gdi.addRectangle(rc, colorLightGreen, true, true); + gdi.dropLine(); + } + } + gdi.dropLine(); + } + + if (isAP) { + gdi.setOffset(storedOY, storedOY, true); + } + + gdi.refresh(); + return true; +} + +void AutoMachine::settingsTitle(gdioutput &gdi, char *title) { + gdi.dropLine(0.5); + gdi.addString("", fontMediumPlus, title).setColor(colorDarkBlue); + gdi.dropLine(0.5); +} + +void AutoMachine::startCancelInterval(gdioutput &gdi, char *startCommand, bool created, IntervalType type, const string &interval) { + gdi.pushX(); + gdi.fillRight(); + if (type == IntervalMinute) + gdi.addInput("Interval", interval, 7, 0, "Tidsintervall (MM:SS):"); + else if (type == IntervalSecond) + gdi.addInput("Interval", interval, 7, 0, "Tidsintervall (sekunder):"); + gdi.dropLine(1); + gdi.addButton(startCommand, "Starta automaten", AutomaticCB).setExtra(getId()); + gdi.addButton(created ? "Stop":"Cancel", "Avbryt", AutomaticCB).setExtra(getId()); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2.5); + int dx = gdi.scaleLength(3); + RECT rc; + rc.left = gdi.getCX() - dx; + rc.right = rc.left + gdi.scaleLength(450); + rc.top = gdi.getCY(); + rc.bottom = rc.top + dx; + gdi.addRectangle(rc, colorDarkBlue, false, false); + gdi.dropLine(); +} + + +void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, bool created) { + settingsTitle(gdi, "Resultatutskrift / export"); + string time=created ? "10:00" : getTimeMS(interval); + startCancelInterval(gdi, "StartResult", created, IntervalMinute, time); + + if (created) { + oe.getAllClasses(classesToPrint); + } + + gdi.pushX(); + gdi.fillRight(); + gdi.addCheckbox("DoPrint", "Skriv ut", AutomaticCB, doPrint); + gdi.dropLine(-0.5); + gdi.addButton("PrinterSetup", "Skrivare...", AutomaticCB, "Välj skrivare...").setExtra(getId()); + + gdi.dropLine(4); + gdi.popX(); + gdi.addCheckbox("DoExport", "Exportera", AutomaticCB, doExport); + gdi.dropLine(-1); + int cx = gdi.getCX(); + gdi.addInput("ExportFile", exportFile, 32, 0, "Fil att exportera till:"); + gdi.dropLine(0.7); + gdi.addButton("BrowseFile", "Bläddra...", AutomaticCB); + gdi.setCX(cx); + gdi.dropLine(2.3); + gdi.addCheckbox("StructuredExport", "Strukturerat exportformat", 0, structuredExport); + gdi.addCheckbox("HTMLRefresh", "HTML med AutoRefresh", 0, htmlRefresh != 0); + gdi.dropLine(1.2); + gdi.setCX(cx); + gdi.addInput("ExportScript", exportScript, 32, 0, "Skript att köra efter export:"); + gdi.dropLine(0.7); + gdi.addButton("BrowseScript", "Bläddra...", AutomaticCB); + gdi.dropLine(3); + gdi.popX(); + + gdi.setInputStatus("ExportFile", doExport); + gdi.setInputStatus("ExportScript", doExport); + gdi.setInputStatus("BrowseFile", doExport); + gdi.setInputStatus("BrowseScript", doExport); + gdi.setInputStatus("StructuredExport", doExport); + gdi.setInputStatus("HTMLRefresh", doExport); + gdi.setInputStatus("PrinterSetup", doPrint); + + if (!readOnly) { + gdi.fillDown(); + gdi.addString("", 1, "Listval"); + gdi.dropLine(); + gdi.fillRight(); + gdi.addListBox("Classes", 150,300,0,"","", true); + gdi.pushX(); + gdi.fillDown(); + vector< pair > d; + gdi.addItem("Classes", oe.fillClasses(d, oEvent::extraNone, oEvent::filterNone)); + gdi.setSelection("Classes", classesToPrint); + + gdi.addSelection("ListType", 200, 100, 0, "Lista"); + oe.fillListTypes(gdi, "ListType", 1); + if (notShown) { + notShown = false; + ClassConfigInfo cnf; + oe.getClassConfigurationInfo(cnf); + int type = EStdResultListLARGE; + if (cnf.hasRelay()) + type = EStdTeamAllLegLARGE; + else if (cnf.hasPatrol()) + type = EStdPatrolResultListLARGE; + + gdi.selectItemByData("ListType", type); + } + else + gdi.selectItemByData("ListType", listInfo.getListCode()); + + gdi.addSelection("LegNumber", 140, 300, 0, "Sträcka:"); + set clsUnused; + vector< pair > out; + oe.fillLegNumbers(clsUnused, listInfo.isTeamList(), true, out); + gdi.addItem("LegNumber", out); + gdi.selectItemByData("LegNumber", listInfo.getLegNumberCoded()); + + gdi.addCheckbox("PageBreak", "Sidbrytning mellan klasser", 0, pageBreak); + gdi.addCheckbox("ShowInterResults", "Visa mellantider", 0, showInterResult, + "Mellantider visas för namngivna kontroller."); + gdi.addCheckbox("SplitAnalysis", "Med sträcktidsanalys", 0, splitAnalysis); + + gdi.addCheckbox("OnlyChanged", "Skriv endast ut ändade sidor", 0, po.onlyChanged); + + gdi.popX(); + gdi.addButton("SelectAll", "Välj allt", AutomaticCB, "").setExtra("Classes"); + gdi.popX(); + gdi.addButton("SelectNone", "Välj inget", AutomaticCB, "").setExtra("Classes"); + } + else { + gdi.fillDown(); + gdi.addString("", 1, "Lista av typ 'X'#" + listInfo.getName()); + gdi.addCheckbox("OnlyChanged", "Skriv endast ut ändade sidor", 0, po.onlyChanged); + } +} + +void PrintResultMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) +{ + if (lock) + return; + + if (ast!=SyncDataUp) { + string printError; + lock = true; + try { + gdioutput gdiPrint("print", gdi.getScale(), gdi.getEncoding()); + gdiPrint.clearPage(false); + oe->generateList(gdiPrint, true, listInfo, false); + if (doPrint) { + gdiPrint.refresh(); + try { + gdiPrint.print(po, oe); + } + catch (const meosException &ex) { + printError = ex.what(); + if (printError.empty()) + printError = "Printing failed (X: Y) Z#Auto#0#Unknown"; + } + } + if (doExport) { + if (!exportFile.empty()) { + if (structuredExport) + gdiPrint.writeTableHTML(gdi.toWide(exportFile), oe->getName(), htmlRefresh); + else + gdiPrint.writeHTML(gdi.toWide(exportFile), oe->getName(), htmlRefresh); + + if (!exportScript.empty()) { + ShellExecute(NULL, NULL, exportScript.c_str(), exportFile.c_str(), NULL, SW_HIDE); + } + } + } + } + catch (...) { + lock = false; + throw; + } + lock = false; + + if (!printError.empty() && !errorLock) { + errorLock = true; + gdi.alert(printError); + errorLock = false; + } + } +} + +void PrintResultMachine::status(gdioutput &gdi) +{ + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 0, name); + gdi.addString("", 0, listInfo.getName()); + gdi.dropLine(); + if (doExport) { + gdi.popX(); + gdi.addString("", 0, "Målfil: "); + gdi.addStringUT(0, exportFile).setColor(colorRed); + gdi.dropLine(); + } + gdi.fillRight(); + gdi.popX(); + if (interval>0){ + gdi.addString("", 0, "Automatisk utskrift / export: "); + gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign, (GetTickCount()-timeout)/1000); + } + else { + + } + gdi.popX(); + gdi.dropLine(2); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.addButton("PrintNow", "Exportera nu", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("Result", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void PrewarningMachine::settings(gdioutput &gdi, oEvent &oe, bool created) { + settingsTitle(gdi, "Förvarningsröst"); + startCancelInterval(gdi, "StartPrewarning", created, IntervalNone, ""); + + gdi.addString("", 10, "help:computer_voice"); + + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("WaveFolder", waveFolder, 32, 0, "Ljudfiler, baskatalog."); + + gdi.fillDown(); + gdi.dropLine(); + gdi.addButton("WaveBrowse", "Bläddra...", AutomaticCB); + gdi.popX(); + + gdi.addListBox("Controls", 100, 200, 0, "", "", true); + gdi.pushX(); + gdi.fillDown(); + vector< pair > d; + oe.fillControls(d, oEvent::CTCourseControl); + gdi.addItem("Controls", d); + gdi.setSelection("Controls", controls); + gdi.popX(); + gdi.addButton("SelectAll", "Välj alla", AutomaticCB, "").setExtra("Controls"); + gdi.popX(); +} + +void PrewarningMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) +{ + oe->playPrewarningSounds(waveFolder, controlsSI); +} + +void PrewarningMachine::status(gdioutput &gdi) +{ + gdi.addString("", 1, name); + + string info="Förvarning på (SI-kod): "; + bool first=true; + + if (controls.empty()) + info+="alla stämplingar"; + else { + for (set::iterator it=controlsSI.begin();it!=controlsSI.end();++it) { + char bf[32]; + _itoa_s(*it, bf, 10); + + if (!first) info+=", "; + else first=false; + + info+=bf; + } + } + gdi.addString("", 0, info); + gdi.fillRight(); + gdi.pushX(); + + gdi.popX(); + gdi.dropLine(0.3); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.addButton("TestVoice", "Testa rösten", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("Prewarning", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void PunchMachine::settings(gdioutput &gdi, oEvent &oe, bool created) { + settingsTitle(gdi, "Test av stämplingsinläsningar"); + string time=created ? "10" : itos(interval); + startCancelInterval(gdi, "StartPunch", created, IntervalSecond, time); + + gdi.addString("", 10, "help:simulate"); + + gdi.pushX(); + gdi.fillRight(); + gdi.dropLine(); + + gdi.addString("", 0, "Radiotider, kontroll:"); + gdi.dropLine(-0.2); + gdi.addInput("Radio", "", 6, 0); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(5); + gdi.addString("", 1, "Generera testtävling"); + gdi.fillRight(); + gdi.addInput("nRunner", "100", 10, 0, "Antal löpare"); + gdi.addInput("nClass", "10", 10, 0, "Antal klasser"); + gdi.dropLine(); + gdi.addCheckbox("UseRelay", "Med stafettklasser"); + gdi.addButton("GenerateCMP", "Generera testtävling", AutomaticCB); +} + +void PunchMachine::status(gdioutput &gdi) +{ + gdi.addString("", 1, name); + gdi.fillRight(); + gdi.pushX(); + if (interval>0){ + gdi.addString("", 0, "Stämplar om: "); + gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign|timeSeconds, (GetTickCount()-timeout)/1000); + gdi.addString("", 0, "(sekunder)"); + } + else { + + } + gdi.popX(); + gdi.dropLine(2); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("Punches", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) +{ +#ifndef MEOSDB + SICard sic; + oe->generateTestCard(sic); + SportIdent &si = TabSI::getSI(gdi); + if (!sic.empty()) { + if (!radio) si.addCard(sic); + } + else gdi.addInfoBox("", "Failed to generate card.", interval*2); + + if (radio && !sic.empty()) { + pRunner r=oe->getRunnerByCardNo(sic.CardNumber, 0, false); + if (r && r->getCardNo()) { + sic.CardNumber=r->getCardNo(); + sic.PunchOnly=true; + sic.nPunch=1; + sic.Punch[0].Code=radio; + si.addCard(sic); + } + } +#endif +} + +void SplitsMachine::settings(gdioutput &gdi, oEvent &oe, bool created) { + string time = ""; + if (interval>0) + time = itos(interval); + else if (created) + time = "30"; + + settingsTitle(gdi, "Sträcktider / WinSplits"); + startCancelInterval(gdi, "StartSplits", created, IntervalSecond, time); + + gdi.addString("", 0, "Intervall (sekunder). Lämna blankt för att uppdatera när " + "tävlingsdata ändras."); + gdi.dropLine(); + + gdi.addString("", 10, "help:winsplits_auto"); + + + gdi.dropLine(); + gdi.fillRight(); + gdi.addInput("FileName", file, 30, 0, "Filnamn:"); + gdi.dropLine(0.9); + gdi.addButton("BrowseSplits", "Bläddra...", AutomaticCB); + + gdi.popX(); + gdi.dropLine(2); + +} + +void SplitsMachine::status(gdioutput &gdi) +{ + gdi.addString("", 1, name); + if (!file.empty()) { + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 0, "Fil: X#" + file); + + if (interval>0){ + gdi.popX(); + gdi.dropLine(1); + gdi.addString("", 0, "Skriver sträcktider om: "); + gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign|timeSeconds, (GetTickCount()-timeout)/1000); + gdi.addString("", 0, "(sekunder)"); + } + else { + gdi.dropLine(1); + gdi.addString("", 0, "Skriver sträcktider när tävlingsdata ändras."); + } + + gdi.popX(); + } + gdi.dropLine(2); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("Splits", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void SplitsMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) +{ + if ((interval>0 && ast==SyncTimer) || (interval==0 && ast==SyncDataUp)) { + if (!file.empty()) + oe->exportIOFSplits(oEvent::IOF20, file.c_str(), true, false, classes, + leg, false, true, true, false); + } +} + +void SaveMachine::status(gdioutput &gdi) { + gdi.addString("", 1, name); + if (!baseFile.empty()) { + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 0, "Destination: X#" + baseFile); + + if (interval>0){ + gdi.popX(); + gdi.dropLine(1); + gdi.addString("", 0, "Säkerhetskopierar om: "); + gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign, (GetTickCount()-timeout)/1000); + } + + gdi.popX(); + } + gdi.dropLine(2); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("SaveBackup", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void SaveMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) { + if (interval>0 && ast==SyncTimer) { + if (!baseFile.empty()) { + string file = baseFile + "meos_backup_" + oe->getDate() + "_" + itos(saveIter++) + ".xml"; + oe->autoSynchronizeLists(true); + oe->save(file); + } + } +} + +void SaveMachine::settings(gdioutput &gdi, oEvent &oe, bool created) { + settingsTitle(gdi, "Säkerhetskopiering"); + string time=created ? "10:00" : getTimeMS(interval); + startCancelInterval(gdi, "StartBackup", created, IntervalMinute, time); + + int cx = gdi.getCX(); + gdi.addInput("BaseFile", baseFile, 32, 0, "Mapp:"); + gdi.dropLine(0.7); + gdi.addButton("BrowseFolder", "Bläddra...", AutomaticCB).setExtra("BaseFile"); + gdi.setCX(cx); +} + +void SaveMachine::saveSettings(gdioutput &gdi) { + + string minute=gdi.getText("Interval"); + int t=convertAbsoluteTimeMS(minute); + + if (t<2 || t>7200) { + throw meosException("Intervallet måste anges på formen MM:SS."); + } + string f = gdi.getText("BaseFile"); + if (f.empty()) { + throw meosException("Filnamnet får inte vara tomt"); + } + + if (*f.rbegin() != '\\' && *f.rbegin() != '/') + f += "\\"; + + string sample = f + "sample.txt"; + ofstream fout(sample.c_str(), ios_base::trunc|ios_base::out); + bool bad = false; + if (fout.bad()) + bad = true; + else { + fout << "foo" << endl; + fout.close(); + bad = fout.bad(); + remove(sample.c_str()); + } + if (bad) + throw meosException("Ogiltig destination X#" + f); + + baseFile = f; + interval = t; +} + +void TabAuto::clearCompetitionData() { +} diff --git a/code/TabAuto.h b/code/TabAuto.h new file mode 100644 index 0000000..bd94288 --- /dev/null +++ b/code/TabAuto.h @@ -0,0 +1,287 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "tabbase.h" +#include "gdioutput.h" +#include "Printer.h" +#include +#include "oListInfo.h" + +using namespace std; + +class TabAuto; +class gdioutput; +class oEvent; + +enum AutoSyncType {SyncNone, SyncTimer, SyncDataUp}; + +enum Machines { + mPunchMachine, + mPrintResultsMachine, + mSplitsMachine, + mPrewarningMachine, + mOnlineResults, + mOnlineInput, + mSaveBackup, +}; + +class AutoMachine +{ +private: + int myid; + static int uniqueId; +protected: + bool editMode; + + void settingsTitle(gdioutput &gdi, char *title); + enum IntervalType {IntervalNone, IntervalMinute, IntervalSecond}; + void startCancelInterval(gdioutput &gdi, char *startCommand, bool created, IntervalType type, const string &interval); + +public: + static AutoMachine *getMachine(int id); + static void resetGlobalId() {uniqueId = 1;} + int getId() const {return myid;} + static AutoMachine* construct(Machines); + void setEditMode(bool em) {editMode = em;} + string name; + DWORD interval; //Interval seconds + DWORD timeout; //Timeout (TickCount) + bool synchronize; + bool synchronizePunches; + virtual void settings(gdioutput &gdi, oEvent &oe, bool created) = 0; + virtual void save(oEvent &oe, gdioutput &gdi) {} + virtual void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) = 0; + virtual bool isEditMode() const {return editMode;} + virtual void status(gdioutput &gdi) = 0; + virtual bool stop() {return true;} + virtual AutoMachine *clone() const = 0; + AutoMachine(const string &s) : myid(uniqueId++), name(s), interval(0), timeout(0), + synchronize(false), synchronizePunches(false), editMode(false) {} + virtual ~AutoMachine() = 0 {} +}; + +class PrintResultMachine : + public AutoMachine +{ +protected: + string exportFile; + string exportScript; + bool doExport; + bool doPrint; + bool structuredExport; + PrinterObject po; + set classesToPrint; + bool pageBreak; + bool showInterResult; + bool splitAnalysis; + bool notShown; + oListInfo listInfo; + bool readOnly; + int htmlRefresh; + bool lock; // true while printing + bool errorLock; // true while showing error dialog +public: + PrintResultMachine *clone() const { + PrintResultMachine *prm = new PrintResultMachine(*this); + prm->lock = false; + prm->errorLock = false; + return prm; + } + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + void settings(gdioutput &gdi, oEvent &oe, bool created); + + PrintResultMachine(int v):AutoMachine("Resultatutskrift") { + interval=v; + pageBreak = true; + showInterResult = true; + notShown = true; + splitAnalysis = true; + lock = false; + errorLock = false; + readOnly = false; + doExport = false; + doPrint = true; + structuredExport = true; + htmlRefresh = v; + } + PrintResultMachine(int v, const oListInfo &li):AutoMachine("Utskrift / export"), listInfo(li) { + interval=v; + pageBreak = true; + showInterResult = true; + notShown = true; + splitAnalysis = true; + lock = false; + errorLock = false; + readOnly = true; + doExport = false; + doPrint = true; + structuredExport = false; + htmlRefresh = v; + } + friend class TabAuto; +}; + +class SaveMachine : + public AutoMachine +{ +protected: + string baseFile; + int saveIter; +public: + SaveMachine *clone() const { + SaveMachine *prm = new SaveMachine(*this); + return prm; + } + + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + void settings(gdioutput &gdi, oEvent &oe, bool created); + void saveSettings(gdioutput &gdi); + + SaveMachine():AutoMachine("Säkerhetskopiera") , saveIter(0) { + } +}; + + +class PrewarningMachine : + public AutoMachine +{ +protected: + string waveFolder; + set controls; + set controlsSI; +public: + void settings(gdioutput &gdi, oEvent &oe, bool created); + PrewarningMachine *clone() const {return new PrewarningMachine(*this);} + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + PrewarningMachine():AutoMachine("Förvarningsröst") {} + friend class TabAuto; +}; + +class MySQLReconnect : + public AutoMachine +{ +protected: + string error; + string timeError; + string timeReconnect; + HANDLE hThread; +public: + void settings(gdioutput &gdi, oEvent &oe, bool created); + MySQLReconnect *clone() const {return new MySQLReconnect(*this);} + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + bool stop(); + MySQLReconnect(const string &error); + virtual ~MySQLReconnect(); + friend class TabAuto; +}; + +bool isThreadReconnecting(); + +class PunchMachine : + public AutoMachine +{ +protected: + int radio; +public: + PunchMachine *clone() const {return new PunchMachine(*this);} + void settings(gdioutput &gdi, oEvent &oe, bool created); + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + PunchMachine():AutoMachine("Stämplingsautomat"), radio(0) {} + friend class TabAuto; +}; + +class SplitsMachine : + public AutoMachine +{ +protected: + string file; + set classes; + int leg; +public: + SplitsMachine *clone() const {return new SplitsMachine(*this);} + void settings(gdioutput &gdi, oEvent &oe, bool created); + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + SplitsMachine() : AutoMachine("Sträcktider/WinSplits"), leg(-1) {} + friend class TabAuto; +}; + + + +class TabAuto : + public TabBase +{ +private: + //DWORD printResultIntervalSec; + //DWORD printResultTimeOut; + bool editMode; + + bool synchronize; + bool synchronizePunches; + void updateSyncInfo(); + + list machines; + void setTimer(AutoMachine *am); + + void timerCallback(gdioutput &gdi); + void syncCallback(gdioutput &gdi); + + void settings(gdioutput &gdi, AutoMachine *sm, Machines type); + +protected: + void clearCompetitionData(); + +public: + + AutoMachine *getMachine(int id); + //AutoMachine *getMachine(const string &name); + bool stopMachine(AutoMachine *am); + void killMachines(); + void addMachine(const AutoMachine &am) { + machines.push_back(am.clone()); + setTimer(machines.back()); + } + + int processButton(gdioutput &gdi, const ButtonInfo &bu); + int processListBox(gdioutput &gdi, const ListBoxInfo &bu); + + bool loadPage(gdioutput &gdi); + + const char * getTypeStr() const {return "TAutoTab";} + TabType getType() const {return TAutoTab;} + + TabAuto(oEvent *poe); + ~TabAuto(void); + + friend class AutoTask; + friend void tabForceSync(gdioutput &gdi, pEvent oe); +}; + +void tabAutoKillMachines(); +void tabAutoRegister(TabAuto *ta); +void tabAutoAddMachinge(const AutoMachine &am); diff --git a/code/TabBase.cpp b/code/TabBase.cpp new file mode 100644 index 0000000..8170b83 --- /dev/null +++ b/code/TabBase.cpp @@ -0,0 +1,211 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "TabBase.h" + +#include "oEvent.h" + +#include "TabRunner.h" +#include "TabTeam.h" +#include "TabList.h" +#include "TabSpeaker.h" +#include "TabClass.h" +#include "TabCourse.h" +#include "TabControl.h" +#include "TabClub.h" +#include "TabSI.h" +#include "TabCompetition.h" +#include "TabAuto.h" + +extern oEvent *gEvent; + +FixedTabs::FixedTabs() { + runnerTab = 0; + teamTab = 0; + classTab = 0; + courseTab = 0; + controlTab = 0; + siTab = 0; + listTab = 0; + cmpTab = 0; + speakerTab = 0; + clubTab = 0; + autoTab = 0; + } + +FixedTabs::~FixedTabs() { + tabs.clear(); + + delete runnerTab; + runnerTab = 0; + + delete teamTab; + teamTab = 0; + + delete classTab; + classTab = 0; + + delete courseTab; + courseTab = 0; + + delete controlTab; + controlTab = 0; + + delete siTab; + siTab = 0; + + delete listTab; + listTab = 0; + + delete cmpTab; + cmpTab = 0; + + delete speakerTab; + speakerTab = 0; + + delete clubTab; + clubTab = 0; + + delete autoTab; + autoTab = 0; +} + +TabBase *FixedTabs::get(const TabType tab) { + switch(tab) { + case TCmpTab: + if (!cmpTab) { + cmpTab = new TabCompetition(gEvent); + tabs.push_back(cmpTab); + } + return cmpTab; + break; + case TRunnerTab: + if (!runnerTab) { + runnerTab = new TabRunner(gEvent); + tabs.push_back(runnerTab); + } + return runnerTab; + break; + case TTeamTab: + if (!teamTab) { + teamTab = new TabTeam(gEvent); + tabs.push_back(teamTab); + } + return teamTab; + break; + + case TListTab: + if (!listTab) { + listTab = new TabList(gEvent); + tabs.push_back(listTab); + } + return listTab; + break; + + case TClassTab: + if (!classTab) { + classTab = new TabClass(gEvent); + tabs.push_back(classTab); + } + return classTab; + break; + + case TCourseTab: + if (!courseTab) { + courseTab = new TabCourse(gEvent); + tabs.push_back(courseTab); + } + return courseTab; + break; + + case TControlTab: + if (!controlTab) { + controlTab = new TabControl(gEvent); + tabs.push_back(controlTab); + } + return controlTab; + break; + + case TClubTab: + if (!clubTab) { + clubTab = new TabClub(gEvent); + tabs.push_back(clubTab); + } + return clubTab; + break; + + case TSpeakerTab: + if (!speakerTab) { + speakerTab = new TabSpeaker(gEvent); + tabs.push_back(speakerTab); + } + return speakerTab; + break; + + case TSITab: + if (!siTab) { + siTab = new TabSI(gEvent); + tabs.push_back(siTab); + } + return siTab; + break; + + case TAutoTab: + if (!autoTab) { + autoTab = new TabAuto(gEvent); + tabs.push_back(autoTab); + } + return autoTab; + break; + + default: + throw new std::exception("Bad tab type"); + } + + return 0; +} + +void FixedTabs::clearCompetitionData() { + for (size_t k = 0; k < tabs.size(); k++) + tabs[k]->clearCompetitionData(); +} + + +TabObject::TabObject(TabBase *t) +{ + tab = t; + tab->tabId = id; +} + +TabObject::~TabObject() +{ + //delete tab; +} + + +bool TabObject::loadPage(gdioutput &gdi) +{ + if (tab) + return tab->loadPage(gdi); + else return false; +} \ No newline at end of file diff --git a/code/TabBase.h b/code/TabBase.h new file mode 100644 index 0000000..ff5d658 --- /dev/null +++ b/code/TabBase.h @@ -0,0 +1,156 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "Localizer.h" +#include +#include "gdioutput.h" + + +class oBase; +class oRunner; +typedef oRunner * pRunner; + +class oTeam; +typedef oTeam * pTeam; + +class gdioutput; +class oEvent; + +enum TabType { + TRunnerTab, + TTeamTab, + TClassTab, + TCourseTab, + TControlTab, + TSITab, + TListTab, + TCmpTab, + TSpeakerTab, + TClubTab, + TAutoTab, +}; + +class TabBase +{ +protected: + oEvent *oe; + int tabId; + virtual void clearCompetitionData() = 0; + +public: + oEvent *getEvent() const {return oe;} + int getTabId() const {return tabId;} + virtual bool loadPage(gdioutput &gdi) = 0; + + virtual TabType getType() const = 0; + virtual const char *getTypeStr() const = 0; + + TabBase(oEvent *poe) : oe(poe), tabId(0) {} + virtual ~TabBase()=0 {} + friend class TabObject; + friend class FixedTabs; +}; + + +class TabObject +{ +protected: + mutable TabBase *tab; + +public: + string name; + int id; + + TabObject(TabBase *t, string n):name(n),tab(t) {} + + void setId(int i){id=i; if (tab) tab->tabId=id;} + void setPage(TabBase *tb){delete tab; tab=tb;} + + const type_info &getType() const {return typeid(*tab);} + const TabBase &getTab() const {return *tab;} + TabObject(const TabObject &t) + { + if (&t!=this) { + name=t.name; + id=t.id; + tab=t.tab; + //t.tab=0; + } + } + + TabObject &operator=(TabObject &t) + { + if (&t!=this) { + delete tab; + name=t.name; + id=t.id; + tab=t.tab; + //t.tab=0; + } + } + + TabObject(TabBase *t); + ~TabObject(); + + bool loadPage(gdioutput &gdi); +}; + +class TabRunner; +class TabTeam; +class TabClass; +class TabCourse; +class TabControl; +class TabClub; +class TabSI; +class TabList; +class TabCompetition; +class TabSpeaker; +class TabAuto; + +class FixedTabs { + oEvent *oe; + TabRunner *runnerTab; + TabTeam *teamTab; + TabClass *classTab; + TabCourse *courseTab; + TabControl *controlTab; + TabSI *siTab; + TabList *listTab; + TabCompetition *cmpTab; + TabSpeaker *speakerTab; + TabClub *clubTab; + TabAuto *autoTab; + + vector tabs; +public: + + TabBase *get(TabType tag); + const vector &getActiveTabs() const {return tabs;} + // Clean up competition specific data from user interface + void clearCompetitionData(); + + + FixedTabs(); + ~FixedTabs(); +}; + diff --git a/code/TabClass.cpp b/code/TabClass.cpp new file mode 100644 index 0000000..48f2bcb --- /dev/null +++ b/code/TabClass.cpp @@ -0,0 +1,3930 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include + +#include "resource.h" + +#include +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include "meos_util.h" +#include "oListInfo.h" +#include "TabClass.h" +#include "ClassConfigInfo.h" +#include "meosException.h" +#include "gdifonts.h" +#include "oEventDraw.h" +#include "MeOSFeatures.h" + +extern pEvent gEvent; +const char *visualDrawWindow = "visualdraw"; + +TabClass::TabClass(oEvent *poe):TabBase(poe) +{ + handleCloseWindow.tabClass = this; + clearCompetitionData(); +} + +void TabClass::clearCompetitionData() { + pSettings.clear(); + pSavedDepth = 3600; + pFirstRestart = 3600; + pTimeScaling = 1.0; + pInterval = 120; + + currentStage = -1; + EditChanged = false; + ClassId=0; + tableMode = false; + showForkingGuide = false; + storedNStage = "3"; + storedStart = ""; + storedPredefined = oEvent::PredefinedTypes(-1); + cInfoCache.clear(); + hasWarnedDirect = false; + + lastSeedMethod = -1; + lastSeedPreventClubNb = true; + lastSeedReverse = false; + lastSeedGroups = "1"; + lastPairSize = 1; + lastFirstStart = ""; + lastInterval = "2:00"; + lastNumVac = "0"; + lastHandleBibs = false; + lastScaleFactor = "1.0"; + lastMaxAfter = "60:00"; + + gdioutput *gdi = getExtraWindow(visualDrawWindow, false); + if (gdi) { + gdi->closeWindow(); + } +} + +TabClass::~TabClass(void) +{ +} + +bool ClassInfoSortStart(ClassInfo &ci1, ClassInfo &ci2) +{ + return ci1.firstStart>ci2.firstStart; +} + +void TabClass::HandleCloseWindow::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) { + if (type == GUI_EVENT) { + EventInfo &ei = dynamic_cast(info); + if (ei.id == "CloseWindow") { + tabClass->closeWindow(gdi); + } + } +} + +void TabClass::closeWindow(gdioutput &gdi) { +} + +int ClassesCB(gdioutput *gdi, int type, void *data) +{ + TabClass &tc = dynamic_cast(*gdi->getTabs().get(TClassTab)); + return tc.classCB(*gdi, type, data); +} + +int MultiCB(gdioutput *gdi, int type, void *data) +{ + TabClass &tc = dynamic_cast(*gdi->getTabs().get(TClassTab)); + return tc.multiCB(*gdi, type, data); +} + +int DrawClassesCB(gdioutput *gdi, int type, void *data) +{ + TabClass &tc = dynamic_cast(*gdi->getTabs().get(TClassTab)); + + if (type == GUI_LISTBOX) { + tc.enableLoadSettings(*gdi); + } + else if (type == GUI_INPUT || type == GUI_INPUTCHANGE) { + InputInfo &ii = *(InputInfo *)data; + if (ii.id.length() > 1) { + int id = atoi(ii.id.substr(1).c_str()); + if (id > 0 && ii.changed()) { + string key = "C" + itos(id); + TextInfo &ti = dynamic_cast(gdi->getBaseInfo(key.c_str())); + ti.setColor(colorRed); + gdi->enableInput("DrawAdjust"); + gdi->refreshFast(); + } + } + } + return 0; +} + + +int TabClass::multiCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="ChangeLeg") { + gdi.dropLine(); + legSetup(gdi); + gdi.refresh(); + } + else if (bi.id == "CommonStart") { + gdi.setInputStatus("CommonStartTime", gdi.isChecked(bi.id)); + } + else if (bi.id == "CoursePool") { + string strId = "StageCourses_expl"; + gdi.setTextTranslate(strId, getCourseLabel(gdi.isChecked(bi.id)), true); + } + else if (bi.id == "DefineForking") { + if (!checkClassSelected(gdi)) + return false; + save(gdi, true); + EditChanged=true; + defineForking(gdi, true); + return true; + } + else if (bi.id == "ApplyForking") { + showForkingGuide = false; + pClass pc = oe->getClass(ClassId); + + vector allR; + oe->getRunners(ClassId, 0, allR, false); + bool doClear = false; + for (size_t k = 0; k < allR.size(); k++) { + if (allR[k]->getCourseId() != 0) { + if (!doClear) { + if (gdi.ask("Vill du nollställa alla manuellt tilldelade banor?")) + doClear = true; + else + break; + } + if (doClear) + allR[k]->setCourseId(0); + } + } + pair res = pc->autoForking(forkingSetup); + gdi.alert("Created X distinct forkings using Y courses.#" + + itos(res.first) + "#" + itos(res.second)); + loadPage(gdi); + EditChanged=true; + } + else if (bi.id == "AssignCourses") { + set selectedCourses, selectedLegs; + gdi.getSelection("AllCourses", selectedCourses); + gdi.getSelection("AllStages", selectedLegs); + for (set::iterator it = selectedLegs.begin(); it != selectedLegs.end(); ++it) { + int leg = *it; + forkingSetup[leg].clear(); + forkingSetup[leg].insert(forkingSetup[leg].begin(), selectedCourses.begin(), selectedCourses.end()); + } + + bool empty = true; + for (size_t k = 0; k < forkingSetup.size(); k++) { + if (forkingSetup[k].empty()) { + gdi.setText("leg"+ itos(k), lang.tl("Leg X: Do not modify.#" + itos(k+1))); + } + else { + empty = false; + string crs; + for (size_t j = 0; j < forkingSetup[k].size(); j++) { + if (j>0) + crs += ", "; + crs += oe->getCourse(forkingSetup[k][j])->getName(); + if (j > 3) { + crs += "..."; + break; + } + } + gdi.setText("leg"+ itos(k), lang.tl("Leg X: Use Y.#" + itos(k+1) + "#" + crs)); + } + } + gdi.setInputStatus("ApplyForking", !empty); + gdi.setSelection("AllCourses", set()); + gdi.setSelection("AllStages", set()); + gdi.refresh(); + } + else if (bi.id == "ClearCourses") { + gdi.setSelection("AllCourses", set()); + gdi.setSelection("AllStages", set()); + gdi.disableInput("AssignCourses"); + } + else if (bi.id == "ShowForking") { + if (!checkClassSelected(gdi)) + return false; + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Klassen finns ej."); + + vector< vector > forks; + set< pair > unfairLegs; + vector< vector > legOrder; + + pc->checkForking(legOrder, forks, unfairLegs); + + gdioutput *gdi_new = getExtraWindow("fork", true); + string title = lang.tl("Forkings for X#" + pc->getName()); + if (!gdi_new) + gdi_new = createExtraWindow("fork", title, + gdi.scaleLength(1024) ); + else + gdi_new->setWindowTitle(title); + + gdi_new->clearPage(false); + + gdi_new->addString("", fontMediumPlus, "Forkings"); + + for (size_t k = 0; k < forks.size(); k++) { + gdi_new->dropLine(0.7); + string ver = itos(k+1) + ": "; + for (size_t j = 0; j < legOrder[k].size(); j++) { + pCourse crs = oe->getCourse(legOrder[k][j]); + if (crs) { + if (j>0) + ver += ", "; + ver += crs->getName(); + } + } + gdi_new->addStringUT(1, ver); + gdi_new->pushX(); + gdi_new->fillRight(); + for (size_t j = 0; j < forks[k].size(); j++) { + string ctrl; + if (forks[k][j] > 0) + ctrl += itos(forks[k][j]); + else { + if (j == 0) + ctrl += lang.tl("Start"); + else if (j + 1 == forks[k].size()) + ctrl += lang.tl("Mål"); + else + ctrl += lang.tl("Växel"); + } + int next = -100; + if (j + 1 < forks[k].size()) { + ctrl += ","; + next = forks[k][j+1]; + } + int prev = j>0 ? forks[k][j-1] : -100; + + bool warn = unfairLegs.count(make_pair(prev, forks[k][j])) != 0;// || + //unfairLegs.count(make_pair(forks[k][j], next)) != 0; + + TextInfo &ti = gdi_new->addStringUT(italicText, ctrl); + if (warn) { + ti.setColor(colorRed); + ti.format = boldText; + } + gdi.setCX(gdi.getCX() - gdi.scaleLength(4)); + } + gdi_new->popX(); + gdi_new->fillDown(); + gdi_new->dropLine(); + } + + if (!unfairLegs.empty()) { + gdi_new->dropLine(); + gdi_new->addString("", fontMediumPlus, "Unfair control legs"); + gdi_new->dropLine(0.5); + for (set< pair >::const_iterator p = unfairLegs.begin(); + p != unfairLegs.end(); ++p) { + + string f = p->first > 0 ? itos(p->first) : "Växel"; + string s = p->second > 0 ? itos(p->second) : "Växel"; + gdi_new->addStringUT(0, MakeDash(f + " - " + s)); + } + } + + gdi_new->dropLine(); + gdi_new->addButton("CloseWindow", "Stäng", ClassesCB); + gdi_new->refresh(); + } + else if (bi.id == "OneCourse") { + if (!checkClassSelected(gdi)) + return false; + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Klassen finns ej."); + pc->setNumStages(0); + pc->synchronize(); + gdi.restore(); + gdi.enableInput("MultiCourse", true); + gdi.enableInput("Courses"); + } + else if (bi.id=="SetNStage") { + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(ClassId); + + if (!pc) + throw std::exception("Klassen finns ej."); + + int total, finished, dns; + oe->getNumClassRunners(pc->getId(), 0, total, finished, dns); + + oEvent::PredefinedTypes newType = oEvent::PredefinedTypes(gdi.getSelectedItem("Predefined").first); + int nstages = gdi.getTextNo("NStage"); + + if (finished > 0) { + if (gdi.ask("warning:has_results") == false) + return false; + } + else if (total>0) { + bool ok = false; + ClassType ct = pc->getClassType(); + if (ct == oClassIndividual) { + switch (newType) { + case oEvent::PPatrolOptional: + case oEvent::PPool: + case oEvent::PPoolDrawn: + case oEvent::PNoMulti: + case oEvent::PForking: + ok = true; + break; + case oEvent::PNoSettings: + ok = (nstages == 1); + } + } + + if (!ok) { + if (gdi.ask("warning:has_entries") == false) + return false; + } + } + storedPredefined = newType; + + if (nstages > 0) + storedNStage = gdi.getText("NStage"); + else { + storedNStage = ""; + if (newType != oEvent::PNoMulti) + nstages = 1; //Fixed by type + } + + if (nstages>0 && nstages<41) { + string st=gdi.getText("StartTime"); + if (oe->convertAbsoluteTime(st)>0) + storedStart = st; + + save(gdi, false); //Clears and reloads + + gdi.selectItemByData("Courses", -2); + gdi.disableInput("Courses"); + oe->setupRelay(*pc, newType, nstages, st); + + if (gdi.hasField("MAdd")) { + gdi.enableInput("MAdd"); + gdi.enableInput("MCourses"); + gdi.enableInput("MRemove"); + } + pc->forceShowMultiDialog(true); + selectClass(gdi, pc->getId()); + } + else if (nstages==0){ + pc->setNumStages(0); + pc->synchronize(); + gdi.restore(); + gdi.enableInput("MultiCourse", true); + gdi.enableInput("Courses"); + oe->adjustTeamMultiRunners(pc); + } + else { + gdi.alert("Antalet sträckor måste vara ett heltal mellan 0 och 40."); + } + } + else if (bi.id.substr(0, 7)=="@Course") { + int cnr=atoi(bi.id.substr(7).c_str()); + selectCourses(gdi, cnr); + } + else if (bi.id=="MAdd"){ + DWORD cid=ClassId; + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(cid); + + if (!pc) + return false; + + if (currentStage>=0){ + ListBoxInfo lbi; + if (gdi.getSelectedItem("MCourses", lbi)) { + int courseid=lbi.data; + + pc->addStageCourse(currentStage, courseid); + pc->fillStageCourses(gdi, currentStage, "StageCourses"); + + pc->synchronize(); + oe->checkOrderIdMultipleCourses(cid); + } + } + EditChanged=true; + } + else if (bi.id=="MRemove"){ + if (!checkClassSelected(gdi)) + return false; + + DWORD cid=ClassId; + + pClass pc=oe->getClass(cid); + + if (!pc) + return false; + + if (currentStage>=0){ + ListBoxInfo lbi; + if (gdi.getSelectedItem("StageCourses", lbi)) { + int courseid=lbi.data; + pc->removeStageCourse(currentStage, courseid, lbi.index); + pc->synchronize(); + pc->fillStageCourses(gdi, currentStage, "StageCourses"); + } + } + } + EditChanged=true; + } + else if (type==GUI_LISTBOX) { + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id.substr(0, 7)=="LegType") { + LegTypes lt = LegTypes(bi.data); + + int i=atoi(bi.id.substr(7).c_str()); + pClass pc=oe->getClass(ClassId); + if (!pc) + return false; + if (lt == pc->getLegType(i)) + return 0; + + pc->setLegType(i, lt); + char legno[10]; + sprintf_s(legno, "%d", i); + updateStartData(gdi, pc, i, true, false); + + gdi.setInputStatus(string("Restart")+legno, !pc->restartIgnored(i), true); + gdi.setInputStatus(string("RestartRope")+legno, !pc->restartIgnored(i), true); + + EditChanged=true; + } + else if (bi.id == "AllStages") { + set t; + gdi.getSelection(bi.id, t); + gdi.setInputStatus("AssignCourses", !t.empty()); + } + else if (bi.id.substr(0, 9)=="StartType") { + StartTypes st=StartTypes(bi.data); + int i=atoi(bi.id.substr(9).c_str()); + pClass pc=oe->getClass(ClassId); + if (!pc) + return false; + pc->setStartType(i, st, true); + char legno[10]; + sprintf_s(legno, "%d", i); + updateStartData(gdi, pc, i, true, false); + + gdi.setInputStatus(string("Restart")+legno, !pc->restartIgnored(i), true); + gdi.setInputStatus(string("RestartRope")+legno, !pc->restartIgnored(i), true); + + EditChanged=true; + } + else if (bi.id == "Predefined") { + bool nleg; + bool start; + oe->setupRelayInfo(oEvent::PredefinedTypes(bi.data), nleg, start); + gdi.setInputStatus("NStage", nleg); + gdi.setInputStatus("StartTime", start); + + string nl = gdi.getText("NStage"); + if (!nleg && nl != "-") { + storedNStage = nl; + gdi.setText("NStage", "-"); + } + else if (nleg && nl == "-") { + gdi.setText("NStage", storedNStage); + } + + string st = gdi.getText("StartTime"); + if (!start && st != "-") { + storedStart = st; + gdi.setText("StartTime", "-"); + } + else if (start && st == "-") { + gdi.setText("StartTime", storedStart); + } + } + else if (bi.id=="Courses") { + EditChanged=true; + } + } + else if (type==GUI_INPUTCHANGE){ + InputInfo ii=*(InputInfo *)data; + + EditChanged=true; + if (ii.id=="NStage") + gdi.enableInput("SetNStage"); + //else if (ii.id=="") + } + return 0; +} + +int TabClass::classCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="Cancel") { + showForkingGuide = false; + loadPage(gdi); + return 0; + } + else if (bi.id == "UseAdvanced") { + bool checked = gdi.isChecked("UseAdvanced"); + oe->setProperty("AdvancedClassSettings", checked); + save(gdi, true); + PostMessage(gdi.getTarget(), WM_USER + 2, TClassTab, 0); + } + else if (bi.id=="SwitchMode") { + if (!tableMode) + save(gdi, true); + tableMode=!tableMode; + loadPage(gdi); + } + else if (bi.id=="Restart") { + save(gdi, true); + gdi.clearPage(true); + gdi.addString("", 2, "Omstart i stafettklasser"); + gdi.addString("", 10, "help:31661"); + gdi.addListBox("RestartClasses", 200, 250, 0, "Stafettklasser", "", true); + oe->fillClasses(gdi, "RestartClasses", oEvent::extraNone, oEvent::filterOnlyMulti); + gdi.pushX(); + gdi.fillRight(); + oe->updateComputerTime(); + int t=oe->getComputerTime()-(oe->getComputerTime()%60)+60; + gdi.addInput("Rope", oe->getAbsTime(t), 6, 0, "Repdragningstid"); + gdi.addInput("Restart", oe->getAbsTime(t+600), 6, 0, "Omstartstid"); + gdi.dropLine(0.9); + gdi.addButton("DoRestart","OK", ClassesCB); + gdi.addButton("Cancel","Stäng", ClassesCB); + gdi.fillDown(); + gdi.dropLine(3); + gdi.popX(); + } + else if (bi.id=="DoRestart") { + set cls; + gdi.getSelection("RestartClasses", cls); + gdi.fillDown(); + set::iterator it; + string ropeS=gdi.getText("Rope"); + int rope = oe->getRelativeTime(ropeS); + string restartS=gdi.getText("Restart"); + int restart = oe->getRelativeTime(restartS); + + if (rope<=0) { + gdi.alert("Ogiltig repdragningstid."); + return 0; + } + if (restart<=0) { + gdi.alert("Ogiltig omstartstid."); + return 0; + } + if (restartgetAbsTime(rope) + "#" + oe->getAbsTime(restart)); + + for (it=cls.begin(); it!=cls.end(); ++it) { + pClass pc=oe->getClass(*it); + + if (pc) { + gdi.addStringUT(0, pc->getName()); + + int ns=pc->getNumStages(); + + for (int k=0;ksetRopeTime(k, ropeS); + pc->setRestartTime(k, restartS); + } + } + } + gdi.scrollToBottom(); + gdi.refresh(); + } + else if (bi.id=="SaveDrawSettings") { + readClassSettings(gdi); + for(size_t k=0; ksynchronize(false); + ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart); + ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval); + ci.pc->setDrawVacant(ci.nVacant); + ci.pc->setDrawNumReserved(ci.nExtra); + ci.pc->synchronize(true); + } + } + } + else if (bi.id=="DoDrawAll") { + readClassSettings(gdi); + int method = gdi.getSelectedItem("Method").first; + bool soft = method == DMSOFT; + int pairSize = gdi.getSelectedItem("PairSize").first; + + bool drawCoursebased = drawInfo.coursesTogether; + + map > specs; + for(size_t k=0; ksynchronize(false); + ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart); + ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval); + ci.pc->setDrawVacant(ci.nVacant); + ci.pc->setDrawNumReserved(ci.nExtra); + ci.pc->synchronize(true); + } + ClassDrawSpecification cds(ci.classId, 0, drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart, + drawInfo.baseInterval * ci.interval, ci.nVacant); + if (drawCoursebased) { + pCourse pCrs = oe->getClass(ci.classId)->getCourse(); + int id = pCrs ? pCrs->getId() : 101010101 + ci.classId; + specs[id].push_back(cds); + } + else + specs[ci.classId].push_back(cds); + } + + for (map >::iterator it = specs.begin(); + it != specs.end(); ++it) { + oe->drawList(it->second, soft, pairSize, oEvent::drawAll); + } + + oe->addAutoBib(); + + gdi.clearPage(false); + gdi.addButton("Cancel", "Återgå", ClassesCB); + + oListParam par; + oListInfo info; + par.listCode = EStdStartList; + for (size_t k=0; kgenerateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + gdi.refresh(); + } + else if (bi.id == "RemoveVacant") { + if (gdi.ask("Vill du radera alla vakanser från tävlingen?")) { + oe->removeVacanies(0); + gdi.disableInput(bi.id.c_str()); + } + } + else if (bi.id == "SelectAll") { + set lst; + oe->getAllClasses(lst); + gdi.setSelection("Classes", lst); + enableLoadSettings(gdi); + } + else if (bi.id == "SelectUndrawn") { + set lst; + oe->getNotDrawnClasses(lst, false); + gdi.setSelection("Classes", lst); + enableLoadSettings(gdi); + } + else if (bi.id == "SelectStart") { + int id = bi.getExtraInt(); + vector blocks; + vector starts; + oe->getStartBlocks(blocks, starts); + if (size_t(id) < starts.size()) { + string start = starts[id]; + set lst; + vector cls; + oe->getClasses(cls, true); + for (size_t k = 0; k < cls.size(); k++) { + if (cls[k]->getStart() == start) + lst.insert(cls[k]->getId()); + } + gdi.setSelection("Classes", lst); + } + enableLoadSettings(gdi); + } + else if (bi.id == "QuickSettings") { + save(gdi, false); + prepareForDrawing(gdi); + } + else if (bi.id == "DrawMode") { + save(gdi, false); + ClassId = 0; + + EditChanged=false; + gdi.clearPage(true); + + gdi.addString("", boldLarge, "Lotta flera klasser"); + gdi.dropLine(); + + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("FirstStart", oe->getAbsTime(3600), 10, 0, "Första (ordinarie) start:"); + gdi.addInput("MinInterval", "2:00", 10, 0, "Minsta startintervall:"); + gdi.fillDown(); + gdi.addInput("Vacances", "5%", 10, 0, "Andel vakanser:"); + gdi.popX(); + + gdi.addSelection("Method", 200, 200, 0, "Metod:"); + gdi.addItem("Method", lang.tl("Lottning"), DMRandom); + gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); + gdi.selectItemByData("Method", getDefaultMethod(false)); + + gdi.fillDown(); + gdi.addCheckbox("LateBefore", "Efteranmälda före ordinarie"); + gdi.dropLine(); + + gdi.popX(); + gdi.fillRight(); + gdi.addButton("AutomaticDraw", "Automatisk lottning", ClassesCB).setDefault(); + gdi.addButton("DrawAll", "Manuell lottning", ClassesCB).setExtra(1); + gdi.addButton("Simultaneous", "Gemensam start", ClassesCB); + + const bool multiDay = oe->hasPrevStage(); + + if (multiDay) + gdi.addButton("Pursuit", "Hantera jaktstart", ClassesCB); + + gdi.addButton("Cancel", "Återgå", ClassesCB).setCancel(); + + gdi.dropLine(3); + + gdi.newColumn(); + + gdi.addString("", 10, "help_autodraw"); + } + else if (bi.id == "Pursuit") { + pursuitDialog(gdi); + } + else if (bi.id == "SelectAllNoneP") { + bool select = bi.getExtraInt() != 0; + for (int k = 0; k < oe->getNumClasses(); k++) { + gdi.check("PLUse" + itos(k), select); + gdi.setInputStatus("First" + itos(k), select); + } + } + else if (bi.id == "DoPursuit" || bi.id=="CancelPursuit" || bi.id == "SavePursuit") { + bool cancel = bi.id=="CancelPursuit"; + + int maxAfter = convertAbsoluteTimeMS(gdi.getText("MaxAfter")); + int deltaRestart = convertAbsoluteTimeMS(gdi.getText("TimeRestart")); + int interval = convertAbsoluteTimeMS(gdi.getText("Interval")); + + double scale = atof(gdi.getText("ScaleFactor").c_str()); + bool reverse = bi.getExtraInt() == 2; + int pairSize = gdi.getSelectedItem("PairSize").first; + + pSavedDepth = maxAfter; + pFirstRestart = deltaRestart; + pTimeScaling = scale; + pInterval = interval; + + oListParam par; + + for (int k = 0; k < oe->getNumClasses(); k++) { + if (!gdi.hasField("PLUse" + itos(k))) + continue; + BaseInfo *bi = gdi.setText("PLUse" + itos(k), "", false); + if (bi) { + int id = bi->getExtraInt(); + bool checked = gdi.isChecked("PLUse" + itos(k)); + int first = oe->getRelativeTime(gdi.getText("First" + itos(k))); + //int max = oe->getRelativeTime(gdi.getText("Max" + itos(k))); + + map::iterator st = pSettings.find(id); + if (st != pSettings.end()) { + st->second.firstTime = first; + st->second.maxTime = maxAfter; + st->second.use = checked; + } + + if (checked) { + pClass pc = oe->getClass(id); + if (pc) + pc->setDrawFirstStart(first); + } + + if (!cancel && checked) { + oe->drawPersuitList(id, first, first + deltaRestart, maxAfter, + interval, pairSize, reverse, scale); + par.selection.insert(id); + } + } + } + + if (bi.id == "SavePursuit") { + return 0; + } + + if (cancel) { + loadPage(gdi); + return 0; + } + + gdi.restore("Pursuit", false); + + gdi.dropLine(); + gdi.fillDown(); + + oListInfo info; + par.listCode = EStdStartList; + oe->generateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + gdi.dropLine(); + gdi.addButton("Cancel", "Återgå", ClassesCB); + gdi.refresh(); + } + else if (bi.id.substr(0,5) == "PLUse") { + int k = atoi(bi.id.substr(5).c_str()); + gdi.setInputStatus("First" + itos(k), gdi.isChecked(bi.id)); + } + else if (bi.id == "AutomaticDraw") { + string firstStart = gdi.getText("FirstStart"); + string minInterval = gdi.getText("MinInterval"); + string vacances = gdi.getText("Vacances"); + bool lateBefore = false; + //bool pairwise = gdi.isChecked("Pairwise"); + int pairSize = 1; + if (gdi.hasField("PairSize")) { + pairSize = gdi.getSelectedItem("PairSize").first; + } + + int method = gdi.getSelectedItem("Method").first; + bool useSoft = method == DMSOFT; + gdi.clearPage(true); + oe->automaticDrawAll(gdi, firstStart, minInterval, vacances, + lateBefore, useSoft, pairSize); + oe->addAutoBib(); + gdi.scrollToBottom(); + gdi.addButton("Cancel", "Återgå", ClassesCB); + } + else if (bi.id == "SelectMisses") { + set lst; + oe->getNotDrawnClasses(lst, true); + gdi.setSelection("Classes", lst); + enableLoadSettings(gdi); + } + else if (bi.id == "SelectNone") { + gdi.setSelection("Classes", set()); + enableLoadSettings(gdi); + } + else if (bi.id == "Simultaneous") { + string firstStart;// = oe->getAbsTime(3600); + firstStart = gdi.getText("FirstStart"); + + gdi.clearPage(false); + gdi.addString("", boldLarge, "Gemensam start"); + gdi.dropLine(); + int by = 0; + int bx = gdi.getCX(); + + showClassSelection(gdi, bx, by, 0); + + gdi.pushX(); + gdi.addInput("FirstStart", firstStart, 10, 0, "Starttid:"); + + gdi.dropLine(4); + gdi.popX(); + gdi.fillRight(); + gdi.addButton("AssignStart", "Tilldela", ClassesCB).isEdit(true); + gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel(); + gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(1); + + gdi.refresh(); + } + else if (bi.id == "AssignStart") { + set classes; + gdi.getSelection("Classes", classes); + if (classes.empty()) { + gdi.alert("Ingen klass vald."); + return 0; + } + + string time = gdi.getText("FirstStart"); + for (set::iterator it = classes.begin(); it!=classes.end();++it) { + simultaneous(*it, time); + } + + bi.id = "Simultaneous"; + classCB(gdi, type, &bi); + } + else if (bi.id == "DrawAll") { + int origin = bi.getExtraInt(); + string firstStart = oe->getAbsTime(3600); + string minInterval = "2:00"; + string vacances = "5%"; + int maxNumControl = 1; + int pairSize = 1; + + //bool pairwise = false; + int by = 0; + int bx = gdi.getCX(); + if (origin!=13) { + if (origin!=1) { + save(gdi, true); + ClassId = 0; + + EditChanged=false; + } + else { + firstStart = gdi.getText("FirstStart"); + minInterval = gdi.getText("MinInterval"); + vacances = gdi.getText("Vacances"); + //pairwise = gdi.isChecked("Pairwise"); + if (gdi.hasField("PairSize")) { + pairSize = gdi.getSelectedItem("PairSize").first; + } + } + + gdi.clearPage(false); + + gdi.addString("", boldLarge, "Lotta flera klasser"); + gdi.dropLine(0.5); + + showClassSelection(gdi, bx, by, DrawClassesCB); + vector cls; + oe->getClasses(cls, false); + set clsId; + for (size_t k = 0; k < cls.size(); k++) { + if (cls[k]->hasFreeStart()) + continue; + if (cls[k]->getStartType(0) != STDrawn) + continue; + clsId.insert(cls[k]->getId()); + } + + gdi.setSelection("Classes", clsId); + + gdi.addString("", 1, "Grundinställningar"); + + gdi.pushX(); + gdi.fillRight(); + + gdi.addInput("FirstStart", firstStart, 10, 0, "Första start:"); + gdi.addInput("nFields", "10", 10, 0, "Max parallellt startande:"); + gdi.popX(); + gdi.dropLine(3); + + gdi.addSelection("MaxCommonControl", 150, 100, 0, + "Max antal gemensamma kontroller:"); + + vector< pair > items; + items.push_back(make_pair(lang.tl("Inga"), 1)); + items.push_back(make_pair(lang.tl("Första kontrollen"), 2)); + for (int k = 2; k<10; k++) + items.push_back(make_pair(lang.tl("X kontroller#" + itos(k)), k+1)); + items.push_back(make_pair(lang.tl("Hela banan"), 1000)); + gdi.addItem("MaxCommonControl", items); + gdi.selectItemByData("MaxCommonControl", maxNumControl); + + gdi.popX(); + gdi.dropLine(4); + gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, true); + gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false); + + gdi.popX(); + gdi.dropLine(2); + gdi.addString("", 1, "Startintervall"); + gdi.dropLine(1.4); + gdi.popX(); + gdi.fillRight(); + gdi.addInput("BaseInterval", "1:00", 10, 0, "Basintervall (min):"); + gdi.addInput("MinInterval", minInterval, 10, 0, "Minsta intervall i klass:"); + gdi.addInput("MaxInterval", minInterval, 10, 0, "Största intervall i klass:"); + + gdi.popX(); + gdi.dropLine(4); + gdi.addString("", 1, "Vakanser och efteranmälda"); + gdi.dropLine(1.4); + gdi.popX(); + gdi.addInput("Vacances", vacances, 10, 0, "Andel vakanser:"); + gdi.addInput("VacancesMin", "1", 10, 0, "Min. vakanser (per klass):"); + gdi.addInput("VacancesMax", "10", 10, 0, "Max. vakanser (per klass):"); + + gdi.popX(); + gdi.dropLine(3); + + gdi.addInput("Extra", "0%", 10, 0, "Förväntad andel efteranmälda:"); + + gdi.dropLine(4); + gdi.fillDown(); + gdi.popX(); + gdi.setRestorePoint("Setup"); + + } + else { + gdi.restore("Setup"); + by = gdi.getHeight(); + gdi.enableEditControls(true); + } + + gdi.fillRight(); + gdi.pushX(); + RECT rcPrepare; + rcPrepare.left = gdi.getCX(); + rcPrepare.top = gdi.getCY(); + gdi.setCX(gdi.getCX() + gdi.getLineHeight()); + gdi.dropLine(); + gdi.addString("", fontMediumPlus, "Förbered lottning"); + gdi.dropLine(2.5); + gdi.popX(); + gdi.setCX(gdi.getCX() + gdi.getLineHeight()); + gdi.addButton("PrepareDrawAll", "Fördela starttider...", ClassesCB).isEdit(true).setDefault(); + gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(0); + gdi.addButton("LoadSettings", "Hämta inställningar från föregående lottning", ClassesCB).isEdit(true); + enableLoadSettings(gdi); + + gdi.dropLine(3); + rcPrepare.bottom = gdi.getCY(); + rcPrepare.right = gdi.getWidth(); + gdi.addRectangle(rcPrepare, colorLightGreen); + gdi.dropLine(); + gdi.popX(); + + gdi.addString("", 1, "Efteranmälningar"); + gdi.dropLine(1.5); + gdi.popX(); + gdi.addButton("DrawAllBefore", "Efteranmälda (före ordinarie)", ClassesCB).isEdit(true); + gdi.addButton("DrawAllAfter", "Efteranmälda (efter ordinarie)", ClassesCB).isEdit(true); + + gdi.dropLine(4); + gdi.popX(); + + gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel(); + gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, ""); + gdi.dropLine(3); + + by = max(by, gdi.getCY()); + + gdi.setCX(bx); + gdi.setCY(by); + gdi.fillDown(); + gdi.dropLine(); + + gdi.setRestorePoint("ReadyToDistribute"); + gdi.refresh(); + } + else if (bi.id == "HelpDraw") { + + gdioutput *gdi_new = getExtraWindow("help", true); + + if (!gdi_new) + gdi_new = createExtraWindow("help", MakeDash("MeOS - " + lang.tl("Hjälp")), gdi.scaleLength(640)); + gdi_new->clearPage(true); + gdi_new->addString("", boldLarge, "Lotta flera klasser"); + gdi_new->addString("", 10, "help_draw"); + gdi_new->dropLine(); + gdi_new->addButton("CloseWindow", "Stäng", ClassesCB); + } + else if (bi.id == "CloseWindow") { + gdi.closeWindow(); + } + else if (bi.id=="PrepareDrawAll") { + set classes; + gdi.getSelection("Classes", classes); + if (classes.empty()) { + throw meosException("Ingen klass vald."); + } + gdi.restore("ReadyToDistribute"); + drawInfo.classes.clear(); + + for (set::iterator it = classes.begin(); it!=classes.end();++it) { + map::iterator res = cInfoCache.find(*it); + if ( res != cInfoCache.end() ) { + res->second.hasFixedTime = false; + drawInfo.classes[*it] = res->second; + } + else + drawInfo.classes[*it] = ClassInfo(oe->getClass(*it)); + } + + readDrawInfo(gdi, drawInfo); + if (drawInfo.baseInterval <= 0 || drawInfo.baseInterval == NOTIME) + throw meosException("Ogiltigt basintervall."); + if (drawInfo.minClassInterval <= 0 || drawInfo.minClassInterval == NOTIME) + throw meosException("Ogiltigt minimalt intervall."); + if (drawInfo.minClassInterval > drawInfo.maxClassInterval || drawInfo.maxClassInterval == NOTIME) + throw meosException("Ogiltigt maximalt intervall. "); + + if (drawInfo.minClassInterval < drawInfo.baseInterval) { + throw meosException("Startintervallet får inte vara kortare än basintervallet."); + } + + if (drawInfo.minClassInterval % drawInfo.baseInterval != 0 || + drawInfo.maxClassInterval % drawInfo.baseInterval != 0) { + throw meosException("Ett startintervall måste vara en multipel av basintervallet."); + } + + gdi.enableEditControls(false); + + if (drawInfo.firstStart<=0) { + drawInfo.baseInterval = 0; + gdi.addString("", 0, "Raderar starttider..."); + } + + oe->optimizeStartOrder(gdi, drawInfo, cInfo); + + showClassSettings(gdi); + } + else if (bi.id == "LoadSettings") { + set classes; + gdi.getSelection("Classes", classes); + if (classes.empty()) { + throw meosException("Ingen klass vald."); + } + gdi.restore("ReadyToDistribute"); + oe->loadDrawSettings(classes, drawInfo, cInfo); + + /* + drawInfo.firstStart = 3600 * 22; + drawInfo.minClassInterval = 3600; + drawInfo.maxClassInterval = 1; + drawInfo.minVacancy = 10; + + set reducedStart; + for (set::iterator it = classes.begin(); it != classes.end(); ++it) { + pClass pc = oe->getClass(*it); + if (pc) { + int fs = pc->getDrawFirstStart(); + int iv = pc->getDrawInterval(); + if (iv > 0 && fs > 0) { + drawInfo.firstStart = min(drawInfo.firstStart, fs); + drawInfo.minClassInterval = min(drawInfo.minClassInterval, iv); + drawInfo.maxClassInterval = max(drawInfo.maxClassInterval, iv); + drawInfo.minVacancy = min(drawInfo.minVacancy, pc->getDrawVacant()); + drawInfo.maxVacancy = max(drawInfo.maxVacancy, pc->getDrawVacant()); + reducedStart.insert(fs%iv); + } + } + } + + drawInfo.baseInterval = drawInfo.minClassInterval; + int lastStart = -1; + for (set::iterator it = reducedStart.begin(); it != reducedStart.end(); ++it) { + if (lastStart == -1) + lastStart = *it; + else { + drawInfo.baseInterval = min(drawInfo.baseInterval, *it-lastStart); + lastStart = *it; + } + } + + cInfo.clear(); + cInfo.resize(classes.size()); + int i = 0; + for (set::iterator it = classes.begin(); it != classes.end(); ++it) { + pClass pc = oe->getClass(*it); + if (pc) { + int fs = pc->getDrawFirstStart(); + int iv = pc->getDrawInterval(); + cInfo[i].pc = pc; + cInfo[i].classId = *it; + cInfo[i].courseId = pc->getCourseId(); + cInfo[i].firstStart = fs; + cInfo[i].unique = pc->getCourseId(); + if (cInfo[i].unique == 0) + cInfo[i].unique = pc->getId() * 10000; + cInfo[i].firstStart = (fs - drawInfo.firstStart) / drawInfo.baseInterval; + cInfo[i].interval = iv / drawInfo.baseInterval; + cInfo[i].nVacant = pc->getDrawVacant(); + i++; + } + } + */ + writeDrawInfo(gdi, drawInfo); + gdi.enableEditControls(false); + + showClassSettings(gdi); + } + else if (bi.id == "VisualizeDraw") { + readClassSettings(gdi); + + gdioutput *gdi_new = getExtraWindow(visualDrawWindow, true); + if (!gdi_new) + gdi_new = createExtraWindow(visualDrawWindow, MakeDash("MeOS - " + lang.tl("Visualisera startfältet")), gdi.scaleLength(1000)); + + gdi_new->clearPage(false); + gdi_new->addString("", boldLarge, "Visualisera startfältet"); + gdi_new->dropLine(); + gdi_new->addString("", 0, "För muspekaren över en markering för att få mer information."); + gdi_new->dropLine(); + visualizeField(*gdi_new); + gdi_new->dropLine(); + gdi_new->addButton("CloseWindow", "Stäng", ClassesCB); + gdi_new->registerEvent("CloseWindow", 0).setHandler(&handleCloseWindow); + gdi_new->refresh(); + } + else if (bi.id == "EraseStartAll") { + set classes; + gdi.getSelection("Classes", classes); + if (classes.empty()) { + gdi.alert("Ingen klass vald."); + return 0; + } + if (classes.size() == 1) { + pClass pc = oe->getClass(*classes.begin()); + if (!pc || !gdi.ask("Vill du verkligen radera alla starttider i X?#" + pc->getName())) + return 0; + } + else { + if (!gdi.ask("Vill du verkligen radera starttider i X klasser?#" + itos(classes.size())) ) + return 0; + } + + for (set::const_iterator it = classes.begin(); it != classes.end(); ++it) { + vector spec; + spec.push_back(ClassDrawSpecification(*it, 0, 0, 0, 0)); + oe->drawList(spec, false, 1, oEvent::drawAll); + } + + if (bi.getExtraInt() == 1) + bi.id = "Simultaneous"; + else + bi.id = "DrawAll"; + + bi.setExtra(1); + classCB(gdi, type, &bi); // Reload draw dialog + } + else if (bi.id == "DrawAdjust") { + readClassSettings(gdi); + gdi.restore("ReadyToDistribute"); + oe->optimizeStartOrder(gdi, drawInfo, cInfo); + showClassSettings(gdi); + } + else if (bi.id == "DrawAllAdjust") { + readClassSettings(gdi); + bi.id = "DrawAll"; + return classCB(gdi, type, &bi); + } + else if (bi.id == "DrawAllBefore" || bi.id == "DrawAllAfter") { + oe->drawRemaining(true, bi.id == "DrawAllAfter"); + oe->addAutoBib(); + loadPage(gdi); + } + else if (bi.id=="DoDraw" || bi.id=="DoDrawAfter" || bi.id=="DoDrawBefore"){ + if (!checkClassSelected(gdi)) + return false; + + DWORD cid=ClassId; + DrawMethod method = DrawMethod(gdi.getSelectedItem("Method").first); + + int interval = 0; + if (gdi.hasField("Interval")) + interval = convertAbsoluteTimeMS(gdi.getText("Interval")); + + int vacanses = 0; + if (gdi.hasField("Vacanses")) + vacanses = gdi.getTextNo("Vacanses"); + + int leg = 0; + if (gdi.hasField("Leg")) { + leg = gdi.getSelectedItem("Leg").first; + } + + string bib; + bool doBibs = false; + + if (gdi.hasField("Bib")) { + bib = gdi.getText("Bib"); + doBibs = gdi.isChecked("HandleBibs"); + } + + string time = gdi.getText("FirstStart"); + int t=oe->getRelativeTime(time); + + if (t<=0) + throw std::exception("Ogiltig första starttid. Måste vara efter nolltid."); + + oEvent::DrawType type(oEvent::drawAll); + if (bi.id=="DoDrawAfter") + type = oEvent::remainingAfter; + else if (bi.id=="DoDrawBefore") + type = oEvent::remainingBefore; + + //bool pairwise = false; + +// if (gdi.hasField("Pairwise")) + // pairwise = gdi.isChecked("Pairwise"); + int pairSize = 1; + if (gdi.hasField("PairSize")) { + pairSize = gdi.getSelectedItem("PairSize").first; + } + + int maxTime = 0, restartTime = 0; + double scaleFactor = 1.0; + + if (gdi.hasField("TimeRestart")) + restartTime = oe->getRelativeTime(gdi.getText("TimeRestart")); + + if (gdi.hasField("MaxAfter")) + maxTime = convertAbsoluteTimeMS(gdi.getText("MaxAfter")); + + if (gdi.hasField("ScaleFactor")) + scaleFactor = atof(gdi.getText("ScaleFactor").c_str()); + + if (method == DMRandom || method == DMSOFT) { + vector spec; + spec.push_back(ClassDrawSpecification(cid, leg, t, interval, vacanses)); + + oe->drawList(spec, method == DMSOFT, pairSize, type); + } + else if (method == DMClumped) + oe->drawListClumped(cid, t, interval, vacanses); + else if (method == DMPursuit || method == DMReversePursuit) { + oe->drawPersuitList(cid, t, restartTime, maxTime, + interval, pairSize, + method == DMReversePursuit, + scaleFactor); + } + else if (method == DMSimultaneous) { + simultaneous(cid, time); + } + else if (method == DMSeeded) { + ListBoxInfo seedMethod; + gdi.getSelectedItem("SeedMethod", seedMethod); + string seedGroups = gdi.getText("SeedGroups"); + vector out; + split(seedGroups, " ,;", out); + vector sg; + bool invalid = false; + for (size_t k = 0; k < out.size(); k++) { + if (trim(out[k]).empty()) + continue; + int val = atoi(trim(out[k]).c_str()); + if (val <= 0) + invalid = true; + + sg.push_back(val); + } + if (invalid || sg.empty()) + throw meosException("Ogiltig storlek på seedningsgrupper X.#" + seedGroups); + + bool noClubNb = gdi.isChecked("PreventClubNb"); + bool reverse = gdi.isChecked("ReverseSeedning"); + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw meosException("Class not found"); + + pc->drawSeeded(ClassSeedMethod(seedMethod.data), leg, t, interval, + sg, noClubNb, reverse, pairSize); + } + else + throw std::exception("Not implemented"); + + if (doBibs) + oe->addBib(cid, leg, bib); + + // Clear input + gdi.restore("", false); + gdi.addButton("Cancel", "Återgå", ClassesCB).setCancel(); + + gdi.dropLine(); + + oListParam par; + par.selection.insert(cid); + oListInfo info; + par.listCode = EStdStartList; + par.setLegNumberCoded(leg); + oe->generateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + + gdi.refresh(); + return 0; + } + else if (bi.id=="HandleBibs") { + gdi.setInputStatus("Bib", gdi.isChecked("HandleBibs")); + } + else if (bi.id == "DoDeleteStart") { + pClass pc=oe->getClass(ClassId); + if (!pc) + throw meosException("Class not found"); + + if (!gdi.ask("Vill du verkligen radera alla starttider i X?#" + pc->getName())) + return 0; + + int leg = 0; + if (gdi.hasField("Leg")) { + leg = gdi.getSelectedItem("Leg").first; + } + vector spec; + spec.push_back(ClassDrawSpecification(ClassId, leg, 0, 0, 0)); + + oe->drawList(spec, false, 1, oEvent::drawAll); + loadPage(gdi); + } + else if (bi.id=="Draw") { + save(gdi, true); + if (!checkClassSelected(gdi)) + return false; + + DWORD cid=ClassId; + + if (oe->classHasResults(cid)) { + if (!gdi.ask("warning:drawresult")) + return 0; + } + + pClass pc=oe->getClass(cid); + + if (!pc) + throw std::exception("Class not found"); + if (EditChanged) + gdi.sendCtrlMessage("Save"); + + gdi.clearPage(false); + + gdi.addString("", boldLarge, "Lotta klassen X#"+pc->getName()); + gdi.dropLine(); + gdi.pushX(); + gdi.setRestorePoint(); + + gdi.fillDown(); + bool multiDay = oe->hasPrevStage(); + + if (multiDay) { + gdi.addCheckbox("HandleMultiDay", "Använd funktioner för fleretappsklass", ClassesCB, true); + } + + gdi.addSelection("Method", 200, 200, ClassesCB, "Metod:"); + gdi.dropLine(1.5); + gdi.popX(); + + gdi.setRestorePoint("MultiDayDraw"); + + lastDrawMethod = NOMethod; + drawDialog(gdi, getDefaultMethod(true), *pc); + } + else if (bi.id == "HandleMultiDay") { + ListBoxInfo lbi; + gdi.getSelectedItem("Method", lbi); + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Class not found"); + + if (gdi.isChecked(bi.id) && (lastDrawMethod == DMReversePursuit || + lastDrawMethod == DMPursuit)) { + drawDialog(gdi, getDefaultMethod(false), *pc); + } + else + setMultiDayClass(gdi, gdi.isChecked(bi.id), lastDrawMethod); + + } + else if (bi.id=="Bibs") { + save(gdi, true); + if (!checkClassSelected(gdi)) + return false; + + DWORD cid=ClassId; + + pClass pc=oe->getClass(cid); + if (!pc) + throw std::exception("Class not found"); + + gdi.clearPage(false); + gdi.addString("", boldLarge, "Nummerlappar i X#" + pc->getName()); + gdi.dropLine(); + gdi.setRestorePoint("bib"); + + gdi.addString("", 10, "help:bibs"); + gdi.dropLine(); + + vector< pair > bibOptions; + vector< pair > bibTeamOptions; + bibOptions.push_back(make_pair(lang.tl("Manuell"), AutoBibManual)); + bibOptions.push_back(make_pair(lang.tl("Löpande"), AutoBibConsecutive)); + bibOptions.push_back(make_pair(lang.tl("Ingen"), AutoBibNone)); + bibOptions.push_back(make_pair(lang.tl("Automatisk"), AutoBibExplicit)); + + gdi.fillRight(); + gdi.pushX(); + + gdi.addSelection("BibSettings", 150, 100, ClassesCB, "Metod:"); + gdi.addItem("BibSettings", bibOptions); + + AutoBibType bt = pc->getAutoBibType(); + gdi.selectItemByData("BibSettings", bt); + string bib = pc->getDCI().getString("Bib"); + + if (pc->getNumDistinctRunners() > 1) { + bibTeamOptions.push_back(make_pair(lang.tl("Oberoende"), BibFree)); + bibTeamOptions.push_back(make_pair(lang.tl("Samma"), BibSame)); + bibTeamOptions.push_back(make_pair(lang.tl("Ökande"), BibAdd)); + bibTeamOptions.push_back(make_pair(lang.tl("Sträcka"), BibLeg)); + gdi.addSelection("BibTeam", 80, 100, 0, "Lagmedlem:", "Ange relation mellan lagets och deltagarnas nummerlappar."); + gdi.addItem("BibTeam", bibTeamOptions); + gdi.selectItemByData("BibTeam", pc->getBibMode()); + } + + gdi.dropLine(1.1); + gdi.addInput("Bib", "", 10, 0, ""); + gdi.dropLine(3); + + gdi.fillRight(); + gdi.popX(); + gdi.addString("", 0, "Antal reserverade nummerlappsnummer mellan klasser:"); + gdi.dropLine(-0.1); + gdi.addInput("BibGap", itos(oe->getBibClassGap()), 5); + gdi.dropLine(3); + gdi.popX(); + gdi.fillRight(); + gdi.addButton("DoBibs", "Tilldela", ClassesCB).setDefault(); + + gdi.setInputStatus("Bib", bt == AutoBibExplicit || bt == AutoBibManual); + gdi.setInputStatus("BibGap", bt != AutoBibManual); + + if (bt != AutoBibManual) + gdi.setTextTranslate("DoBibs", "OK"); + if (bt == AutoBibExplicit) + gdi.setText("Bib", bib); + + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel(); + gdi.popX(); + + EditChanged=false; + gdi.refresh(); + } + else if (bi.id=="DoBibs") { + if (!checkClassSelected(gdi)) + return false; + + DWORD cid=ClassId; + pClass pc = oe->getClass(cid); + + AutoBibType bt = AutoBibType(gdi.getSelectedItem("BibSettings").first); + + pair teamBib = gdi.getSelectedItem("TeamBib"); + if (teamBib.second) { + pc->setBibMode(BibMode(teamBib.first)); + } + + pc->getDI().setString("Bib", getBibCode(bt, gdi.getText("Bib"))); + pc->synchronize(); + + if (bt == AutoBibManual) { + oe->addBib(cid, 0, gdi.getText("Bib")); + } + else { + oe->setBibClassGap(gdi.getTextNo("BibGap")); + oe->addAutoBib(); + } + + gdi.restore("bib", false); + gdi.dropLine(); + gdi.addButton("Cancel", "Återgå", ClassesCB).setDefault(); + + oListParam par; + par.selection.insert(cid); + oListInfo info; + par.listCode = EStdStartList; + par.setLegNumberCoded(0); + oe->generateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + + gdi.refresh(); + return 0; + } + else if (bi.id=="Split") { + save(gdi, true); + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Class not found"); + + gdi.clearPage(true); + gdi.addString("", boldLarge, "Dela klass: X#" + pc->getName()); + gdi.dropLine(); + int tot, fin, dns; + oe->getNumClassRunners(pc->getId(), 0, tot, fin, dns); + gdi.addString("", fontMediumPlus, "Antal deltagare: X#" + itos(tot)); + gdi.dropLine(1.2); + gdi.pushX(); + gdi.fillRight(); + gdi.addSelection("Type", 200, 100, ClassesCB, "Typ av delning:"); + gdi.selectItemByData("Type", 1); + vector< pair > mt; + oClass::getSplitMethods(mt); + gdi.addItem("Type", mt); + gdi.selectFirstItem("Type"); + + gdi.addSelection("SplitInput", 100, 150, ClassesCB, "Antal klasser:").setExtra(tot); + vector< pair > sp; + for (int k = 2; k < 10; k++) + sp.push_back(make_pair(itos(k), k)); + gdi.addItem("SplitInput", sp); + gdi.selectFirstItem("SplitInput"); + + gdi.dropLine(3); + gdi.popX(); + + updateSplitDistribution(gdi, 2, tot); + } + else if (bi.id=="DoSplit") { + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Class not found"); + + ListBoxInfo lbi; + gdi.getSelectedItem("Type", lbi); + + int number = gdi.getSelectedItem("SplitInput").first; + vector parts(number); + for (int k = 0; k < number; k++) { + string id = "CLS" + itos(k); + parts[k] = gdi.getTextNo(id, false); + } + + vector outClass; + + pc->splitClass(ClassSplitMethod(lbi.data), parts, outClass); + + gdi.clearPage(true); + gdi.addButton("Cancel", "Återgå", ClassesCB); + + oListParam par; + par.selection.insert(outClass.begin(), outClass.end()); + oListInfo info; + par.listCode = EStdStartList; + oe->generateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + } + else if (bi.id=="Merge") { + save(gdi, true); + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Class not found"); + + vector< pair > rawClass, cls; + oe->fillClasses(rawClass, oEvent::extraNone, oEvent::filterNone); + int def = -1; + bool next = false; + for (size_t k = 0; k < rawClass.size(); k++) { + if (rawClass[k].second == ClassId) + next = true; + else { + cls.push_back(rawClass[k]); + + if (next) { + next = false; + def = rawClass[k].second; + } + } + } + if (cls.empty()) + throw std::exception("En klass kan inte slås ihop med sig själv."); + + gdi.clearPage(true); + gdi.addString("", boldLarge, "Slå ihop klass: X (denna klass behålls)#" + pc->getName()); + gdi.dropLine(); + gdi.addString("", 10, "help:12138"); + gdi.dropLine(2); + gdi.pushX(); + gdi.fillRight(); + gdi.addSelection("Class", 150, 300, 0, "Klass att slå ihop:"); + gdi.addItem("Class", cls); + if (def != -1) + gdi.selectItemByData("Class", def); + else + gdi.selectFirstItem("Class"); + + gdi.dropLine(); + gdi.addButton("DoMergeAsk", "Slå ihop", ClassesCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel(); + gdi.dropLine(3); + gdi.popX(); + } + else if (bi.id=="DoMergeAsk") { + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Class not found"); + + pClass mergeClass = oe->getClass(gdi.getSelectedItem("Class").first); + + if (!mergeClass) + throw std::exception("Ingen klass vald."); + + if (mergeClass->getId() == ClassId) + throw std::exception("En klass kan inte slås ihop med sig själv."); + + if (gdi.ask("Vill du flytta löpare från X till Y och ta bort Z?#" + + mergeClass->getName() + "#" + pc->getName() + "#" + mergeClass->getName())) { + bi.id = "DoMerge"; + return classCB(gdi, type, &bi); + } + return false; + } + else if (bi.id=="DoMerge") { + if (!checkClassSelected(gdi)) + return false; + + pClass pc=oe->getClass(ClassId); + if (!pc) + throw std::exception("Class not found"); + + ListBoxInfo lbi; + gdi.getSelectedItem("Class", lbi); + + if (signed(lbi.data)<=0) + throw std::exception("Ingen klass vald."); + + if (lbi.data==ClassId) + throw std::exception("En klass kan inte slås ihop med sig själv."); + + pc->mergeClass(lbi.data); + gdi.clearPage(true); + gdi.addButton("Cancel", "Återgå", ClassesCB); + + oListParam par; + par.selection.insert(ClassId); + oListInfo info; + par.listCode = EStdStartList; + oe->generateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + gdi.refresh(); + } + else if (bi.id=="MultiCourse") { + save(gdi, false); + multiCourse(gdi, 0); + gdi.refresh(); + } + else if (bi.id=="Save") + save(gdi, false); + else if (bi.id=="Add") { + string name = gdi.getText("Name"); + pClass c = oe->getClass(ClassId); + if (!name.empty() && c && c->getName() != name) { + if (gdi.ask("Vill du lägga till klassen 'X'?#" + name)) { + c = oe->addClass(name); + ClassId = c->getId(); + save(gdi, false); + return true; + } + } + + + save(gdi, true); + pClass pc = oe->addClass(oe->getAutoClassName(), 0); + if (pc) { + oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone); + selectClass(gdi, pc->getId()); + gdi.setInputFocus("Name", true); + } + } + else if (bi.id=="Remove") { + EditChanged=false; + if (!checkClassSelected(gdi)) + return false; + + DWORD cid=ClassId; + + if (oe->isClassUsed(cid)) + gdi.alert("Klassen används och kan inte tas bort."); + else + oe->removeClass(cid); + + oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone); + ClassId = 0; + selectClass(gdi, 0); + } + } + else if (type==GUI_LISTBOX) { + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Classes") { + if (gdi.isInputChanged("")) + save(gdi, true); + + selectClass(gdi, bi.data); + } + else if (bi.id == "SplitInput") { + int num = bi.data; + updateSplitDistribution(gdi, num, bi.getExtraInt()); + } + else if (bi.id=="Courses") + EditChanged=true; + else if (bi.id == "BibSettings") { + AutoBibType bt = (AutoBibType)bi.data; + gdi.setInputStatus("Bib", bt == AutoBibExplicit || bt == AutoBibManual); + gdi.setInputStatus("BibGap", bt != AutoBibManual); + if (bt != AutoBibManual) + gdi.setTextTranslate("DoBibs", "OK"); + else + gdi.setTextTranslate("DoBibs", "Tilldela"); + } + else if (bi.id=="Type") { + if (bi.data==1) { + gdi.setTextTranslate("TypeDesc", "Antal klasser:", true); + gdi.setText("SplitInput", "2"); + } + else { + gdi.setTextTranslate("TypeDesc", "Löpare per klass:", true); + gdi.setText("SplitInput", "100"); + } + } + else if (bi.id == "Method") { + pClass pc = oe->getClass(ClassId); + if (!pc) + throw std::exception("Nullpointer exception"); + + drawDialog(gdi, DrawMethod(bi.data), *pc); + } + } + else if (type==GUI_INPUTCHANGE) { + //InputInfo ii=*(InputInfo *)data; + + } + else if (type==GUI_CLEAR) { + if (ClassId>0) + save(gdi, true); + if (EditChanged) { + if (gdi.ask("Spara ändringar?")) + gdi.sendCtrlMessage("Save"); + } + return true; + } + return 0; +} + +void TabClass::readClassSettings(gdioutput &gdi) +{ + for (size_t k=0;kgetRelativeTime(start) - drawInfo.firstStart; + + if (drawInfo.firstStart == 0 && startPos == -1) + startPos = 0; + else if (startPos<0 || (startPos % drawInfo.baseInterval)!=0) + throw std::exception("Ogiltig tid"); + + startPos /= drawInfo.baseInterval; + + int intervalPos = convertAbsoluteTimeMS(intervall); + + if (intervalPos<0 || intervalPos == NOTIME || (intervalPos % drawInfo.baseInterval)!=0) + throw std::exception("Ogiltigt startintervall"); + + intervalPos /= drawInfo.baseInterval; + + if (ci.nVacant != vacant) { + ci.nVacantSpecified = true; + ci.nVacant = vacant; + } + + if (ci.nExtra != reserved) { + ci.nExtraSpecified = true; + ci.nExtra = reserved; + } + // If times has been changed, mark this class to be kept fixed + if (ci.firstStart != startPos || ci.interval!=intervalPos) + ci.hasFixedTime = true; + + ci.firstStart = startPos; + ci.interval = intervalPos; + + drawInfo.classes[ci.classId] = ci; + + cInfoCache[ci.classId] = ci; + cInfoCache[ci.classId].hasFixedTime = false; + } +} + +void TabClass::visualizeField(gdioutput &gdi) { + ClassInfo::sSortOrder = 3; + sort(cInfo.begin(), cInfo.end()); + ClassInfo::sSortOrder = 0; + + vector field; + vector index(cInfo.size(), -1); + + for (size_t k = 0;k < cInfo.size(); k++) { + const ClassInfo &ci = cInfo[k]; + int laststart = ci.firstStart + (ci.nRunners-1) * ci.interval; + + for (size_t j = 0; j < field.size(); j++) { + if (field[j] < ci.firstStart) { + index[k] = j; + field[j] = laststart; + break; + } + } + if (index[k] == -1) { + index[k] = field.size(); + field.push_back(laststart); + } +/* + string first=oe->getAbsTime(ci.firstStart*drawInfo.baseInterval+drawInfo.firstStart); + string last=oe->getAbsTime((laststart)*drawInfo.baseInterval+drawInfo.firstStart); + pClass pc=oe->getClass(ci.classId);*/ + } + + map groupNumber; + map groups; + int freeNumber = 1; + for (size_t k = 0;k < cInfo.size(); k++) { + const ClassInfo &ci = cInfo[k]; + if (!groupNumber.count(ci.unique)) + groupNumber[ci.unique] = freeNumber++; + + pClass pc = oe->getClass(ci.classId); + if (pc) { + if (groups[ci.unique].empty()) + groups[ci.unique] = pc->getName(); + else if (groups[ci.unique].size() < 64) + groups[ci.unique] += ", " + pc->getName(); + else + groups[ci.unique] += "..."; + } + } + + int marg = gdi.scaleLength(20); + int xp = gdi.getCX() + marg; + int yp = gdi.getCY() + marg; + int h = gdi.scaleLength(12); + int w = gdi.scaleLength(6); + int maxx = xp, maxy = yp; + + RECT rc; + for (size_t k = 0;k < cInfo.size(); k++) { + const ClassInfo &ci = cInfo[k]; + rc.top = yp + index[k] * h; + rc.bottom = rc.top + h - 1; + int g = ci.unique; + GDICOLOR color = GDICOLOR(RGB(((g * 30)&0xFF), ((g * 50)&0xFF), ((g * 70)&0xFF))); + for (int j = 0; jgetClass(ci.classId); + if (pc) { + string course = pc->getCourse() ? ", " + pc->getCourse()->getName() : ""; + string tip = "X (Y deltagare, grupp Z, W)#" + pc->getName() + course + "#" + itos(ci.nRunners) + "#" + itos(groupNumber[ci.unique]) + + "#" + groups[ci.unique]; + rc.left = xp + ci.firstStart * w; + int laststart = ci.firstStart + (ci.nRunners-1) * ci.interval; + rc.right = xp + (laststart + 1) * w; + gdi.addToolTip("", tip, 0, &rc); + maxx = max(maxx, rc.right); + maxy = max(maxy, rc.bottom); + } + } + rc.left = xp - marg; + rc.top = yp - marg; + rc.bottom = maxy + marg; + rc.right = maxx + marg; + gdi.addRectangle(rc, colorLightYellow, true, true); + +} + +void TabClass::showClassSettings(gdioutput &gdi) +{ + ClassInfo::sSortOrder = 2; + sort(cInfo.begin(), cInfo.end()); + ClassInfo::sSortOrder=0; + + int laststart=0; + for (size_t k=0;kgetAbsTime(ci.firstStart*drawInfo.baseInterval+drawInfo.firstStart); + string last=oe->getAbsTime((laststart)*drawInfo.baseInterval+drawInfo.firstStart); + pClass pc=oe->getClass(ci.classId); + sprintf_s(bf1, "%s, %d", pc ? pc->getName().c_str(): "-", ci.nRunners); + sprintf_s(bf2, "%d-[%d]-%d (%s-%s)", ci.firstStart, ci.interval, laststart, first.c_str(), last.c_str()); + + gdi.fillRight(); + + int id = ci.classId; + gdi.addString("C" + itos(id), 0, "X platser. Startar Y#" + string(bf1) + "#" + bf2); + y = gdi.getCY(); + gdi.addInput(xp+300, y, "S"+itos(id), first, 7, DrawClassesCB); + gdi.addInput(xp+300+width, y, "I"+itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB); + gdi.addInput(xp+300+width*2, y, "V"+itos(id), itos(ci.nVacant), 7, DrawClassesCB); + gdi.addInput(xp+300+width*3, y, "R"+itos(id), itos(ci.nExtra), 7, DrawClassesCB); + + if (k%5 == 4) + gdi.dropLine(1); + + gdi.dropLine(1.6); + gdi.fillDown(); + gdi.popX(); + } + + gdi.dropLine(); + gdi.pushX(); + + gdi.fillRight(); + + gdi.addButton("VisualizeDraw", "Visualisera startfältet...", ClassesCB); + + gdi.addButton("SaveDrawSettings", "Spara starttider", ClassesCB, + "Spara inmatade tider i tävlingen utan att tilldela starttider."); + + gdi.addButton("DrawAllAdjust", "Ändra inställningar", ClassesCB, + "Ändra grundläggande inställningar och gör en ny fördelning").setExtra(13); + + if (!cInfo.empty()) { + gdi.addButton("DrawAdjust", "Uppdatera fördelning", ClassesCB, + "Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan"); + gdi.disableInput("DrawAdjust"); + } + gdi.popX(); + gdi.dropLine(3); + + gdi.fillRight(); + + if (!cInfo.empty()) { + gdi.pushX(); + + RECT rc; + rc.left = gdi.getCX(); + rc.top = gdi.getCY(); + rc.bottom = rc.top + gdi.getButtonHeight() + gdi.scaleLength(22) + gdi.getLineHeight(); + gdi.setCX(rc.left + gdi.scaleLength(10)); + gdi.setCY(rc.top + gdi.scaleLength(10)); + + gdi.addSelection("Method", 200, 200, 0, "Metod:"); + gdi.addItem("Method", lang.tl("Lottning"), DMRandom); + gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); + + gdi.selectItemByData("Method", getDefaultMethod(false)); + + gdi.addSelection("PairSize", 150, 200, 0, "Tillämpa parstart:"); + gdi.addItem("PairSize", getPairOptions()); + gdi.selectItemByData("PairSize", 1); + + gdi.dropLine(0.9); + + gdi.addButton("DoDrawAll", "Utför lottning", ClassesCB); + + rc.right = gdi.getCX() + gdi.scaleLength(5); + gdi.addRectangle(rc, colorLightGreen); + gdi.setCX(rc.right + gdi.scaleLength(10)); + } + + gdi.addButton("Cancel", "Avbryt", ClassesCB); + + gdi.fillDown(); + gdi.dropLine(2); + gdi.popX(); + + + gdi.fillDown(); + gdi.popX(); + gdi.scrollToBottom(); + gdi.updateScrollbars(); + gdi.refresh(); +} + +void TabClass::selectClass(gdioutput &gdi, int cid) +{ + oe->fillCourses(gdi, "Courses", true); + gdi.addItem("Courses", lang.tl("Ingen bana"), -2); + + if (cid==0) { + gdi.restore("", true); + gdi.disableInput("MultiCourse", true); + gdi.enableInput("Courses"); + gdi.enableEditControls(false); + gdi.setText("Name", ""); + gdi.selectItemByData("Courses", -2); + gdi.check("AllowQuickEntry", true); + + if (gdi.hasField("FreeStart")) + gdi.check("FreeStart", false); + if (gdi.hasField("IgnoreStart")) + gdi.check("IgnoreStart", false); + + if (gdi.hasField("DirectResult")) + gdi.check("DirectResult", false); + + gdi.check("NoTiming", false); + + ClassId=cid; + EditChanged=false; + + gdi.disableInput("Remove"); + gdi.disableInput("Save"); + return; + } + + pClass pc = oe->getClass(cid); + + if (!pc) { + selectClass(gdi, 0); + return; + } + + gdi.enableEditControls(true); + gdi.enableInput("Remove"); + gdi.enableInput("Save"); + + pc->synchronize(); + gdi.setText("Name", pc->getName()); + + gdi.setText("ClassType", pc->getType()); + gdi.setText("StartName", pc->getStart()); + if (pc->getBlock()>0) + gdi.selectItemByData("StartBlock", pc->getBlock()); + else + gdi.selectItemByData("StartBlock", -1); + + if (gdi.hasField("Status")) { + vector< pair > out; + size_t selected = 0; + pc->getDCI().fillInput("Status", out, selected); + gdi.addItem("Status", out); + gdi.selectItemByData("Status", selected); + } + + gdi.check("AllowQuickEntry", pc->getAllowQuickEntry()); + gdi.check("NoTiming", pc->getNoTiming()); + + if (gdi.hasField("FreeStart")) + gdi.check("FreeStart", pc->hasFreeStart()); + + if (gdi.hasField("IgnoreStart")) + gdi.check("IgnoreStart", pc->ignoreStartPunch()); + + if (gdi.hasField("DirectResult")) + gdi.check("DirectResult", pc->hasDirectResult()); + + ClassId=cid; + + if (pc->hasTrueMultiCourse()) { + gdi.restore("", false); + + multiCourse(gdi, pc->getNumStages()); + gdi.refresh(); + + gdi.addItem("Courses", lang.tl("Flera banor"), -3); + gdi.selectItemByData("Courses", -3); + gdi.disableInput("Courses"); + gdi.check("CoursePool", pc->hasCoursePool()); + + if (gdi.hasField("Unordered")) + gdi.check("Unordered", pc->hasUnorderedLegs()); + + if (gdi.hasField("MCourses")) { + oe->fillCourses(gdi, "MCourses", true); + string strId = "StageCourses_expl"; + gdi.setTextTranslate(strId, getCourseLabel(pc->hasCoursePool()), true); + } + + if (gdi.hasData("SimpleMulti")) { + bool hasStart = pc->getStartType(0) == STTime; + + gdi.setInputStatus("CommonStartTime", hasStart); + gdi.check("CommonStart", hasStart); + if (hasStart) + gdi.setText("CommonStartTime", pc->getStartDataS(0)); + else + gdi.setText("CommonStartTime", MakeDash("-")); + + } + else { + updateFairForking(gdi, pc); + + int nstage=pc->getNumStages(); + gdi.setText("NStage", nstage); + + for (int k=0;kgetLegType(k)); + gdi.selectItemByData((string("StartType")+legno).c_str(), pc->getStartType(k)); + updateStartData(gdi, pc, k, false, true); + gdi.setInputStatus(string("Restart")+legno, !pc->restartIgnored(k), true); + gdi.setInputStatus(string("RestartRope")+legno, !pc->restartIgnored(k), true); + + if (gdi.hasField(string("Restart")+legno)) + gdi.setText(string("Restart")+legno, pc->getRestartTimeS(k)); + if (gdi.hasField(string("RestartRope")+legno)) + gdi.setText(string("RestartRope")+legno, pc->getRopeTimeS(k)); + if (gdi.hasField(string("MultiR")+legno)) + gdi.selectItemByData((string("MultiR")+legno).c_str(), pc->getLegRunner(k)); + } + } + } + else { + gdi.restore("", true); + gdi.enableInput("MultiCourse", true); + gdi.enableInput("Courses"); + pCourse pcourse = pc->getCourse(); + gdi.selectItemByData("Courses", pcourse ? pcourse->getId():-2); + } + + gdi.selectItemByData("Classes", cid); + + ClassId=cid; + EditChanged=false; +} + +void TabClass::legSetup(gdioutput &gdi) +{ + gdi.restore("RelaySetup"); + gdi.pushX(); + gdi.fillDown(); + + gdi.addString("", 10, "help:relaysetup"); + gdi.dropLine(); + gdi.addSelection("Predefined", 150, 200, MultiCB, "Fördefinierade tävlingsformer:").ignore(true); + oe->fillPredefinedCmp(gdi, "Predefined"); + if (storedPredefined == oEvent::PredefinedTypes(-1)) { + bool hasPatrol = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol); + bool hasRelay = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Relay); + if (hasRelay) + storedPredefined = oEvent::PRelay; + else if (hasPatrol) + storedPredefined = oEvent::PPatrol; + else + storedPredefined = oEvent::PNoSettings; + } + + gdi.selectItemByData("Predefined", storedPredefined); + + gdi.fillRight(); + gdi.addInput("NStage", storedNStage, 4, MultiCB, "Antal sträckor:").ignore(true); + gdi.addInput("StartTime", storedStart, 6, MultiCB, "Starttid (HH:MM:SS):"); + gdi.popX(); + + bool nleg; + bool start; + oe->setupRelayInfo(storedPredefined, nleg, start); + gdi.setInputStatus("NStage", nleg); + gdi.setInputStatus("StartTime", start); + + gdi.fillRight(); + gdi.dropLine(3); + gdi.addButton("SetNStage", "Verkställ", MultiCB); + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", ClassesCB); + + gdi.popX(); +} + + +void TabClass::multiCourse(gdioutput &gdi, int nLeg) { + currentStage=-1; + + bool simpleView = nLeg==1; + + bool showGuide = (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Relay) || + oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol)) && nLeg==0; + + if (nLeg == 0 && !showGuide) { + pClass pc = oe->getClass(ClassId); + if (pc) { + pc->setNumStages(1); + pc->setStartType(0, STDrawn, false); + pc->forceShowMultiDialog(true); + selectClass(gdi, ClassId); + return; + } + } + + gdi.disableInput("MultiCourse", true); + gdi.setRestorePoint(); + gdi.fillDown(); + gdi.newColumn(); + + + int cx=gdi.getCX(), cy=gdi.getCY(); + gdi.setCX(cx+10); + gdi.setCY(cy+10); + + if (simpleView) { + gdi.addString("", fontMediumPlus, "Gafflade banor"); + } + else { + gdi.addString("", 2, "Flera banor / stafett / patrull / banpool"); + gdi.addString("", 0, "Låt klassen ha mer än en bana eller sträcka"); + gdi.dropLine(); + } + gdi.setRestorePoint("RelaySetup"); + + if (showGuide) { + legSetup(gdi); + RECT rc; + rc.left = cx; + rc.right = gdi.getWidth()+10; + rc.bottom = gdi.getCY()+10; + rc.top = cy; + gdi.addRectangle(rc, colorLightGreen, true, false).set3D(true).setColor2(colorLightCyan); + } + else if (simpleView) { + gdi.fillRight(); + gdi.pushX(); + gdi.setData("SimpleMulti", 1); + gdi.dropLine(); + gdi.addCheckbox("CommonStart", "Gemensam start", MultiCB, false); + //gdi.dropLine(-1); + gdi.addInput("CommonStartTime", "", 10, 0, ""); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(2); + gdi.addCheckbox("CoursePool", "Använd banpool", MultiCB, false, + "Knyt löparna till banor från en pool vid målgång."); + + gdi.addButton("OneCourse", "Endast en bana", MultiCB, "Använd endast en bana i klassen"); + gdi.setRestorePoint("Courses"); + selectCourses(gdi, 0); + + RECT rc; + rc.left = cx; + rc.right = gdi.getWidth()+10; + rc.bottom = gdi.getCY()+10; + rc.top = cy; + gdi.addRectangle(rc, colorLightBlue, true, false).set3D(true); + } + else { + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("ChangeLeg", "Ändra klassinställningar...", MultiCB, "Starta en guide som hjälper dig göra klassinställningar"); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(2); + + gdi.dropLine(0.5); + int headYPos=gdi.getCY(); + gdi.dropLine(1.2); + + vector< pair > legs; + legs.reserve(nLeg); + for (int j=0;jgetMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces); + bool hasRelay = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Relay); + + for (int k=0;k0) + pc=oe->getClass(cid); + else { + pc=oe->addClass(name); + create=true; + } + + if (!pc) + throw std::exception("Class not found."); + + ClassId=pc->getId(); + + pc->setName(name); + if (gdi.hasField("StartName")) + pc->setStart(gdi.getText("StartName")); + + if (gdi.hasField("ClassType")) + pc->setType(gdi.getText("ClassType")); + + if (gdi.hasField("StartBlock")) + pc->setBlock(gdi.getTextNo("StartBlock")); + + if (gdi.hasField("Status")) { + pc->getDI().setEnum("Status", gdi.getSelectedItem("Status").first); + } + + if (gdi.hasField("CoursePool")) + pc->setCoursePool(gdi.isChecked("CoursePool")); + + if (gdi.hasField("Unordered")) + pc->setUnorderedLegs(gdi.isChecked("Unordered")); + + pc->setAllowQuickEntry(gdi.isChecked("AllowQuickEntry")); + pc->setNoTiming(gdi.isChecked("NoTiming")); + + if (gdi.hasField("FreeStart")) + pc->setFreeStart(gdi.isChecked("FreeStart")); + + if (gdi.hasField("IgnoreStart")) + pc->setIgnoreStartPunch(gdi.isChecked("IgnoreStart")); + + if (gdi.hasField("DirectResult")) { + bool withDirect = gdi.isChecked("DirectResult"); + + if (withDirect && !pc->hasDirectResult() && !hasWarnedDirect) { + if (gdi.ask("warning:direct_result")) + hasWarnedDirect = true; + else + withDirect = false; + } + + pc->setDirectResult(withDirect); + } + + int crs = gdi.getSelectedItem("Courses").first; + + if (crs==0) { + //Skapa ny bana... + pCourse pcourse=oe->addCourse("Bana "+name); + pc->setCourse(pcourse); + pc->synchronize(); + return; + } + else if (crs==-2) + pc->setCourse(0); + else if (crs > 0) + pc->setCourse(oe->getCourse(crs)); + + if (pc->hasMultiCourse()) { + + if (gdi.hasData("SimpleMulti")) { + bool sim = gdi.isChecked("CommonStart"); + if (sim) { + pc->setStartType(0, STTime, true); + pc->setStartData(0, gdi.getText("CommonStartTime")); + } + else { + pc->setStartType(0, STDrawn, true); + } + } + else { + int nstage=pc->getNumStages(); + bool needAdjust = false; + for (int k=0;ksetLegType(k, LegTypes(gdi.getSelectedItem(string("LegType")+legno).first)); + + pc->setStartType(k, StartTypes(gdi.getSelectedItem(string("StartType")+legno).first), true); + + if (pc->getStartType(k) == STChange) { + int val = gdi.getSelectedItem(string("StartData")+legno).first; + if (val <= -10) + pc->setStartData(k, val + 10); + else + pc->setStartData(k, 0); + } + else { + pc->setStartData(k, gdi.getText(string("StartData")+legno)); + } + string key; + + key = string("Restart")+legno; + if (gdi.hasField(key)) + pc->setRestartTime(k, gdi.getText(key)); + + key = string("RestartRope")+legno; + + if (gdi.hasField(key)) + pc->setRopeTime(k, gdi.getText(key)); + + key = string("MultiR")+legno; + if (gdi.hasField(key)) { + int mr = gdi.getSelectedItem(key).first; + + if (pc->getLegRunner(k) != mr) + needAdjust = true; + + pc->setLegRunner(k, mr); + } + } + + if (needAdjust) + oe->adjustTeamMultiRunners(pc); + } + } + + pc->addClassDefaultFee(false); + pc->updateChangedCoursePool(); + pc->synchronize(); + oe->reCalculateLeaderTimes(pc->getId()); + set cls; + cls.insert(pc->getId()); + oe->reEvaluateAll(cls, true); + + oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone); + EditChanged=false; + if (!skipReload) { + ClassId = 0; + selectClass(gdi, pc->getId()); + } + + if (checkValid) { + // Check/warn that starts blocks are set up correctly + vector b; + vector s; + oe->getStartBlocks(b, s); + oe->sanityCheck(gdi, false, pc->getId()); + } +} + +struct ButtonData { + ButtonData(const char *idIn, + const char *labelIn, + bool glob) : id(idIn), label(labelIn), global(glob) {} + string id; + string label; + bool global; +}; + +bool TabClass::loadPage(gdioutput &gdi) +{ + oe->checkDB(); + oe->checkNecessaryFeatures(); + gdi.selectTab(tabId); + gdi.clearPage(false); + int xp=gdi.getCX(); + + const int button_w=gdi.scaleLength(90); + string switchMode; + switchMode=tableMode ? "Formulärläge" : "Tabelläge"; + gdi.addButton(2, 2, button_w, "SwitchMode", switchMode, + ClassesCB, "Välj vy", false, false).fixedCorner(); + + if (tableMode) { + Table *tbl=oe->getClassTB(); + gdi.addTable(tbl, xp, 30); + return true; + } + + if (showForkingGuide) { + try { + defineForking(gdi, false); + } + catch(...) { + showForkingGuide = false; + throw; + } + return true; + } + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + + bool showAdvanced = oe->getPropertyInt("AdvancedClassSettings", 0) != 0; + gdi.addString("", boldLarge, "Klasser"); + + gdi.fillDown(); + gdi.addListBox("Classes", 200, showAdvanced ? 512 : 420, ClassesCB, "").isEdit(false).ignore(true); + gdi.setTabStops("Classes", 185); + oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone); + + gdi.newColumn(); + gdi.dropLine(2); + + gdi.fillRight(); + gdi.pushX(); + gdi.addInput("Name", "", 14, ClassesCB, "Klassnamn:"); + bool sameLineNameCourse = true; + if (showAdvanced) { + gdi.addCombo("ClassType", 100, 300, 0, "Typ:"); + oe->fillClassTypes(gdi, "ClassType"); + sameLineNameCourse = false; + } + + if (showMulti(false) || !sameLineNameCourse) { + gdi.dropLine(3); + gdi.popX(); + } + + gdi.addSelection("Courses", 120, 400, ClassesCB, "Bana:"); + oe->fillCourses(gdi, "Courses", true); + gdi.addItem("Courses", lang.tl("Ingen bana"), -2); + + if (showMulti(false)) { + gdi.dropLine(0.9); + if (showMulti(true)) { + gdi.addButton("MultiCourse", "Flera banor/stafett...", ClassesCB); + } + else { + gdi.addButton("MultiCourse", "Gafflade banor...", ClassesCB); + } + gdi.disableInput("MultiCourse"); + } + + gdi.popX(); + if (showAdvanced) { + gdi.dropLine(3); + + gdi.addCombo("StartName", 120, 300, 0, "Startnamn:"); + oe->fillStarts(gdi, "StartName"); + + gdi.addSelection("StartBlock", 80, 300, 0, "Startblock:"); + + for (int k=1;k<=100;k++) { + char bf[16]; + sprintf_s(bf, "%d", k); + gdi.addItem("StartBlock", bf, k); + } + + gdi.popX(); + gdi.dropLine(3); + gdi.addSelection("Status", 200, 300, 0, "Status:"); + } + + gdi.popX(); + gdi.dropLine(3.5); + gdi.addCheckbox("AllowQuickEntry", "Tillåt direktanmälan", 0); + gdi.addCheckbox("NoTiming", "Utan tidtagning", 0); + + if (showAdvanced) { + gdi.dropLine(2); + gdi.popX(); + gdi.addCheckbox("FreeStart", "Fri starttid", 0, false, "Klassen lottas inte, startstämpling"); + gdi.addCheckbox("IgnoreStart", "Ignorera startstämpling", 0, false, "Uppdatera inte starttiden vid startstämpling"); + + gdi.dropLine(2); + gdi.popX(); + + gdi.addCheckbox("DirectResult", "Resultat vid målstämpling", 0, false, + "help:DirectResult"); + + } + gdi.dropLine(2); + gdi.popX(); + + gdi.fillDown(); + gdi.addString("", 1, "Funktioner"); + + vector func; + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList)) + func.push_back(ButtonData("Draw", "Lotta / starttider...", false)); + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Bib)) + func.push_back(ButtonData("Bibs", "Nummerlappar...", false)); + if (cnf.hasTeamClass()) + func.push_back(ButtonData("Restart", "Omstart...", true)); + if (showAdvanced) { + func.push_back(ButtonData("Merge", "Slå ihop klasser...", false)); + func.push_back(ButtonData("Split", "Dela klassen...", false)); + } + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList)) + func.push_back(ButtonData("DrawMode", "Lotta flera klasser", true)); + func.push_back(ButtonData("QuickSettings", "Snabbinställningar", true)); + + if (showAdvanced && oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) { + vector rr; + oe->getRunners(0, 0, rr, false); + bool hasVac = false; + for (size_t k = 0; k < rr.size(); k++) { + if (rr[k]->isVacant()) { + hasVac = true; + break; + } + } + if (hasVac) + func.push_back(ButtonData("RemoveVacant", "Radera vakanser", true)); + } + + gdi.dropLine(0.3); + gdi.pushX(); + gdi.fillRight(); + + for (size_t k = 0; k < func.size(); k++) { + ButtonInfo &bi = gdi.addButton(func[k].id, func[k].label, ClassesCB); + if (!func[k].global) + bi.isEdit(true); + if ( k % 2 == 1) { + gdi.popX(); + gdi.dropLine(2.5); + } + } + + gdi.popX(); + gdi.dropLine(3); + gdi.fillRight(); + gdi.addButton("Save", "Spara", ClassesCB).setDefault(); + gdi.disableInput("Save"); + gdi.addButton("Remove", "Radera", ClassesCB); + gdi.disableInput("Remove"); + gdi.addButton("Add", "Ny klass", ClassesCB); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(3); + gdi.addCheckbox("UseAdvanced", "Visa avancerade funktioner", ClassesCB, showAdvanced).isEdit(false); + + gdi.setOnClearCb(ClassesCB); + gdi.setRestorePoint(); + + gdi.setCX(xp); + gdi.setCY(gdi.getHeight()); + + gdi.addString("", 10, "help:26963"); + + selectClass(gdi, ClassId); + + EditChanged=false; + gdi.refresh(); + + return true; +} + +bool TabClass::showMulti(bool singleOnly) const { + const MeOSFeatures &mf = oe->getMeOSFeatures(); + if (!singleOnly) + return mf.hasFeature(MeOSFeatures::Relay) || mf.hasFeature(MeOSFeatures::Patrol) || mf.hasFeature(MeOSFeatures::ForkedIndividual); + else + return mf.hasFeature(MeOSFeatures::Relay) || mf.hasFeature(MeOSFeatures::Patrol) || mf.hasFeature(MeOSFeatures::MultipleRaces); +} + +static int classSettingsCB(gdioutput *gdi, int type, void *data) +{ + TabClass &tc = dynamic_cast(*gdi->getTabs().get(TClassTab)); + + static string lastStart = "Start 1"; + if (type==GUI_INPUT) { + InputInfo ii=*(InputInfo *)data; + + if (ii.id.substr(0,4) == "Strt") { + lastStart = ii.text; + } + } + else if (type == GUI_FOCUS) { + InputInfo ii=*(InputInfo *)data; + if (ii.id.substr(0,4) == "Strt") { + if (ii.text.empty()) { + gdi->setText(ii.id, lastStart); + gdi->setInputFocus(ii.id, true); + } + } + } + else if (type == GUI_BUTTON) { + ButtonInfo bi = *(ButtonInfo*)data; + if (bi.id == "SaveCS") { + tc.saveClassSettingsTable(*gdi); + } + } + else if (type == GUI_CLEAR) { + tc.saveClassSettingsTable(*gdi); + return 1; + } + return 0; +} + +void TabClass::saveClassSettingsTable(gdioutput &gdi) { + set modifiedFee; + bool modifiedBib = false; + + saveClassSettingsTable(gdi, modifiedFee, modifiedBib); + + oe->synchronize(true); + if (gdi.hasField("BibGap")) { + int gap = gdi.getTextNo("BibGap"); + if (oe->getBibClassGap() != gap) { + oe->setBibClassGap(gap); + modifiedBib = true; + } + } + + if (!modifiedFee.empty() && oe->getNumRunners() > 0) { + bool updateFee = gdi.ask("ask:changedclassfee"); + + if (updateFee) + oe->applyEventFees(false, true, false, modifiedFee); + } + + if (modifiedBib && gdi.ask("Vill du uppdatera alla nummerlappar?")) { + oe->addAutoBib(); + } + oe->synchronize(true); + gdi.sendCtrlMessage("Cancel"); +} + +void TabClass::prepareForDrawing(gdioutput &gdi) { + gdi.clearPage(false); + gdi.addString("", 2, "Klassinställningar"); + int baseLine = gdi.getCY(); + gdi.addString("", 10, "help:59395"); + gdi.pushX(); + + int by = gdi.getCY(); + gdi.setCX(gdi.getWidth()); + gdi.setCY(baseLine); + gdi.addString("", 10, "help:59395_more"); + + gdi.setCY(max(gdi.getCY(), by)); + gdi.popX(); + gdi.dropLine(); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Bib)) { + gdi.fillRight(); + gdi.addString("", 0, "Antal reserverade nummerlappsnummer mellan klasser:"); + gdi.dropLine(-0.1); + gdi.addInput("BibGap", itos(oe->getBibClassGap()), 5); + gdi.popX(); + gdi.dropLine(1.5); + gdi.fillDown(); + } + + getClassSettingsTable(gdi, classSettingsCB); + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("SaveCS", "Spara", classSettingsCB); + gdi.addButton("Cancel", "Avbryt", ClassesCB); + + gdi.refresh(); +} + +void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) { + oe->setProperty("DefaultDrawMethod", method); + + if (lastDrawMethod == method) + return; + + if (lastDrawMethod == DMPursuit && method == DMReversePursuit) + return; + if (lastDrawMethod == DMReversePursuit && method == DMPursuit) + return; + + if (lastDrawMethod == DMRandom && method == DMSOFT) + return; + if (lastDrawMethod == DMSOFT && method == DMRandom) + return; + + int firstStart = 3600, + interval = 120, + vac = atoi(lastNumVac.c_str()); + + int pairSize = lastPairSize; + + if (gdi.hasField("FirstStart")) + firstStart = oe->getRelativeTime(gdi.getText("FirstStart")); + else if (!lastFirstStart.empty()) + firstStart = oe->getRelativeTime(lastFirstStart); + + if (gdi.hasField("Interval")) + interval = convertAbsoluteTimeMS(gdi.getText("Interval")); + else if (!lastInterval.empty()) + interval = convertAbsoluteTimeMS(lastInterval); + + if (gdi.hasField("PairSize")) { + pairSize = gdi.getSelectedItem("PairSize").first; + } + gdi.restore("MultiDayDraw", false); + + const bool multiDay = oe->hasPrevStage(); + + if (method == DMSeeded) { + gdi.addString("", 10, "help:seeding_info"); + gdi.dropLine(1); + gdi.pushX(); + gdi.fillRight(); + ListBoxInfo &seedmethod = gdi.addSelection("SeedMethod", 120, 100, 0, "Seedningskälla:"); + vector< pair > methods; + oClass::getSeedingMethods(methods); + gdi.addItem("SeedMethod", methods); + if (lastSeedMethod == -1) + gdi.selectFirstItem("SeedMethod"); + else + gdi.selectItemByData("SeedMethod", lastSeedMethod); + seedmethod.setSynchData(&lastSeedMethod); + gdi.addInput("SeedGroups", lastSeedGroups, 32, 0, "Seedningsgrupper:", + "Ange en gruppstorlek (som repeteras) eller flera kommaseparerade gruppstorlekar"). + setSynchData(&lastSeedGroups); + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + gdi.addCheckbox("PreventClubNb", "Hindra att deltagare från samma klubb startar på angränsande tider", + 0, lastSeedPreventClubNb).setSynchData(&lastSeedPreventClubNb); + gdi.addCheckbox("ReverseSeedning", "Låt de bästa start först", 0, lastSeedReverse). + setSynchData(&lastSeedReverse); + } + else { + gdi.popX(); + gdi.addString("", 10, "help:41641"); + gdi.dropLine(1); + } + + if (method == DMRandom || method == DMSOFT || method == DMPursuit + || method == DMReversePursuit || method == DMSeeded) { + gdi.addSelection("PairSize", 150, 200, 0, "Tillämpa parstart:").setSynchData(&lastPairSize); + gdi.addItem("PairSize", getPairOptions()); + gdi.selectItemByData("PairSize", pairSize); + } + gdi.fillRight(); + + gdi.addInput("FirstStart", oe->getAbsTime(firstStart), 10, 0, "Första start:").setSynchData(&lastFirstStart); + + if (method == DMPursuit || method == DMReversePursuit) { + gdi.addInput("MaxAfter", lastMaxAfter, 10, 0, "Maxtid efter:", "Maximal tid efter ledaren för att delta i jaktstart").setSynchData(&lastMaxAfter); + gdi.addInput("TimeRestart", oe->getAbsTime(firstStart + 3600), 8, 0, "Första omstartstid:"); + gdi.addInput("ScaleFactor", lastScaleFactor, 8, 0, "Tidsskalning:").setSynchData(&lastScaleFactor); + } + + if (method != DMSimultaneous) + gdi.addInput("Interval", formatTime(interval), 10, 0, "Startintervall (min):").setSynchData(&lastInterval); + + if (method == DMRandom || method == DMSOFT || method == DMClumped) + gdi.addInput("Vacanses", itos(vac), 10, 0, "Antal vakanser:").setSynchData(&lastNumVac); + + if ((method == DMRandom || method == DMSOFT || method == DMSeeded) && pc.getNumStages() > 1 && pc.getClassType() != oClassPatrol) { + gdi.addSelection("Leg", 90, 100, 0, "Sträcka:", "Sträcka att lotta"); + for (unsigned k = 0; k 10) + defaultMethod = getDefaultMethod(hasMulti); + + gdi.selectItemByData("Method", defaultMethod); + + if (gdi.hasField("Vacanses")) { + gdi.setInputStatus("Vacanses", !hasMulti); + gdi.setInputStatus("HandleBibs", !hasMulti); + + if (hasMulti) { + gdi.check("HandleBibs", false); + gdi.setInputStatus("Bib", false); + } + } + + if (gdi.hasField("DoDrawBefore")) { + gdi.setInputStatus("DoDrawBefore", !hasMulti); + gdi.setInputStatus("DoDrawAfter", !hasMulti); + } +} + +void TabClass::pursuitDialog(gdioutput &gdi) { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Jaktstart"); + gdi.dropLine(); + vector cls; + oe->getClasses(cls, true); + + gdi.setRestorePoint("Pursuit"); + + gdi.pushX(); + + gdi.fillRight(); + + gdi.addInput("MaxAfter", formatTime(pSavedDepth), 10, 0, "Maxtid efter:", "Maximal tid efter ledaren för att delta i jaktstart"); + gdi.addInput("TimeRestart", "+" + formatTime(pFirstRestart), 8, 0, "Första omstartstid:", "Ange tiden relativt klassens första start"); + gdi.addInput("Interval", formatTime(pInterval), 8, 0, "Startintervall:", "Ange startintervall för minutstart"); + char bf[32]; + sprintf_s(bf, "%f", pTimeScaling); + gdi.addInput("ScaleFactor", bf, 8, 0, "Tidsskalning:"); + + gdi.dropLine(4); + gdi.popX(); + gdi.fillDown(); + //xxx + //gdi.addCheckbox("Pairwise", "Tillämpa parstart", 0, false); + gdi.addSelection("PairSize", 150, 200, 0, "Tillämpa parstart:"); + gdi.addItem("PairSize", getPairOptions()); + gdi.selectItemByData("PairSize", 1); + + int cx = gdi.getCX(); + int cy = gdi.getCY(); + + const int len5 = gdi.scaleLength(5); + const int len40 = gdi.scaleLength(30); + const int len200 = gdi.scaleLength(200); + + gdi.addString("", cy, cx, 1, "Välj klasser"); + gdi.addString("", cy, cx + len200 + len40, 1, "Första starttid"); + cy += gdi.getLineHeight()*2; + + for (size_t k = 0; k::iterator st = pSettings.find(cls[k]->getId()); + + if (st == pSettings.end()) { + pSettings.insert(make_pair(cls[k]->getId(), PursuitSettings(*cls[k]))); + st = pSettings.find(cls[k]->getId()); + } + + PursuitSettings &ps = st->second; + int fs = cls[k]->getDrawFirstStart(); + if (fs > 0) + ps.firstTime = fs; + + ButtonInfo &bi = gdi.addCheckbox(cx, cy + len5, "PLUse" + itos(k), "", ClassesCB, ps.use); + bi.setExtra(cls[k]->getId()); + gdi.addStringUT(cy, cx + len40, 0, cls[k]->getName(), len200); + + gdi.addInput(cx + len200 + len40, cy, "First" + itos(k), oe->getAbsTime(ps.firstTime), 8); + + if (!ps.use) + gdi.disableInput(("First" + itos(k)).c_str()); + + cy += int(gdi.getLineHeight()*1.8); + } + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("SelectAllNoneP", "Välj alla", ClassesCB).setExtra(1); + gdi.addButton("SelectAllNoneP", "Välj ingen", ClassesCB).setExtra(0); + gdi.popX(); + gdi.dropLine(3); + RECT rc; + rc.left = gdi.getCX(); + rc.top = gdi.getCY(); + rc.bottom = rc.top + gdi.getButtonHeight() + gdi.scaleLength(17); + gdi.setCX(rc.left + gdi.scaleLength(10)); + gdi.setCY(rc.top + gdi.scaleLength(10)); + gdi.addButton("DoPursuit", "Jaktstart", ClassesCB).setDefault().setExtra(1); + gdi.addButton("DoPursuit", "Omvänd jaktstart", ClassesCB).setExtra(2); + + rc.right = gdi.getCX() + gdi.scaleLength(5); + gdi.addRectangle(rc, colorLightGreen); + gdi.setCX(rc.right + gdi.scaleLength(10)); + + gdi.addButton("SavePursuit", "Spara starttider", ClassesCB, "Spara inmatade tider i tävlingen utan att tilldela starttider."); + + gdi.addButton("CancelPursuit", "Återgå", ClassesCB).setCancel(); + gdi.refresh(); +} + + +void TabClass::showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK classesCB) const { + gdi.pushY(); + int cx = gdi.getCX(); + int width = gdi.scaleLength(230); + gdi.addListBox("Classes", 200, 400, classesCB, "Klasser:", "", true); + gdi.setTabStops("Classes", 185); + gdi.fillRight(); + gdi.pushX(); + + gdi.addButton("SelectAll", "Välj allt", ClassesCB, + "Välj alla klasser").isEdit(true); + + gdi.addButton("SelectMisses", "Saknad starttid", ClassesCB, + "Välj klasser där någon löpare saknar starttid").isEdit(true); + + gdi.dropLine(2.3); + gdi.popX(); + + gdi.addButton("SelectUndrawn", "Ej lottade", ClassesCB, + "Välj klasser där alla löpare saknar starttid").isEdit(true); + + gdi.fillDown(); + gdi.addButton("SelectNone", "Välj inget", ClassesCB, + "Avmarkera allt").isEdit(true); + gdi.popX(); + + vector blocks; + vector starts; + oe->getStartBlocks(blocks, starts); + map sstart; + for (size_t k = 0; k < starts.size(); k++) { + sstart.insert(make_pair(starts[k], k)); + } + if (sstart.size() > 1) { + gdi.fillRight(); + int cnt = 0; + for (map::reverse_iterator it = sstart.rbegin(); it != sstart.rend(); ++it) { + if ((cnt & 1)==0 && cnt>0) { + gdi.dropLine(2); + gdi.popX(); + } + string name = it->first; + if (name.empty()) + name = lang.tl("övriga"); + gdi.addButton("SelectStart", "Välj X#" + name, ClassesCB, "").isEdit(true).setExtra(it->second); + cnt++; + } + gdi.dropLine(2.5); + gdi.popX(); + gdi.fillDown(); + } + + oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone); + + by = gdi.getCY()+gdi.getLineHeight(); + bx = gdi.getCX(); + //gdi.newColumn(); + gdi.setCX(cx+width); + gdi.popY(); +} + +void TabClass::enableLoadSettings(gdioutput &gdi) { + if (!gdi.hasField("LoadSettings")) + return; + set sel; + gdi.getSelection("Classes", sel); + bool ok = !sel.empty(); + + gdi.setInputStatus("PrepareDrawAll", ok); + gdi.setInputStatus("EraseStartAll", ok); + ok = false; + for (set::iterator it = sel.begin(); it != sel.end(); ++it) { + pClass pc = oe->getClass(*it); + + if (pc) { + if (pc->getDrawFirstStart() > 0 && pc->getDrawInterval() > 0) { + ok = true; + break; + } + } + } + + gdi.setInputStatus("LoadSettings", ok); +} + + +void TabClass::simultaneous(int classId, string time) { + pClass pc = oe->getClass(classId); + + if (!pc) + throw exception(); + + pc->getNumStages(); + if (pc->getNumStages() == 0) { + pCourse crs = pc->getCourse(); + pc->setNumStages(1); + if (crs) + pc->addStageCourse(0, crs->getId()); + } + + pc->setStartType(0, STTime, false); + pc->setStartData(0, time); + pc->synchronize(true); + pc->forceShowMultiDialog(false); + oe->reCalculateLeaderTimes(pc->getId()); + set cls; + cls.insert(pc->getId()); + oe->reEvaluateAll(cls, true); +} + +const char *TabClass::getCourseLabel(bool pool) { + if (pool) + return "Banpool:"; + else + return "Sträckans banor:"; +} + +void TabClass::selectCourses(gdioutput &gdi, int legNo) { + gdi.restore("Courses", false); + gdi.setRestorePoint("Courses"); + char bf[128]; + pClass pc=oe->getClass(ClassId); + + if (!pc) { + gdi.refresh(); + return; + } + currentStage = legNo; + gdi.dropLine(); + gdi.pushX(); + gdi.fillRight(); + + bool simpleView = pc->getNumStages() == 1; + + if (!simpleView) { + sprintf_s(bf, lang.tl("Banor för %s, sträcka %d").c_str(), pc->getName().c_str(), legNo+1); + gdi.addStringUT(1, bf); + ButtonInfo &bi1 = gdi.addButton("@Course" + itos(legNo-1), "<< Föregående", MultiCB); + if (legNo<=0) + gdi.disableInput(bi1.id.c_str()); + ButtonInfo &bi2 = gdi.addButton("@Course" + itos(legNo+1), "Nästa >>", MultiCB); + if (unsigned(legNo + 1) >= pc->getNumStages()) + gdi.disableInput(bi2.id.c_str()); + gdi.popX(); + gdi.dropLine(2.5); + } + gdi.fillRight(); + int x1=gdi.getCX(); + gdi.addListBox("StageCourses", 180, 200, MultiCB, getCourseLabel(pc->hasCoursePool())).ignore(true); + pc->fillStageCourses(gdi, currentStage, "StageCourses"); + int x2=gdi.getCX(); + gdi.fillDown(); + gdi.addListBox("MCourses", 180, 200, MultiCB, "Banor:").ignore(true); + oe->fillCourses(gdi, "MCourses", true); + + gdi.setCX(x1); + gdi.fillRight(); + + gdi.addButton("MRemove", "Ta bort markerad >>", MultiCB); + gdi.setCX(x2); + gdi.fillDown(); + + gdi.addButton("MAdd", "<< Lägg till", MultiCB); + gdi.setCX(x1); + gdi.refresh(); + if (pc->getNumStages() > 1) + gdi.scrollTo(gdi.getCX(), gdi.getCY()); +} + +void TabClass::updateFairForking(gdioutput &gdi, pClass pc) const { + vector< vector > forks; + vector< vector > forksC; + set< pair > unfairLegs; + + if (pc->checkForking(forksC, forks, unfairLegs)) { + BaseInfo *bi = gdi.setText("FairForking", gdi.getText("FairForking"), false); + TextInfo &text = dynamic_cast(*bi); + text.setColor(colorGreen); + gdi.setText("FairForking", lang.tl("The forking is fair."), true); + } + else { + BaseInfo *bi = gdi.setText("FairForking", gdi.getText("FairForking"), false); + TextInfo &text = dynamic_cast(*bi); + text.setColor(colorRed); + gdi.setText("FairForking", lang.tl("The forking is not fair."), true); + } +} + +void TabClass::defineForking(gdioutput &gdi, bool clearSettings) { + pClass pc = oe->getClass(ClassId); + if (clearSettings) { + forkingSetup.clear(); + forkingSetup.resize(pc->getNumStages()); + } + else if (forkingSetup.size() != pc->getNumStages()) + throw meosException("Internal error"); + + showForkingGuide = true; + gdi.clearPage(false); + int tx = gdi.getCX(); + int ty = gdi.getCY(); + + gdi.dropLine(2); + gdi.pushY(); + gdi.addListBox("AllCourses", 180, 300, 0, "Banor:", "", true); + oe->fillCourses(gdi, "AllCourses", true); + int bxp = gdi.getCX(); + int byp = gdi.getCY(); + gdi.fillDown(); + + gdi.newColumn(); + gdi.popY(); + gdi.addListBox("AllStages", 180, 300, MultiCB, "Legs:", "", true); + int ns = pc->getNumStages(); + + gdi.newColumn(); + gdi.fillDown(); + gdi.popY(); + gdi.addButton("AssignCourses", "Assign selected courses to selected legs", MultiCB); + gdi.disableInput("AssignCourses"); + + gdi.dropLine(); + gdi.addString("", boldText, "Forking setup"); + gdi.dropLine(0.5); + for (int k = 0; k < ns; k++) { + LegTypes lt = pc->getLegType(k); + if (lt != LTIgnore) { + gdi.addString("leg"+ itos(k), 0, "Leg X: Do not modify.#" + itos(k+1)); + gdi.addItem("AllStages", lang.tl("Leg X#" + itos(k+1)), k); + } + } + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("ApplyForking", "Calculate and apply forking", MultiCB); + gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel(); + gdi.disableInput("ApplyForking"); + + gdi.setCX(bxp); + gdi.setCY(byp); + gdi.fillDown(); + gdi.addButton("ClearCourses", "Clear selections", MultiCB); + + gdi.addString("", 10, "help:assignforking"); + gdi.addString("", ty, tx, boldLarge, "Assign courses and apply forking to X#" + pc->getName()); + + if (!clearSettings) + gdi.sendCtrlMessage("AssignCourses"); + + gdi.refresh(); +} + +void TabClass::getClassSettingsTable(gdioutput &gdi, GUICALLBACK cb) { + + vector cls; + oe->getClasses(cls, true); + + int yp = gdi.getCY(); + int a = gdi.scaleLength(160); + int b = gdi.scaleLength(250); + int c = gdi.scaleLength(300); + int d = gdi.scaleLength(350); + int e = gdi.scaleLength(510); + int et = gdi.scaleLength(605); + int f = gdi.scaleLength(510); + int g = gdi.scaleLength(535); + + int ek1 = 0, ekextra = 0; + bool useEco = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy); + + gdi.setOnClearCb(cb); + + if (useEco) { + ek1 = gdi.scaleLength(70); + ekextra = gdi.scaleLength(35); + d += 4 * ek1 + ekextra; + e += 4 * ek1 + ekextra; + et += 4 * ek1 + ekextra; + f += 4 * ek1 + ekextra; + g += 4 * ek1 + ekextra; + + gdi.addString("", yp, c+ek1, 1, "Avgift"); + gdi.addString("", yp, c+2*ek1, 1, "Sen avgift"); + gdi.addString("", yp, c+3*ek1, 1, "Red. avgift"); + gdi.addString("", yp, c+4*ek1, 1, "Sen red. avgift"); + } + + gdi.addString("", yp, gdi.getCX(), 1, "Klass"); + gdi.addString("", yp, a, 1, "Start"); + gdi.addString("", yp, b, 1, "Block"); + gdi.addString("", yp, c, 1, "Index"); + gdi.addString("", yp, d, 1, "Bana"); + + const bool useBibs = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Bib); + const bool useTeam = oe->hasTeam(); + + vector< pair > bibOptions; + vector< pair > bibTeamOptions; + + if (useBibs) { + gdi.addString("", yp, e, 1, "Nummerlapp"); + bibOptions.push_back(make_pair(lang.tl("Manuell"), 0)); + bibOptions.push_back(make_pair(lang.tl("Löpande"), 1)); + bibOptions.push_back(make_pair(lang.tl("Ingen"), 2)); + + int bibW = gdi.scaleLength(100); + + if (useTeam) { + gdi.addString("", yp, et, 1, "Lagmedlem"); + + bibTeamOptions.push_back(make_pair(lang.tl("Oberoende"), BibFree)); + bibTeamOptions.push_back(make_pair(lang.tl("Samma"), BibSame)); + bibTeamOptions.push_back(make_pair(lang.tl("Ökande"), BibAdd)); + bibTeamOptions.push_back(make_pair(lang.tl("Sträcka"), BibLeg)); + bibW += gdi.scaleLength(85); + } + + f += bibW; + g += bibW; + } + + gdi.addString("", yp, f, 1, "Direktanmälan"); + + vector< pair > arg; + oe->fillCourses(arg, true); + + for (size_t k = 0; k < cls.size(); k++) { + pClass it = cls[k]; + int yp = gdi.getCY(); + string id = itos(it->getId()); + gdi.addStringUT(0, it->getName(), 0); + gdi.addInput(a, yp, "Strt"+id, it->getStart(), 7, cb); + string blk = it->getBlock()>0 ? itos(it->getBlock()) : ""; + gdi.addInput(b, yp, "Blck"+id, blk, 4); + gdi.addInput(c, yp, "Sort"+id, itos(it->getDCI().getInt("SortIndex")), 4); + + if (useEco) { + gdi.addInput(c + ek1, yp, "Fee"+id, oe->formatCurrency(it->getDCI().getInt("ClassFee")), 5); + gdi.addInput(c + 2*ek1, yp, "LateFee"+id, oe->formatCurrency(it->getDCI().getInt("HighClassFee")), 5); + gdi.addInput(c + 3*ek1, yp, "RedFee"+id, oe->formatCurrency(it->getDCI().getInt("ClassFeeRed")), 5); + gdi.addInput(c + 4*ek1, yp, "RedLateFee"+id, oe->formatCurrency(it->getDCI().getInt("HighClassFeeRed")), 5); + } + + string crs = "Cors"+id; + gdi.addSelection(d, yp, crs, 150, 400); + + if (it->hasTrueMultiCourse()) { + gdi.addItem(crs, lang.tl("Flera banor"), -5); + gdi.selectItemByData(crs.c_str(), -5); + gdi.disableInput(crs.c_str()); + } + else { + gdi.addItem(crs, arg); + gdi.selectItemByData(crs.c_str(), it->getCourseId()); + } + + if (useBibs) { + gdi.addCombo(e, yp, "Bib" + id, 90, 100, 0, "", "Ange löpande numrering eller första nummer i klassen."); + gdi.addItem("Bib" + id, bibOptions); + + string bib = it->getDCI().getString("Bib"); + AutoBibType bt = it->getAutoBibType(); + if (bt != AutoBibExplicit) + gdi.selectItemByData("Bib"+ id, bt); + else + gdi.setText("Bib"+ id, bib); + + if (useTeam && it->getNumDistinctRunners() > 1) { + gdi.addSelection(et, yp, "BibTeam" + id, 80, 100, 0, "", "Ange relation mellan lagets och deltagarnas nummerlappar."); + gdi.addItem("BibTeam" + id, bibTeamOptions); + gdi.selectItemByData("BibTeam" + id, it->getBibMode()); + } + } + + gdi.addCheckbox(g, yp, "Dirc"+id, " ", 0, it->getAllowQuickEntry()); + + gdi.dropLine(-0.3); + + } +} + +void TabClass::saveClassSettingsTable(gdioutput &gdi, set &classModifiedFee, bool &modifiedBib) { + vector cls; + oe->getClasses(cls, true); + classModifiedFee.clear(); + modifiedBib = false; + + for (size_t k = 0; k < cls.size(); k++) { + pClass it = cls[k]; + + string id = itos(it->getId()); + string start = gdi.getText("Strt"+id); + int block = gdi.getTextNo("Blck"+id); + int sort = gdi.getTextNo("Sort"+id); + + if (gdi.hasField("Fee" + id)) { + int fee = oe->interpretCurrency(gdi.getText("Fee"+id)); + int latefee = oe->interpretCurrency(gdi.getText("LateFee"+id)); + int feered = oe->interpretCurrency(gdi.getText("RedFee"+id)); + int latefeered = oe->interpretCurrency(gdi.getText("RedLateFee"+id)); + + int oFee = it->getDCI().getInt("ClassFee"); + int oLateFee = it->getDCI().getInt("HighClassFee"); + int oFeeRed = it->getDCI().getInt("ClassFeeRed"); + int oLateFeeRed = it->getDCI().getInt("HighClassFeeRed"); + + if (oFee != fee || oLateFee != latefee || + oFeeRed != feered || oLateFeeRed != latefeered) + classModifiedFee.insert(it->getId()); + + it->getDI().setInt("ClassFee", fee); + it->getDI().setInt("HighClassFee", latefee); + it->getDI().setInt("ClassFeeRed", feered); + it->getDI().setInt("HighClassFeeRed", latefeered); + } + + if (gdi.hasField("Bib" + id)) { + ListBoxInfo lbi; + bool mod = false; + if (gdi.getSelectedItem("Bib" + id, lbi)) { + mod = it->getDI().setString("Bib", getBibCode(AutoBibType(lbi.data), "1")); + } + else { + const string &v = gdi.getText("Bib" + id); + mod = it->getDI().setString("Bib", v); + } + modifiedBib |= mod; + + if (gdi.hasField("BibTeam" + id)) { + ListBoxInfo lbi; + if (gdi.getSelectedItem("BibTeam" + id, lbi)) { + if (it->getBibMode() != lbi.data) + modifiedBib = true; + it->setBibMode(BibMode(lbi.data)); + } + } + } + + int courseId = 0; + ListBoxInfo lbi; + if (gdi.getSelectedItem("Cors"+id, lbi)) + courseId = lbi.data; + bool direct = gdi.isChecked("Dirc"+id); + + it->setStart(start); + it->setBlock(block); + if (courseId != -5) + it->setCourse(oe->getCourse(courseId)); + it->getDI().setInt("SortIndex", sort); + it->setAllowQuickEntry(direct); + } +} + +string TabClass::getBibCode(AutoBibType bt, const string &key) { + if (bt == AutoBibManual) + return ""; + else if (bt == AutoBibConsecutive) + return "*"; + else if (bt == AutoBibNone) + return "-"; + else + return key; +} + +void TabClass::updateStartData(gdioutput &gdi, pClass pc, int leg, bool updateDependent, bool forceWrite) { + string sdKey = "StartData"+itos(leg); + + BaseInfo &sdataBase = gdi.getBaseInfo(sdKey.c_str()); + StartTypes st = pc->getStartType(leg); + + if (st == STChange) { + if (typeid(sdataBase) != typeid(ListBoxInfo)) { + InputInfo sdII = dynamic_cast(sdataBase); + gdi.removeControl(sdKey); + gdi.addSelection(sdII.getX(), sdII.getY(), sdKey, sdII.getWidth(), 200, MultiCB); + setParallelOptions(sdKey, gdi, pc, leg); + } + else if (forceWrite) { + setParallelOptions(sdKey, gdi, pc, leg); + } + } + else { + if (typeid(sdataBase) != typeid(InputInfo)) { + ListBoxInfo sdLBI = dynamic_cast(sdataBase); + gdi.removeControl(sdKey); + string val = "-"; + gdi.addInput(sdLBI.getX(), sdLBI.getY(), sdKey, pc->getStartDataS(leg), 8, MultiCB); + } + else if (forceWrite) { + gdi.setText(sdKey, pc->getStartDataS(leg), true); + } + gdi.setInputStatus(sdKey, !pc->startdataIgnored(leg)); + } + + if (updateDependent) { + for (size_t j = 0; j < pc->getNumStages(); j++) { + if (j != leg && pc->getStartType(leg) == STChange) { + setParallelOptions("StartData"+itos(j), gdi, pc, j); + } + } + } +} + +void TabClass::setParallelOptions(const string &sdKey, gdioutput &gdi, pClass pc, int legno) { + int baseLeg = legno; + while (baseLeg > 0 && pc->isParallel(baseLeg)) + baseLeg--; + baseLeg--; + int sd = pc->getStartData(legno); + + vector< pair > opt; + int defKey = 0; + opt.push_back(make_pair(lang.tl("Ordnat"), 0)); + for (int k = 0; k <= baseLeg; k++) { + if (!pc->isOptional(k)) { + opt.push_back(make_pair(lang.tl("Str. X#" + itos(k+1)), (k-legno) - 10)); + if (sd == k-legno) + defKey = sd - 10; + } + } + if (defKey == 0) { + pc->setStartData(legno, 0); + } + + gdi.addItem(sdKey, opt); + gdi.selectItemByData(sdKey, defKey); +} + +void TabClass::updateSplitDistribution(gdioutput &gdi, int num, int tot) const { + gdi.restore("SplitDistr", false); + gdi.setRestorePoint("SplitDistr"); + + vector distr; + + for (int k = 0; k < num; k++) { + int frac = tot / (num-k); + + distr.push_back(frac); + tot -= frac; + } + sort(distr.rbegin(), distr.rend()); + + gdi.dropLine(); + gdi.fillDown(); + gdi.pushX(); + for (size_t k = 0; k < distr.size(); k++) { + int yp = gdi.getCY(); + int xp = gdi.getCX(); + gdi.addString("", yp, xp, 0, "Klass X:#" + itos(k+1)); + gdi.addInput(xp + gdi.scaleLength(100), yp, "CLS" + itos(k), itos(distr[k]), 4); + gdi.popX(); + } + + gdi.dropLine(1.5); + gdi.fillRight(); + gdi.popX(); + gdi.addButton("DoSplit", "Dela", ClassesCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel(); + gdi.popX(); + + gdi.refresh(); +} + +DrawMethod TabClass::getDefaultMethod(bool allowPursuit) const { + int dm = oe->getPropertyInt("DefaultDrawMethod", DMSOFT); + if (!allowPursuit) { + if (dm == DMRandom) + return DMRandom; + else + return DMSOFT; + } + else { + switch (dm) { + case DMRandom: + return DMRandom; + case DMPursuit: + return DMPursuit; + case DMReversePursuit: + return DMReversePursuit; + case DMSeeded: + return DMSeeded; + default: + return DMSOFT; + } + } +} + +vector< pair > TabClass::getPairOptions() { + vector< pair > res; + + res.push_back(make_pair(lang.tl("Ingen parstart"), 1)); + res.push_back(make_pair(lang.tl("Parvis (två och två)"), 2)); + for (int j = 3; j <= 10; j++) { + res.push_back(make_pair(lang.tl("X och Y[N by N]#" + itos(j) + "#" + itos(j)), j)); + } + return res; +} + +void TabClass::readDrawInfo(gdioutput &gdi, DrawInfo &drawInfo) { + drawInfo.maxCommonControl = gdi.getSelectedItem("MaxCommonControl").first; + + drawInfo.maxVacancy=gdi.getTextNo("VacancesMax"); + drawInfo.minVacancy=gdi.getTextNo("VacancesMin"); + drawInfo.vacancyFactor = 0.01*atof(gdi.getText("Vacances").c_str()); + drawInfo.extraFactor = 0.01*atof(gdi.getText("Extra").c_str()); + + drawInfo.baseInterval=convertAbsoluteTimeMS(gdi.getText("BaseInterval")); + drawInfo.allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours"); + drawInfo.coursesTogether = gdi.isChecked("CoursesTogether"); + drawInfo.minClassInterval = convertAbsoluteTimeMS(gdi.getText("MinInterval")); + drawInfo.maxClassInterval = convertAbsoluteTimeMS(gdi.getText("MaxInterval")); + drawInfo.nFields = gdi.getTextNo("nFields"); + drawInfo.firstStart = oe->getRelativeTime(gdi.getText("FirstStart")); +} + +void TabClass::writeDrawInfo(gdioutput &gdi, const DrawInfo &drawInfo) { + gdi.selectItemByData("MaxCommonControl", drawInfo.maxCommonControl); + + gdi.setText("VacancesMax", drawInfo.maxVacancy); + gdi.setText("VacancesMin", drawInfo.minVacancy); + gdi.setText("Vacances", itos(int(drawInfo.vacancyFactor *100.0)) + "%"); + gdi.setText("Extra", itos(int(drawInfo.extraFactor * 100.0) ) + "%"); + + gdi.setText("BaseInterval", formatTime(drawInfo.baseInterval)); + + gdi.check("AllowNeighbours", drawInfo.allowNeighbourSameCourse); + gdi.check("CoursesTogether", drawInfo.coursesTogether); + gdi.setText("MinInterval", formatTime(drawInfo.minClassInterval)); + gdi.setText("MaxInterval", formatTime(drawInfo.maxClassInterval)); + gdi.setText("nFields", drawInfo.nFields); + gdi.setText("FirstStart", oe->getAbsTime(drawInfo.firstStart)); +} diff --git a/code/TabClass.h b/code/TabClass.h new file mode 100644 index 0000000..704f93d --- /dev/null +++ b/code/TabClass.h @@ -0,0 +1,161 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "tabbase.h" +#include "oEventDraw.h" + +class TabClass : + public TabBase +{ + struct PursuitSettings { + bool use; + int firstTime; + int maxTime; + + PursuitSettings(oClass &c) { + firstTime = 3600; + use = c.interpretClassType() != ctOpen; + maxTime = 3600; + } + }; + + map pSettings; + int pSavedDepth; + int pFirstRestart; + double pTimeScaling; + int pInterval; + + + class HandleCloseWindow : public GuiHandler { + TabClass *tabClass; + HandleCloseWindow(const HandleCloseWindow&); + HandleCloseWindow &operator=(const HandleCloseWindow&); + public: + HandleCloseWindow() : tabClass(0) {} + void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type); + friend class TabClass; + }; + HandleCloseWindow handleCloseWindow; + + + bool EditChanged; + int ClassId; + int currentStage; + string storedNStage; + string storedStart; + oEvent::PredefinedTypes storedPredefined; + bool showForkingGuide; + + bool checkClassSelected(const gdioutput &gdi) const; + void save(gdioutput &gdi, bool skipReload); + void legSetup(gdioutput &gdi); + vector cInfo; + + map cInfoCache; + + DrawInfo drawInfo; + void setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaultMethod); + void drawDialog(gdioutput &gdi, DrawMethod method, const oClass &cls); + + void pursuitDialog(gdioutput &gdi); + + bool hasWarnedDirect; + bool tableMode; + DrawMethod lastDrawMethod; + int lastSeedMethod; + bool lastSeedPreventClubNb; + bool lastSeedReverse; + string lastSeedGroups; + int lastPairSize; + string lastFirstStart; + string lastInterval; + string lastNumVac; + string lastScaleFactor; + string lastMaxAfter; + + bool lastHandleBibs; + // Generate a table with class settings + void showClassSettings(gdioutput &gdi); + + void visualizeField(gdioutput &gdi); + + // Read input from the table with class settings + void readClassSettings(gdioutput &gdi); + + // Prepare for drawing by declaring starts and blocks + void prepareForDrawing(gdioutput &gdi); + + void showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK classesCB) const; + + // Set simultaneous start in a class + void simultaneous(int classId, string time); + + void updateFairForking(gdioutput &gdi, pClass pc) const; + void selectCourses(gdioutput &gdi, int legNo); + bool showMulti(bool singleOnly) const; + + void defineForking(gdioutput &gdi, bool clearSettings); + vector< vector > forkingSetup; + static const char *getCourseLabel(bool pool); + + void getClassSettingsTable(gdioutput &gdi, GUICALLBACK cb); + void saveClassSettingsTable(gdioutput &gdi, set &classModifiedFee, bool &modifiedBib); + + static string getBibCode(AutoBibType bt, const string &key); + + void setParallelOptions(const string &sdKey, gdioutput &gdi, pClass pc, int legno); + + void updateStartData(gdioutput &gdi, pClass pc, int leg, bool updateDependent, bool forceWrite); + + void updateSplitDistribution(gdioutput &gdi, int numInClass, int tot) const; + + DrawMethod getDefaultMethod(bool allowPursuit) const; + + void enableLoadSettings(gdioutput &gdi); + + void readDrawInfo(gdioutput &gdi, DrawInfo &drawInfo); + void writeDrawInfo(gdioutput &gdi, const DrawInfo &drawInfo); + + static vector< pair > getPairOptions(); +public: + + void clearCompetitionData(); + + void closeWindow(gdioutput &gdi); + + void saveClassSettingsTable(gdioutput &gdi); + void multiCourse(gdioutput &gdi, int nLeg); + bool loadPage(gdioutput &gdi); + void selectClass(gdioutput &gdi, int cid); + + int classCB(gdioutput &gdi, int type, void *data); + int multiCB(gdioutput &gdi, int type, void *data); + + const char * getTypeStr() const {return "TClassTab";} + TabType getType() const {return TClassTab;} + + friend int DrawClassesCB(gdioutput *gdi, int type, void *data); + + TabClass(oEvent *oe); + ~TabClass(void); +}; diff --git a/code/TabClub.cpp b/code/TabClub.cpp new file mode 100644 index 0000000..0b3bc5e --- /dev/null +++ b/code/TabClub.cpp @@ -0,0 +1,786 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Stigbergsvägen 11, SE-75242 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include +#include "meos_util.h" +#include "Table.h" +#include "gdifonts.h" +#include "meosexception.h" +#include "MeOSFeatures.h" + +#include "TabCompetition.h" +#include "TabClub.h" +#include "TabList.h" + +#include "csvparser.h" +#include "pdfwriter.h" + + +TabClub::TabClub(oEvent *poe):TabBase(poe) +{ + baseFee = 0; + lowAge = 0; + highAge = 0; + filterAge = false; + onlyNoFee = false; + useManualFee = false; +} + +TabClub::~TabClub(void) +{ +} + +void TabClub::readFeeFilter(gdioutput &gdi) { + baseFee = oe->interpretCurrency(gdi.getText("BaseFee")); + firstDate = gdi.getText("FirstDate"); + lastDate = gdi.getText("LastDate"); + filterAge = gdi.isChecked("FilterAge"); + useManualFee = gdi.isChecked("DefaultFees"); + if (filterAge) { + highAge = gdi.getTextNo("HighLimit"); + lowAge = gdi.getTextNo("LowLimit"); + } + + onlyNoFee = gdi.isChecked("OnlyNoFee"); + + ListBoxInfo lbi; + gdi.getSelectedItem("ClassType", lbi); + + if (lbi.data == -5) + typeS = "*"; + else if (lbi.data > 0) + typeS = "::" + itos(lbi.data); + else + typeS = lbi.text; + +} + +void TabClub::selectClub(gdioutput &gdi, pClub pc) +{ + if (pc) { + pc->synchronize(); + ClubId = pc->getId(); + } + else{ + ClubId = 0; + } +} + +void manualFees(gdioutput &gdi, bool on) { + gdi.setInputStatus("BaseFee", on); + gdi.setInputStatus("FirstDate", on); + gdi.setInputStatus("LastDate", on); +} + +void ageFilter(gdioutput &gdi, bool on, bool use) { + gdi.setInputStatus("HighLimit", on & use); + gdi.setInputStatus("LowLimit", on & use); + gdi.setInputStatus("FilterAge", use); +} + +int ClubsCB(gdioutput *gdi, int type, void *data) +{ + TabClub &tc = dynamic_cast(*gdi->getTabs().get(TClubTab)); + return tc.clubCB(*gdi, type, data); +} + +int TabClub::clubCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="Save") { + } + else if (bi.id == "EraseClubs") { + if (gdi.ask("Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa.")) { + oClub::clearClubs(*oe); + } + } + else if (bi.id=="Invoice") { + ListBoxInfo lbi; + gdi.getSelectedItem("Clubs", lbi); + pClub pc=oe->getClub(lbi.data); + if (pc) { + gdi.clearPage(true); + oe->calculateTeamResults(false); + oe->sortTeams(ClassStartTime, 0, true); + oe->calculateResults(oEvent::RTClassResult); + oe->sortRunners(ClassStartTime); + int pay, paid; + { + map ppm; + map dpm; + oClub::definedPayModes(*oe, dpm); + pc->generateInvoice(gdi, pay, paid, dpm, ppm); + } + gdi.addButton(gdi.getWidth()+20, 15, gdi.scaleLength(120), + "Cancel", "Återgå", ClubsCB, "", true, false); + gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(120), + "Print", "Skriv ut...", ClubsCB, + "Skriv ut fakturan", true, false); + gdi.addButton(gdi.getWidth()+20, 75, gdi.scaleLength(120), + "PDF", "PDF...", ClubsCB, + "Spara som PDF.", true, false); + gdi.refresh(); + } + } + else if (bi.id=="AllInvoice") { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Skapa fakturor"); + + gdi.addSelection("Type", 300, 100, 0, "Val av export:"); + + gdi.addItem("Type", lang.tl("Skriv ut alla"), oEvent::IPTAllPrint); + gdi.addItem("Type", lang.tl("Exportera alla till HTML"), oEvent::IPTAllHTML); + gdi.addItem("Type", lang.tl("Exportera alla till PDF"), oEvent::IPTAllPDF); + +#ifdef _DEBUG + gdi.addItem("Type", lang.tl("Skriv ut dem utan e-post"), oEvent::IPTNoMailPrint); + gdi.addItem("Type", lang.tl("Skriv ut ej accepterade elektroniska"), oEvent::IPTNonAcceptedPrint); + gdi.addItem("Type", lang.tl("Exportera elektroniska fakturor"), oEvent::IPTElectronincHTML); +#endif + gdi.selectFirstItem("Type"); + gdi.fillRight(); + gdi.pushX(); + gdi.addButton("DoAllInvoice", "Skapa fakturor", ClubsCB); +#ifdef _DEBUG + gdi.addButton("ImportAnswer", "Hämta svar om elektroniska fakturor", ClubsCB); +#endif + gdi.addButton("Cancel", "Avbryt", ClubsCB); + gdi.refresh(); + } + else if (bi.id=="DoAllInvoice") { + ListBoxInfo lbi; + gdi.getSelectedItem("Type", lbi); + string path; + if (lbi.data > 10) + path = gdi.browseForFolder(path, 0); + gdi.clearPage(false); + + oe->printInvoices(gdi, oEvent::InvoicePrintType(lbi.data), path, false); + + gdi.addButton(gdi.getWidth()+20, 15, gdi.scaleLength(120), + "Cancel", "Återgå", ClubsCB, "", true, false); + + if (lbi.data>10) { // To file + gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(120), + "Print", "Skriv ut...", ClubsCB, + "", true, false); + gdi.addButton(gdi.getWidth()+20, 75, gdi.scaleLength(120), + "PDF", "PDF...", ClubsCB, + "Spara som PDF.", true, false); + gdi.refresh(); + } + else { + gdi.refresh(); + gdi.print(oe, 0, false, false); + } + } + else if (bi.id=="ImportAnswer") { + vector< pair > ft; + ft.push_back(make_pair("Textfiler", "*.txt")); + string file = gdi.browseForOpen(ft, "txt"); + if (!file.empty()) { + gdi.clearPage(true); + try { + importAcceptedInvoice(gdi, file); + } + catch (std::exception &ex) { + gdi.addString("", 0, ex.what()).setColor(colorRed); + } + gdi.addButton("Cancel", "OK", ClubsCB); + } + } + else if (bi.id=="UpdateAll") { + oe->updateClubsFromDB(); + gdi.getTable().update(); + gdi.refresh(); + } + else if (bi.id=="UpdateAllRunners") { + oe->updateClubsFromDB(); + oe->updateRunnersFromDB(); + gdi.getTable().update(); + gdi.refresh(); + } + else if (bi.id=="Update") { + pClub pc=oe->getClub(gdi.getSelectedItem("Clubs").first); + if (pc) { + pc->updateFromDB(); + pc->synchronize(); + gdi.getTable().update(); + gdi.refresh(); + } + } + else if (bi.id=="Summary") { + gdi.clearPage(false); + string nn; + oe->printInvoices(gdi, oEvent::IPTAllPrint, nn, true); + gdi.addButton(gdi.getWidth()+20, 15, gdi.scaleLength(120), "Cancel", + "Återgå", ClubsCB, "", true, false); + gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(120), "Print", + "Skriv ut...", ClubsCB, "Skriv ut fakturan", true, false); + + gdi.refresh(); + } + else if (bi.id=="Merge") { + ClubId = gdi.getSelectedItem("Clubs").first; + pClub pc = oe->getClub(ClubId); + if (pc) { + gdi.clearPage(false); + gdi.addString("", boldText, "Slå ihop klubb"); + + char bf[256]; + sprintf_s(bf, lang.tl("help:12352").c_str(), pc->getName().c_str(), pc->getId()); + + gdi.addStringUT(10, bf); + + gdi.addSelection("NewClub", 200, 300, 0, "Ny klubb:"); + oe->fillClubs(gdi, "NewClub"); + gdi.selectItemByData("NewClub", pc->getId()); + gdi.removeSelected("NewClub"); + + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("DoMerge", "Slå ihop", ClubsCB); + gdi.addButton("Cancel", "Avbryt", ClubsCB); + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(2); + gdi.addStringUT(boldText, lang.tl("Klubb att ta bort: ") + pc->getName()); + oe->viewClubMembers(gdi, pc->getId()); + + gdi.refresh(); + } + } + else if (bi.id=="DoMerge") { + pClub pc1 = oe->getClub(ClubId); + pClub pc2 = oe->getClub(gdi.getSelectedItem("NewClub").first); + + if (pc1==pc2) + throw std::exception("En klubb kan inte slås ihop med sig själv."); + + if (pc1 && pc2) + oe->mergeClub(pc2->getId(), pc1->getId()); + loadPage(gdi); + } + else if (bi.id == "InvoiceSettings") { + gdi.clearPage(true); + gdi.addString("", boldLarge, "Fakturainställningar"); + gdi.dropLine(); + firstInvoice = oClub::getFirstInvoiceNumber(*oe); + if (firstInvoice == 0) + firstInvoice = oe->getPropertyInt("FirstInvoice", 1000); + + gdi.addInput("FirstInvoice", itos(firstInvoice), 5, 0, "Första fakturanummer:"); + + gdi.dropLine(); + gdi.addString("", boldText, "Organisatör"); + + vector fields; + gdi.pushY(); + fields.push_back("Organizer"); + fields.push_back("CareOf"); + fields.push_back("Street"); + fields.push_back("Address"); + fields.push_back("EMail"); + oe->getDI().buildDataFields(gdi, fields); + + gdi.dropLine(); + gdi.addString("", boldText, "Betalningsinformation"); + fields.clear(); + fields.push_back("Account"); + fields.push_back("PaymentDue"); + oe->getDI().buildDataFields(gdi, fields); + + gdi.pushX(); + gdi.fillRight(); + gdi.addString("", normalText, "Avgifter och valuta ställer du in under"); + gdi.addString("CmpSettings", normalText, "Tävlingsinställningar.", ClubsCB); + gdi.fillDown(); + gdi.dropLine(2); + gdi.popX(); + + gdi.addString("", boldText, "Formatering"); + + gdi.fillRight(); + gdi.addString("", 0, "Koordinater (mm) för adressfält:"); + string xc = oe->getPropertyString("addressxpos", "125"); + string yc = oe->getPropertyString("addressypos", "50"); + gdi.addStringUT(0, "x:"); + gdi.addInput("XC", xc + " [mm]", 6); + gdi.addStringUT(0, "y:"); + gdi.addInput("YC", yc + " [mm]", 6); + + gdi.fillDown(); + gdi.popX(); + + TabList::customTextLines(*oe, "IVExtra", gdi); + + gdi.dropLine(1); + + gdi.fillRight(); + gdi.addButton("SaveSettings", "Spara", ClubsCB); + gdi.addButton("Cancel", "Avbryt", ClubsCB); + gdi.dropLine(2); + gdi.setOnClearCb(ClubsCB); + oe->getDI().fillDataFields(gdi); + + } + else if (bi.id == "SaveSettings") { + oe->getDI().saveDataFields(gdi); + + TabList::saveExtraLines(*oe, "IVExtra", gdi); + + int fn = gdi.getTextNo("FirstInvoice"); + + if (fn != firstInvoice && oClub::getFirstInvoiceNumber(*oe) > 0) { + if (gdi.ask("Tilldela nya fakturanummer till alla klubbar?")) { + oe->setProperty("FirstInvoice", fn); + oClub::assignInvoiceNumber(*oe, true); + } + } + else + oe->setProperty("FirstInvoice", fn); + + int xc = gdi.getTextNo("XC"); + int yc = gdi.getTextNo("YC"); + + if (xc<=0 || yc<=0) + throw meosException("Invalid coordinate (x,y)"); + + oe->setProperty("addressxpos", xc); + oe->setProperty("addressypos", yc); + loadPage(gdi); + } + else if (bi.id == "Fees") { + gdi.clearPage(true); + + gdi.addString("", boldLarge, "Tilldela avgifter"); + + gdi.dropLine(); + gdi.addString("", 10, "help:assignfee"); + gdi.dropLine(); + gdi.pushX(); + + gdi.addSelection("ClassType", 150, 300, 0, "Klass / klasstyp:"); + vector< pair > types; + vector< pair > classes; + + oe->fillClassTypes(types); + oe->fillClasses(classes, oEvent::extraNone, oEvent::filterNone); + types.insert(types.end(), classes.begin(), classes.end()); + gdi.addItem("ClassType", types); + gdi.addItem("ClassType", lang.tl("Alla typer"), -5); + + gdi.selectItemByData("ClassType", -5); + + gdi.fillRight(); + gdi.dropLine(2); + gdi.addCheckbox("DefaultFees", "Manuella avgifter:", ClubsCB, useManualFee); + + gdi.dropLine(-1); + + int px = gdi.getCX(); + gdi.addInput("BaseFee", oe->formatCurrency(baseFee), 8, 0, "Avgift:"); + gdi.addInput("FirstDate", firstDate, 10, 0, "Undre datumgräns:", "ÅÅÅÅ-MM-DD"); + gdi.addInput("LastDate", lastDate, 10, 0, "Övre datumgräns:", "ÅÅÅÅ-MM-DD"); + + manualFees(gdi, useManualFee); + + gdi.setCX(px); + gdi.dropLine(4); + gdi.fillRight(); + gdi.addCheckbox("FilterAge", "Åldersfilter:", ClubsCB, filterAge); + + gdi.dropLine(-1); + gdi.addInput("LowLimit", lowAge > 0 ? itos(lowAge) : "", 5, 0, "Undre gräns (år):"); + gdi.addInput("HighLimit", highAge > 0 ? itos(highAge) : "", 5, 0, "Övre gräns (år):"); + ageFilter(gdi, filterAge, useManualFee); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(3); + + gdi.addCheckbox("OnlyNoFee", "Tilldela endast avgift till deltagare utan avgift", ClubsCB, onlyNoFee); + + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("ShowFiltered", "Visa valda deltagare", ClubsCB); + + gdi.addButton("DoFees", "Tilldela avgifter", ClubsCB); + gdi.addButton("ClearFees", "Nollställ avgifter", ClubsCB); + + gdi.addButton("Cancel", "Återgå", ClubsCB); + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2); + gdi.refresh(); + } + else if (bi.id == "FilterAge") { + ageFilter(gdi, gdi.isChecked(bi.id), gdi.isChecked("DefaultFees")); + } + else if (bi.id == "DefaultFees") { + manualFees(gdi, gdi.isChecked(bi.id)); + ageFilter(gdi, gdi.isChecked("FilterAge"), gdi.isChecked(bi.id)); + } + else if (bi.id == "DoFees" || bi.id == "ClearFees" || + bi.id == "ShowFiltered" || bi.id == "ResetFees") { + + readFeeFilter(gdi); + int op; + + if (bi.id == "DoFees") { + if (useManualFee) + op = 0; + else + op = 2; + } + else if (bi.id == "ClearFees") + op = 1; + else if (bi.id == "ResetFees") + op = 2; + else + op = 3; + + gdi.restore("FeeList", false); + gdi.setRestorePoint("FeeList"); + gdi.fillDown(); + + vector filtered; + + oe->sortRunners(ClassStartTimeClub); + string fdate, ldate; + int lage = 0, hage = 0; + + if (useManualFee) { + fdate = firstDate; + ldate = lastDate; + + if (filterAge) { + lage = lowAge; + hage = highAge; + } + } + + oe->selectRunners(typeS, lage, hage, fdate, ldate, !onlyNoFee, filtered); + + gdi.dropLine(2); + int modified = 0; + int count = 0; + for (size_t k = 0; kisVacant()) + continue; + count++; + + oDataInterface di = filtered[k]->getDI(); + int fee = 0; + + if (op == 0 || op == 1) { + if (op == 0) + fee = baseFee; + + if (di.getInt("Fee") != fee) { + di.setInt("Fee", fee); + modified++; + filtered[k]->synchronize(true); + } + } + else if (op == 2) { + filtered[k]->addClassDefaultFee(true); + if (filtered[k]->isChanged()) + modified++; + filtered[k]->synchronize(true); + fee = di.getInt("Fee"); + } + else + fee = di.getInt("Fee"); + + string info = filtered[k]->getClass() + ", " + filtered[k]->getCompleteIdentification(); + + gdi.addStringUT(0, info + " (" + oe->formatCurrency(fee) + ")"); + if (count % 5 == 0) + gdi.dropLine(); + } + + gdi.dropLine(); + + if (count == 0) + gdi.addString("", 1, "Ingen deltagare matchar sökkriteriet").setColor(colorRed); + else if (op == 0 || op == 2) + gdi.addString("", 1, "Ändrade avgift för X deltagare#" + itos(modified)).setColor(colorGreen); + else if (op == 1) + gdi.addString("", 1, "Nollställde avgift för X deltagare#" + itos(modified)).setColor(colorGreen); + + gdi.refresh(); + } + else if (bi.id=="Cancel") { + loadPage(gdi); + } + else if (bi.id=="Print") { + gdi.print(oe); + } + else if (bi.id=="PDF") { + vector< pair > ext; + ext.push_back(make_pair("Portable Document Format (PDF)", "*.pdf")); + + int index; + string file=gdi.browseForSave(ext, "pdf", index); + + if (!file.empty()) { + pdfwriter pdf; + pdf.generatePDF(gdi, gdi.toWide(file), lang.tl("Faktura"), oe->getDCI().getString("Organizer"), gdi.getTL()); + gdi.openDoc(file.c_str()); + } + } + + } + else if (type==GUI_LISTBOX){ + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Clubs"){ + pClub pc=oe->getClub(bi.data); + if (!pc) + throw std::exception("Internal error"); + + selectClub(gdi, pc); + } + } + else if (type == GUI_LINK) { + TextInfo *ti = static_cast(data); + if (ti->id == "CmpSettings") { + if (gdi.hasField("SaveSettings")) + gdi.sendCtrlMessage("SaveSettings"); + TabCompetition &tc = dynamic_cast(*gdi.getTabs().get(TCmpTab)); + tc.loadPage(gdi); + gdi.selectTab(tc.getTabId()); + gdi.sendCtrlMessage("Settings"); + return 0; + } + } + else if (type == GUI_CLEAR) { + if (gdi.isInputChanged("")) { + if (gdi.hasField("SaveSettings")) { + gdi.sendCtrlMessage("SaveSettings"); + } + } + return 1; + } + + return 0; +} + + +bool TabClub::loadPage(gdioutput &gdi) +{ + oe->checkDB(); + gdi.selectTab(tabId); + + if (baseFee == 0) { + if (oe->getDCI().getInt("OrdinaryEntry") > 0) + lastDate = oe->getDCI().getDate("OrdinaryEntry"); + baseFee = oe->getDCI().getInt("EntryFee"); + + lowAge = 0; + highAge = oe->getDCI().getInt("YouthAge"); + } + + gdi.clearPage(false); + gdi.fillDown(); + gdi.addString("", boldLarge, "Klubbar"); + gdi.dropLine(0.5); + gdi.pushX(); + gdi.fillRight(); + gdi.addSelection("Clubs", 200, 300, ClubsCB); + oe->fillClubs(gdi, "Clubs"); + gdi.selectItemByData("Clubs", ClubId); + gdi.addButton("Merge", "Ta bort / slå ihop...", ClubsCB); + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) + gdi.addButton("Invoice", "Faktura", ClubsCB); + if (oe->useRunnerDb()) + gdi.addButton("Update", "Uppdatera", ClubsCB, "Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret"); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) { + gdi.popX(); + gdi.dropLine(3); + + gdi.addString("", boldText, "Ekonomi"); + gdi.popX(); + gdi.dropLine(1.5); + gdi.addButton("Fees", "Avgifter...", ClubsCB); + gdi.addButton("InvoiceSettings", "Fakturainställningar...", ClubsCB); + + gdi.addButton("AllInvoice", "Skapa fakturor...", ClubsCB); + gdi.addButton("Summary", "Sammanställning", ClubsCB); + } + + gdi.popX(); + gdi.dropLine(3); + + gdi.addString("", boldText, "Hantera klubbar"); + + gdi.popX(); + gdi.dropLine(1.5); + if (oe->useRunnerDb()) { + gdi.addButton("UpdateAll", "Uppdatera alla klubbar", ClubsCB, "Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret"); + gdi.addButton("UpdateAllRunners", "Uppdatera klubbar && löpare", ClubsCB, "Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret"); + } + gdi.addButton("EraseClubs", "Radera alla klubbar", ClubsCB, "Radera alla klubbar och ta bort klubbtillhörighet"); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2); + gdi.addString("", 10, "help:29758"); + gdi.dropLine(1); + Table *tbl=oe->getClubsTB(); + gdi.addTable(tbl, gdi.getCX(), gdi.getCY()); + gdi.refresh(); + return true; +} + +void TabClub::importAcceptedInvoice(gdioutput &gdi, const string &file) { + + gdi.addString("", boldLarge, "Hämta svar om elektroniska fakturor"); + + gdi.fillDown(); + gdi.dropLine(2); + csvparser csv; + list< vector > data; + csv.parse(file, data); + list< vector >::iterator it; + map > hasAccepted; + for (it = data.begin(); it != data.end(); ++it) { + if (it->size() == 3) { + int id = atoi((*it)[0].c_str()); + bool accepted = trim((*it)[1]) == "OK"; + pClub pc = oe->getClub(id); + if (pc) { + hasAccepted[id].first = accepted; + if ( hasAccepted[id].second.empty()) + hasAccepted[id].second = (*it)[2]; + else + hasAccepted[id].second += ", " + (*it)[2]; + } + else + gdi.addString("", 0, "Okänd klubb med id X#" + itos(id)).setColor(colorRed); + } + else + throw meosException("Bad file format."); + } + + gdi.pushX(); + gdi.fillNone(); + + int margin = gdi.getCX() + gdi.scaleLength(30); + vector clubs; + oe->getClubs(clubs, true); + bool anyAccepted = false; + int count = 0; + for (size_t k = 0; k < clubs.size(); k++) { + map >::iterator res = hasAccepted.find(clubs[k]->getId()); + + if (res != hasAccepted.end() && res->second.first) { + if (!anyAccepted) { + gdi.dropLine(); + gdi.addString("", 1, "Accepterade elektroniska fakturor"); + gdi.dropLine(); + gdi.popX(); + anyAccepted = true; + } + clubs[k]->getDI().setString("Invoice", "A"); + gdi.addStringUT(0, itos(++count) + "."); + gdi.setCX(margin); + gdi.addStringUT(0, clubs[k]->getName() + ", " + res->second.second); + gdi.dropLine(); + gdi.popX(); + } + } + + bool anyNotAccepted = false; + count = 0; + for (size_t k = 0; k < clubs.size(); k++) { + map >::iterator res = hasAccepted.find(clubs[k]->getId()); + + if (res != hasAccepted.end() && !res->second.first) { + if (!anyNotAccepted) { + gdi.dropLine(); + gdi.addString("", 1, "Ej accepterade elektroniska fakturor"); + gdi.dropLine(); + gdi.popX(); + anyNotAccepted = true; + } + clubs[k]->getDI().setString("Invoice", "P"); + gdi.addStringUT(0, itos(++count) + "."); + gdi.setCX(margin); + gdi.addStringUT(0, clubs[k]->getName() + ", " + res->second.second); + gdi.dropLine(); + gdi.popX(); + + } + } + + bool anyNoAnswer = false; + count = 0; + for (size_t k = 0; k < clubs.size(); k++) { + string email = clubs[k]->getDCI().getString("EMail"); + bool hasMail = !email.empty() && email.find_first_of('@') != email.npos; + + map >::iterator res = hasAccepted.find(clubs[k]->getId()); + + if (res == hasAccepted.end() ) { + if (!anyNoAnswer) { + gdi.dropLine(); + gdi.addString("", 1, "Klubbar som inte svarat"); + gdi.dropLine(); + gdi.popX(); + + anyNoAnswer = true; + } + gdi.addStringUT(0, itos(++count) + "."); + gdi.setCX(margin); + + if (hasMail) + gdi.addStringUT(0, clubs[k]->getName()); + else + gdi.addString("", 0, "X (Saknar e-post)#" + clubs[k]->getName()); + + gdi.dropLine(); + gdi.popX(); + } + } + gdi.fillDown(); + gdi.dropLine(); +} + +void TabClub::clearCompetitionData() { +} diff --git a/code/TabClub.h b/code/TabClub.h new file mode 100644 index 0000000..f18e596 --- /dev/null +++ b/code/TabClub.h @@ -0,0 +1,63 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "tabbase.h" + +class TabClub : + public TabBase +{ + int clubCB(gdioutput &gdi, int type, void *data); + + string firstDate; + string lastDate; + bool filterAge; + bool onlyNoFee; + bool useManualFee; + int highAge; + int lowAge; + int baseFee; + string typeS; + + int firstInvoice; + + int ClubId; + + void readFeeFilter(gdioutput &gdi); + +protected: + void clearCompetitionData(); + +public: + void selectClub(gdioutput &gdi, pClub pc); + + void importAcceptedInvoice(gdioutput &gdi, const string &file); + + const char * getTypeStr() const {return "TClubTab";} + TabType getType() const {return TClubTab;} + + bool loadPage(gdioutput &gdi); + TabClub(oEvent *oe); + ~TabClub(void); + + friend int ClubsCB(gdioutput *gdi, int type, void *data); +}; diff --git a/code/TabCompetition.cpp b/code/TabCompetition.cpp new file mode 100644 index 0000000..3dc199d --- /dev/null +++ b/code/TabCompetition.cpp @@ -0,0 +1,3853 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include "meos_util.h" +#include "TabCompetition.h" +#include "TabCourse.h" +#include "oFreeImport.h" +#include "localizer.h" +#include "oListInfo.h" +#include "download.h" +#include "progress.h" +#include "classconfiginfo.h" +#include "RunnerDB.h" +#include "gdifonts.h" +#include "meosException.h" +#include "meosdb/sqltypes.h" +#include "socket.h" +#include "iof30interface.h" +#include "MeOSFeatures.h" +#include "prefseditor.h" +#include "recorder.h" +#include "testmeos.h" +#include "importformats.h" + +#include +#include +#include +#include +#include + +void Setup(bool overwrite, bool overWriteall); +void exportSetup(); +void resetSaveTimer(); +extern bool enableTests; + +int ListsCB(gdioutput *gdi, int type, void *data); + +TabCompetition::TabCompetition(oEvent *poe):TabBase(poe) +{ + eventorBase = poe->getPropertyString("EventorBase", "https://eventor.orientering.se/api/"); + iofExportVersion = "&version=3.0"; + defaultServer="localhost"; + defaultName="meos"; + organizorId = 0; + lastSelectedClass = -1; + allTransfer.insert(-1); + lastChangeClassType = oEvent::ChangeClassVacant; +} + +TabCompetition::~TabCompetition(void) +{ +} + +extern SportIdent *gSI; +extern HINSTANCE hInst; +extern HWND hWndMain; + +bool TabCompetition::save(gdioutput &gdi, bool write) +{ + string name=gdi.getText("Name"); + + if (name.empty()) { + gdi.alert("Tävlingen måste ha ett namn"); + return 0; + } + + string zt = gdi.getText("ZeroTime"); + bool longTimes = gdi.isChecked("LongTimes"); + string date = gdi.getText("Date"); + + if (longTimes) + zt = "00:00:00"; + + int newZT = convertAbsoluteTimeHMS(zt, -1); + if (newZT < 0) + throw meosException("Felaktigt tidsformat 'X' (Använd TT:MM:SS)#" + zt); + + int oldZT = convertAbsoluteTimeHMS(oe->getZeroTime(), -1); + bool oldLT = oe->useLongTimes(); + string oldDate = oe->getDate(); + + if ((newZT != oldZT || + longTimes != oldLT || + (longTimes && date != oldDate)) && oe->classHasResults(0)) { + if (!gdi.ask("warn:changedtimezero")) { + gdi.setText("ZeroTime", oe->getZeroTime()); + gdi.check("LongTimes", oe->useLongTimes()); + gdi.setText("Date", oe->getDate()); + return 0; + } + } + oe->setDate(date); + oe->useLongTimes(longTimes); + oe->setName(gdi.getText("Name")); + oe->setAnnotation(gdi.getText("Annotation")); + oe->setZeroTime(zt); + + oe->synchronize(); + if (gSI) gSI->SetZeroTime(oe->getZeroTimeNum()); + + gdi.setWindowTitle(oe->getTitleName()); + gdi.setText("Date", oe->getDate()); + gdi.setText("ZeroTime", oe->getZeroTime()); + + if (write) { + gdi.setWaitCursor(true); + resetSaveTimer(); + return oe->save(); + } + else + return true; +} + +bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi) +{ + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.xml;*.bu?")); + string fileName = gdi.browseForOpen(ext, "xml"); + if (fileName.empty()) + return false; + + gdi.setWaitCursor(true); + if (oe->open(fileName, true)) { + if (gSI) gSI->SetZeroTime(oe->getZeroTimeNum()); + gdi.setWindowTitle(oe->getTitleName()); + resetSaveTimer(); + return true; + } + + return false; +} + +bool TabCompetition::exportFileAs(HWND hWnd, gdioutput &gdi) +{ + int ix = 0; + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.xml")); + string fileName = gdi.browseForSave(ext, "xml", ix); + if (fileName.empty()) + return false; + + gdi.setWaitCursor(true); + if (!oe->save(fileName.c_str())) { + gdi.alert("Fel: Filen " + fileName+ " kunde inte skrivas."); + return false; + } + + return true; +} + +int CompetitionCB(gdioutput *gdi, int type, void *data) +{ + TabCompetition &tc = dynamic_cast(*gdi->getTabs().get(TCmpTab)); + + return tc.competitionCB(*gdi, type, data); +} + + +int restoreCB(gdioutput *gdi, int type, void *data) +{ + TabCompetition &tc = dynamic_cast(*gdi->getTabs().get(TCmpTab)); + + return tc.restoreCB(*gdi, type, data); +} + +void TabCompetition::loadConnectionPage(gdioutput &gdi) +{ + gdi.clearPage(false); + showConnectionPage=true; + gdi.addString("", boldLarge, "Anslutningar"); + + if (oe->getServerName().empty()) { + gdi.addString("", 10, "help:52726"); + gdi.pushX(); + gdi.dropLine(); + defaultServer = oe->getPropertyString("Server", defaultServer); + defaultName = oe->getPropertyString("UserName", defaultName); + defaultPort = oe->getPropertyString("Port", defaultPort); + string client = oe->getPropertyString("Client", oe->getClientName()); + + gdi.fillRight(); + gdi.addInput("Server", defaultServer, 16, 0, "MySQL Server / IP-adress:", "IP-adress eller namn på en MySQL-server"); + gdi.addInput("UserName", defaultName, 7, 0, "Användarnamn:"); + gdi.addInput("PassWord", defaultPwd, 9, 0, "Lösenord:").setPassword(true); + gdi.addInput("Port", defaultPort, 4, 0, "Port:"); + + if (defaultServer.empty()) + gdi.setInputFocus("Server"); + else if (defaultName.empty()) + gdi.setInputFocus("UserName"); + else + gdi.setInputFocus("PassWord"); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(2.5); + gdi.addInput("ClientName", client, 16, 0, "Klientnamn:"); + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("ConnectToMySQL", "Anslut", CompetitionCB).setDefault(); + } + else { + gdi.addString("", 10, "help:50431"); + gdi.dropLine(1); + gdi.pushX(); + gdi.fillRight(); + gdi.addString("", 1, "Ansluten till:"); + gdi.addStringUT(1, oe->getServerName()).setColor(colorGreen); + gdi.popX(); + gdi.dropLine(2); + gdi.addInput("ClientName", oe->getClientName(), 16, 0, "Klientnamn:"); + gdi.dropLine(); + gdi.addButton("SaveClient", "Ändra", CompetitionCB); + gdi.dropLine(2.5); + + gdi.popX(); + gdi.addString("", 1, "Öppnad tävling:"); + + if (oe->empty()) + gdi.addString("", 1, "Ingen").setColor(colorRed); + else { + gdi.addStringUT(1, oe->getName()).setColor(colorGreen); + + if (oe->isClient()) + gdi.addString("", 1, "(på server)"); + else + gdi.addString("", 1, "(lokalt)"); + + } + gdi.dropLine(2); + gdi.popX(); + gdi.fillRight(); + + if (!oe->isClient()) + gdi.addButton("UploadCmp", "Ladda upp öppnad tävling på server",CompetitionCB); + + if (oe->empty()) { + gdi.disableInput("UploadCmp"); + } + else { + gdi.addButton("CloseCmp", "Stäng tävlingen", CompetitionCB); + gdi.addButton("Delete", "Radera tävlingen", CompetitionCB); + } + gdi.dropLine(2); + gdi.popX(); + if (oe->empty()) { + char bf[260]; + getUserFile(bf, ""); + oe->enumerateCompetitions(bf, "*.meos"); + + gdi.dropLine(1); + gdi.fillRight(); + gdi.addListBox("ServerCmp", 320, 210, CompetitionCB, "Server"); + oe->fillCompetitions(gdi, "ServerCmp", 2); + gdi.selectItemByData("ServerCmp", oe->getPropertyInt("LastCompetition", 0)); + + gdi.fillDown(); + gdi.addListBox("LocalCmp", 320, 210, CompetitionCB, "Lokalt"); + gdi.popX(); + oe->fillCompetitions(gdi, "LocalCmp", 1); + gdi.selectItemByData("LocalCmp", oe->getPropertyInt("LastCompetition", 0)); + + gdi.addCheckbox("UseDirectSocket", "Skicka och ta emot snabb förhandsinformation om stämplingar och resultat", + 0, oe->getPropertyInt("UseDirectSocket", true) != 0); + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("OpenCmp", "Öppna tävling", CompetitionCB).setDefault(); + gdi.addButton("Repair", "Reparera vald tävling", CompetitionCB); + + gdi.setInputStatus("Repair", gdi.getSelectedItem("ServerCmp").second, true); + } + else if (oe->isClient()) { + gdi.fillDown(); + gdi.popX(); + oe->listConnectedClients(gdi); + gdi.registerEvent("Connections", CompetitionCB); + gdi.fillRight(); + } + + gdi.addButton("DisconnectMySQL", "Koppla ner databas", CompetitionCB); + } + gdi.addButton("Cancel", "Till huvudsidan", CompetitionCB).setCancel(); + gdi.fillDown(); + gdi.refresh(); +} + +bool TabCompetition::checkEventor(gdioutput &gdi, ButtonInfo &bi) { + eventorOrigin = bi.id; + + if (organizorId == 0) { + int clubId = getOrganizer(true); + if (clubId == 0) { + bi.id = "EventorAPI"; + competitionCB(gdi, GUI_BUTTON, &bi); + return true; + } + else if (clubId == -1) + throw std::exception("Kunde inte ansluta till Eventor"); + + organizorId = clubId; + } + return false; +} + +int eventorServer(gdioutput *gdi, int type, void *data) { + TabCompetition &tc = dynamic_cast(*gdi->getTabs().get(TCmpTab)); + if (type == GUI_COMBO) { + const ListBoxInfo &lbi = *((ListBoxInfo *)data); + tc.setEventorServer(lbi.text); + } + else if (type == GUI_BUTTON) { + const ButtonInfo &bi = *((ButtonInfo *)data); + + if (bi.id == "EventorUTC") + tc.setEventorUTC(gdi->isChecked(bi.id)); + } + return 0; +} + +void TabCompetition::setEventorServer(const string &server) { + eventorBase = server; + oe->setProperty("EventorBase", server); +} + +void TabCompetition::setEventorUTC(bool useUTC) { + oe->setProperty("UseEventorUTC", useUTC); +} + +bool TabCompetition::useEventorUTC() const { + bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0; + return eventorUTC; +} + +enum StartMethod {SMCommon = 1, SMDrawn, SMFree, SMCustom}; + +int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data) +{ + if (type == GUI_LINK) { + TextInfo ti = *(TextInfo *)data; + if (ti.id == "link") { + string url = ti.text; + ShellExecute(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL); + } + } + else if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id == "CopyLink") { + string url = gdi.getText("link"); + + if (OpenClipboard(gdi.getHWND())) { + EmptyClipboard(); + HGLOBAL hClipboardData; + hClipboardData = GlobalAlloc(GMEM_DDESHARE, + url.length()+1); + + char * pchData; + pchData = (char*)GlobalLock(hClipboardData); + + strcpy_s(pchData, url.length()+1, LPCSTR(url.c_str())); + + GlobalUnlock(hClipboardData); + + SetClipboardData(CF_TEXT,hClipboardData); + CloseClipboard(); + } + } + else if (bi.id == "LongTimes") { + if (gdi.isChecked(bi.id)) { + gdi.setTextTranslate("ZeroTimeHelp", "help:long_times", true); + gdi.disableInput("ZeroTime"); + } + else { + gdi.setTextTranslate("ZeroTimeHelp", "help:zero_time", true); + gdi.enableInput("ZeroTime"); + } + } + else if (bi.id=="Print") { + gdi.print(oe); + } + else if (bi.id=="Setup") { + gdi.clearPage(false); + + gdi.addString("", boldLarge, "Inställningar MeOS"); + gdi.dropLine(); + gdi.addString("", 10, "help:29191"); + gdi.dropLine(); + char FileNamePath[260]; + getUserFile(FileNamePath, ""); + gdi.addStringUT(0, lang.tl("MeOS lokala datakatalog är") + ": " + FileNamePath); + gdi.dropLine(); + + gdi.addCombo("EventorServer", 320, 100, eventorServer, "Eventor server:"); + + vector eventorCand; + eventorCand.push_back("https://eventor.orientering.se/api/"); + + gdi.addItem("EventorServer", eventorBase); + for (size_t k = 0; k < eventorCand.size(); k++) { + if (eventorBase != eventorCand[k]) + gdi.addItem("EventorServer", eventorCand[k]); + } + + gdi.selectFirstItem("EventorServer"); + + bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0; + gdi.addCheckbox("EventorUTC", "Eventors tider i UTC (koordinerad universell tid)", eventorServer, eventorUTC); + + char bf[260]; + GetCurrentDirectory(260, bf); + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addInput("Source", bf, 40, 0, "Källkatalog:"); + gdi.dropLine(0.8); + gdi.addButton("SourceBrowse", "Bläddra...", CompetitionCB); + gdi.dropLine(4); + gdi.popX(); + gdi.fillRight(); + gdi.addButton("DoSetup", "Installera", CompetitionCB); + gdi.addButton("ExportSetup", "Exportera", CompetitionCB); + gdi.addButton("Cancel", "Stäng", CompetitionCB); + gdi.dropLine(2); + gdi.refresh(); + } + else if (bi.id=="SourceBrowse") { + string s = gdi.browseForFolder(gdi.getText("Source"), 0); + if (!s.empty()) + gdi.setText("Source", s); + } + else if (bi.id=="DoSetup") { + string source = gdi.getText("Source"); + if (SetCurrentDirectory(source.c_str())) { + Setup(true, true); + gdi.alert("Tillgängliga filer installerades. Starta om MeOS."); + exit(0); + } + else + throw std::exception("Operationen misslyckades"); + } + else if (bi.id == "RunnerDatabase") { + loadRunnerDB(gdi, 0, false); + return 0; + } + else if (bi.id=="ExportSetup") { + + gdi.clearPage(false); + gdi.addString("", boldLarge, "Exportera inställningar och löpardatabaser"); + gdi.dropLine(); + gdi.addString("", 10, "help:15491"); + gdi.dropLine(); + char FileNamePath[260]; + getUserFile(FileNamePath, ""); + gdi.addStringUT(0, lang.tl("MeOS lokala datakatalog är: ") + FileNamePath); + + gdi.dropLine(); + + char bf[260]; + GetCurrentDirectory(260, bf); + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addInput("Source", bf, 40, 0, "Destinationskatalog:"); + gdi.dropLine(0.8); + gdi.addButton("SourceBrowse", "Bläddra...", CompetitionCB); + gdi.dropLine(4); + gdi.popX(); + gdi.fillRight(); + gdi.addButton("DoExportSetup", "Exportera", CompetitionCB).setDefault(); + gdi.addButton("CancelRunnerDatabase", "Avbryt", CompetitionCB).setCancel(); + gdi.dropLine(2); + gdi.refresh(); + } + else if (bi.id=="DoExportSetup") { + string source = gdi.getText("Source"); + if (SetCurrentDirectory(source.c_str())) { + exportSetup(); + gdi.alert("Inställningarna har exporterats."); + } + } + else if (bi.id == "SaveTest") { + vector< pair > cpp; + cpp.push_back(make_pair("Source", "*.cpp")); + int ix = 0; + string fn = gdi.browseForSave(cpp, ".cpp", ix); + if (!fn.empty()) + gdi.getRecorder().saveRecordings(fn); + } + else if (bi.id == "RunTest") { + TestMeOS tm(oe, "base"); + tm.runAll(); + oe->clear(); + gdi.selectTab(tabId); + tm.publish(gdi); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.refresh(); + } + else if (bi.id == "RunSpecificTest") { + int test = gdi.getSelectedItem("Tests").first; + TestMeOS tm(oe, "base"); + tm.runSpecific(test); + } + else if (bi.id == "LocalSettings") { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Ändra MeOS lokala systemegenskaper"); + gdi.dropLine(0.5); + gdi.addString("", 0, "Vissa inställningar kräver omstart av MeOS för att ha effekt."); + gdi.dropLine(0.5); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.dropLine(); + + if (prefsEditor.empty()) + prefsEditor.push_back(PrefsEditor(oe)); + + prefsEditor.back().showPrefs(gdi); + gdi.refresh(); + } + else if (bi.id=="Test") { + vector< pair > cpp; + cpp.push_back(make_pair("Source", "*.cpp")); + int ix = 0; + string fn = gdi.browseForSave(cpp, ".cpp", ix); + if (!fn.empty()) + gdi.getRecorder().saveRecordings(fn); + else { + TestMeOS tm(oe, "base"); + tm.runAll(); + tm.publish(gdi); + } + /*gdi.clearPage(false); + gdi.addString("", boldLarge, "Ändra MeOS lokala systemegenskaper"); + gdi.dropLine(0.5); + gdi.addString("", 0, "Vissa inställningar kräver omstart av MeOS för att ha effekt."); + gdi.dropLine(0.5); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.dropLine(); + + if (prefsEditor.empty()) + prefsEditor.push_back(PrefsEditor(oe)); + + prefsEditor.back().showPrefs(gdi); + gdi.refresh();*/ + } + else if (bi.id=="Report") { + gdi.clearPage(true); + oe->generateCompetitionReport(gdi); + + gdi.addButton(gdi.getWidth()+20, 15, gdi.scaleLength(120), "Cancel", + "Återgå", CompetitionCB, "", true, false); + gdi.addButton(gdi.getWidth()+20, 18+gdi.getButtonHeight(), gdi.scaleLength(120), "Print", + "Skriv ut...", CompetitionCB, "Skriv ut rapporten", true, false); + gdi.refresh(); + + //gdi.addButton("Cancel", "Avbryt", CompetitionCB); + } + else if (bi.id=="Features") { + save(gdi, false); + meosFeatures(gdi, false); + } + else if (bi.id == "SaveFeaures") { + saveMeosFeatures(gdi, true); + loadPage(gdi); + } + else if (bi.id=="Settings") { + loadSettings(gdi); + } + else if (bi.id == "UseFraction") { + gdi.setInputStatus("CurrencySeparator_odc", gdi.isChecked(bi.id)); + } + else if (bi.id == "AddPayMode") { + saveSettings(gdi); + vector< pair > modes; + oe->getPayModes(modes); + oe->setPayMode(modes.size(), lang.tl("Betalsätt")); + loadSettings(gdi); + } + else if (bi.id == "RemovePayMode") { + saveSettings(gdi); + oe->setPayMode(bi.getExtraInt(), ""); + loadSettings(gdi); + } + else if (bi.id=="SaveSettings") { + saveSettings(gdi); + loadPage(gdi); + } + else if (bi.id == "Exit") { + PostMessage(gdi.getMain(), WM_CLOSE, 0, 0); + } + else if (bi.id == "Help") { + char fn[MAX_PATH]; + getMeOSFile(fn, lang.tl("documentation").c_str()); + if (_access(fn, 0)==-1) { + gdi.alert(string("Hittar inte hjälpfilen, X#") + fn); + return 0; + } + + gdi.openDoc(fn); + } + else if (bi.id=="Browse") { + vector< pair > ext; + ext.push_back(make_pair(lang.tl("Databaskälla"), "*.xml;*.csv")); + + string f = gdi.browseForOpen(ext, "xml"); + string id; + if (!f.empty()) { + InputInfo &ii = dynamic_cast(gdi.getBaseInfo(bi.getExtra())); + gdi.setText(ii.id, f); + } + } + else if (bi.id=="DBaseIn") { + gdi.clearPage(true); + gdi.addString("", boldLarge, "Importera löpare och klubbar / distriktsregister"); + gdi.dropLine(); + gdi.addString("", 10, "help:runnerdatabase"); + gdi.dropLine(2); + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("ClubFile", "", 40, 0, "Filnamn IOF (xml) med klubbar"); + gdi.dropLine(); + gdi.addButton("Browse", "Bläddra...", CompetitionCB).setExtra("ClubFile"); + gdi.popX(); + gdi.dropLine(3); + gdi.addInput("CmpFile", "", 40, 0, "Filnamn IOF (xml) eller OE (csv) med löpare"); + gdi.dropLine(); + gdi.addButton("Browse", "Bläddra...", CompetitionCB).setExtra("CmpFile"); + gdi.popX(); + + gdi.dropLine(3); + gdi.popX(); + gdi.addCheckbox("Clear", "Nollställ databaser", 0, true); + gdi.dropLine(3); + + gdi.popX(); + gdi.addButton("DoDBaseIn", "Importera", CompetitionCB).setDefault(); + gdi.addButton("CancelRunnerDatabase", "Avbryt", CompetitionCB).setCancel(); + gdi.dropLine(3); + gdi.fillDown(); + gdi.popX(); + } + else if (bi.id=="DoDBaseIn") { + gdi.enableEditControls(false); + gdi.disableInput("DoDBaseIn"); + gdi.disableInput("CancelRunnerDatabase"); + + gdi.setWaitCursor(true); + gdi.addString("", 0, "Importerar..."); + bool clear = gdi.isChecked("Clear"); + string club = gdi.getText("ClubFile"); + string cmp = gdi.getText("CmpFile"); + if (club == cmp) + club = ""; + + csvparser csv; + bool clubCsv = !club.empty() && csv.iscsv(club.c_str()) != 0; + bool cmpCsv = !cmp.empty() && csv.iscsv(cmp.c_str()) != 0; + + if (cmpCsv) { + if (!club.empty()) + throw meosException("Klubbfil får inte anges vid CSV import."); + + oe->importOECSV_Data(cmp.c_str(), clear); + } + else { + if (clubCsv) + throw meosException("Klubbfil får inte anges vid CSV import."); + + oe->importXML_IOF_Data(club.c_str(), cmp.c_str(), clear); + } + + gdi.dropLine(); + gdi.addButton("CancelRunnerDatabase", "Återgå", CompetitionCB); + gdi.refresh(); + gdi.setWaitCursor(false); + } + else if (bi.id=="Reset") { + if (gdi.ask("Vill då återställa inställningar och skriva över egna databaser?")) + Setup(true, true); + } + else if (bi.id=="ConnectMySQL") + loadConnectionPage(gdi); + else if (bi.id=="SaveClient") { + oe->setClientName(gdi.getText("ClientName")); + if (gdi.getText("ClientName").length()>0) + oe->setProperty("Client", gdi.getText("ClientName")); + } + else if (bi.id=="ConnectToMySQL") { + bool s=oe->connectToMySQL(gdi.getText("Server"), + gdi.getText("UserName"), + gdi.getText("PassWord"), + gdi.getTextNo("Port")); + + if (s) { + defaultServer=gdi.getText("Server"); + defaultName=gdi.getText("UserName"); + defaultPwd=gdi.getText("PassWord"); + defaultPort=gdi.getText("Port"); + + oe->setClientName(gdi.getText("ClientName")); + oe->setProperty("Server", defaultServer); + oe->setProperty("UserName", defaultName); + oe->setProperty("Port", defaultPort); + if (gdi.getText("ClientName").length()>0) + oe->setProperty("Client", gdi.getText("ClientName")); + + + loadConnectionPage(gdi); + } + } + else if (bi.id == "Repair") { + if (!gdi.ask("ask:repair")) + return 0; + ListBoxInfo lbi; + int id=0; + if ( gdi.getSelectedItem("ServerCmp", lbi) ) + id=lbi.data; + else + throw meosException("Ingen tävling vald."); + + string nameId = oe->getNameId(id); + vector output; + repairTables(nameId, output); + gdi.clearPage(true); + gdi.addString("", boldLarge, "Reparerar tävlingsdatabasen"); + gdi.dropLine(); + for (size_t k = 0; k < output.size(); k++) { + gdi.addStringUT(0, output[k]); + } + gdi.dropLine(); + gdi.addButton("Cancel", "Klart", CompetitionCB); + + } + else if (bi.id=="DisconnectMySQL") { + oe->closeDBConnection(); + loadConnectionPage(gdi); + } + else if (bi.id=="UploadCmp") { + if (oe->uploadSynchronize()) + gdi.setWindowTitle(oe->getTitleName()); + + if (oe->isClient() && oe->getPropertyInt("UseDirectSocket", true) != 0) { + oe->getDirectSocket().startUDPSocketThread(gdi.getMain()); + } + + loadConnectionPage(gdi); + } + else if (bi.id == "MultiEvent") { + loadMultiEvent(gdi); + } + else if (bi.id == "CloneEvent") { + string ne = oe->cloneCompetition(true, false, false, false, false); + oe->updateTabs(true); + } + else if (bi.id == "CloneCmp") { + gdi.restore("MultiHeader"); + gdi.dropLine(3); + gdi.fillDown(); + gdi.addString("", 1, "Skapar ny etapp").setColor(colorGreen); + gdi.addString("", 0, "Överför anmälda"); + gdi.refreshFast(); + string ne = oe->cloneCompetition(true, false, false, false, true); + + + gdi.addString("", 0, "Klart"); + gdi.dropLine(); + + char bf[260]; + getUserFile(bf, ""); + oe->enumerateCompetitions(bf, "*.meos"); + oe->updateTabs(true); + gdi.addButton("MultiEvent", "Återgå", CompetitionCB); + gdi.refresh(); + } + else if (bi.id == "SaveMulti") { + saveMultiEvent(gdi); + } + else if (bi.id == "OpenPost" || bi.id == "OpenPre") { + + saveMultiEvent(gdi); + + string nameId = oe->getNameId(0); + ListBoxInfo lbi; + bool openPost = false; + + int theNumber = oe->getStageNumber(); + + if (bi.id == "OpenPost") { + gdi.getSelectedItem("PostEvent", lbi); + openPost = true; + if (theNumber == 0) { + oe->setStageNumber(1); + theNumber = 1; + } + theNumber++; + } + else { + gdi.getSelectedItem("PreEvent", lbi); + if (theNumber == 0) { + oe->setStageNumber(2); + theNumber = 2; + } + theNumber--; + } + + int id = lbi.data; + + if (id>0) { + oe->save(); + openCompetition(gdi, id); + oe->getMeOSFeatures().useFeature(MeOSFeatures::SeveralStages, true, *oe); + if (openPost) { + oe->getDI().setString("PreEvent", nameId); + if (theNumber > 1) { + oe->setStageNumber(theNumber); + } + } + else { + oe->getDI().setString("PostEvent", nameId); + if (theNumber >= 0) { + oe->setStageNumber(theNumber); + } + } + loadMultiEvent(gdi); + } + } + else if (bi.id == "TransferData") { + saveMultiEvent(gdi); + + ListBoxInfo lbi; + gdi.getSelectedItem("PostEvent", lbi); + if (int(lbi.data) == -2) + throw std::exception("Nästa etapp är odefinierad."); + + gdi.clearPage(true); + gdi.addString("", boldLarge, "Överför resultat till nästa etapp"); + gdi.setData("PostEvent", lbi.data); + gdi.dropLine(); + selectTransferClasses(gdi, false); + } + else if (bi.id == "SelectAll" || bi.id=="SelectNone") { + set s; + if (bi.id=="SelectAll") + s.insert(-1); + gdi.setSelection("ClassNewEntries", s); + } + else if (bi.id == "ExpandTResults") { + selectTransferClasses(gdi, true); + } + else if (bi.id == "DoTransferData") { + bool transferNoCompet = true; + gdi.disableInput("DoTransferData"); + gdi.disableInput("MultiEvent"); + gdi.disableInput("ExpandTResults", true); + gdi.disableInput("SelectAll", true); + gdi.disableInput("SelectNone", true); + if (gdi.hasField("ClassNewEntries")) { + gdi.getSelection("ClassNewEntries", allTransfer); + transferNoCompet = gdi.isChecked("TransferEconomy"); + } + else { + //oe->getAllClasses(allTransfer); + allTransfer.clear(); + transferNoCompet = false; + } + int id = (int)gdi.getData("PostEvent"); + oEvent::ChangedClassMethod method = oEvent::ChangedClassMethod(gdi.getSelectedItem("ChangeClassType").first); + lastChangeClassType = method; + + string file = oe->getFileNameFromId(id); + + bool success = false; + oEvent nextStage(gdi); + + if (!file.empty()) + success = nextStage.open(file.c_str(), false); + + if (success) + success = nextStage.getNameId(0) == oe->getDCI().getString("PostEvent"); + + if (success) { + gdi.enableEditControls(false); + gdi.dropLine(3); + gdi.fillDown(); + gdi.addString("", 1, "Överför resultat till X#" + nextStage.getName()); + gdi.refreshFast(); + + vector changedClass, changedClassNoResult, assignedVacant,newEntries,notTransfered, failedTarget; + + oe->transferResult(nextStage, allTransfer, method, transferNoCompet, + changedClass, changedClassNoResult, assignedVacant, + newEntries, notTransfered, failedTarget); + bool fixedProblem = false; + + if (!changedClass.empty()) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare har bytt klass:"); + displayRunners(gdi, changedClass); + } + + if (!changedClassNoResult.empty()) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare har bytt klass (inget totalresultat):"); + displayRunners(gdi, changedClassNoResult); + } + + + if (!assignedVacant.empty()) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare har tilldelats en vakant plats:"); + displayRunners(gdi, assignedVacant); + } + + if (!newEntries.empty()) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare är nyanmälda:"); + displayRunners(gdi, newEntries); + } + + if (!notTransfered.empty() && transferNoCompet) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare deltar ej:"); + displayRunners(gdi, notTransfered); + } + else if (!notTransfered.empty()) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare överfördes ej:"); + displayRunners(gdi, notTransfered); + } + + if (!failedTarget.empty()) { + fixedProblem = true; + gdi.dropLine(); + gdi.addString("", 1, "Följande deltagare är anmälda till nästa etapp men inte denna:"); + displayRunners(gdi, failedTarget); + } + + vector newEntriesT, notTransferedT, failedTargetT; + oe->transferResult(nextStage, method, newEntriesT, notTransferedT, failedTargetT); + + nextStage.save(); + oe->updateTabs(true); + gdi.dropLine(); + + if (!fixedProblem) { + gdi.addString("", 1, "Samtliga deltagare tilldelades resultat.").setColor(colorGreen); + } + else { + gdi.addString("", 1, "Klart.").setColor(colorGreen); + } + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("MultiEvent", "Återgå", CompetitionCB); + gdi.scrollToBottom(); + gdi.refresh(); + + } + else + throw std::exception("Kunde inte lokalisera nästa etapp"); + } + else if (bi.id == "UseEventor") { + if (gdi.isChecked("UseEventor")) + oe->setProperty("UseEventor", 1); + else + oe->setProperty("UseEventor", 2); + PostMessage(gdi.getTarget(), WM_USER + 2, TCmpTab, 0); + } + else if (bi.id == "EventorAPI") { + assert(!eventorOrigin.empty()); + //DWORD d; + //if (gdi.getData("ClearPage", d)) + gdi.clearPage(true); + gdi.addString("", boldLarge, "Nyckel för Eventor"); + gdi.dropLine(); + gdi.addString("", 10, "help:eventorkey"); + gdi.dropLine(); + gdi.addInput("apikey", "", 40, 0, "API-nyckel:"); + gdi.dropLine(); + gdi.fillRight(); + gdi.pushX(); + gdi.setRestorePoint("APIKey"); + gdi.addButton("Cancel", "Avbryt", CompetitionCB).setCancel(); + gdi.addButton("EventorAPISave", "Spara", CompetitionCB).setDefault(); + gdi.dropLine(3); + gdi.popX(); + } + else if (bi.id == "EventorAPISave") { + string key = gdi.getText("apikey"); + oe->setPropertyEncrypt("apikey", key); + + int clubId = getOrganizer(false); + + if (clubId > 0) { + gdi.restore("APIKey", false); + gdi.fillDown(); + gdi.addString("", 1, "Godkänd API-nyckel").setColor(colorGreen); + gdi.addString("", 0, "Klubb: X#" + eventor.name); + gdi.addStringUT(0, eventor.city); + gdi.dropLine(); + gdi.addButton("APIKeyOK", "Fortsätt", CompetitionCB); + gdi.refresh(); + } + else { + gdi.fillDown(); + gdi.dropLine(); + oe->setPropertyEncrypt("apikey", ""); + organizorId = 0; + gdi.addString("", boldText, "Felaktig nyckel").setColor(colorRed); + gdi.refresh(); + } + } + else if (bi.id == "APIKeyOK") { + oe->setProperty("Organizer", eventor.name); + string adr = eventor.careOf.empty() ? eventor.street : + eventor.careOf + ", " + eventor.street; + oe->setProperty("Street", adr); + oe->setProperty("Address", eventor.zipCode + " " + eventor.city); + if (eventor.account.size() > 0) + oe->setProperty("Account", eventor.account); + if (eventor.email.size() > 0) + oe->setProperty("EMail", eventor.email); + assert(!eventorOrigin.empty()); + bi.id = eventorOrigin; + eventorOrigin.clear(); + return competitionCB(gdi, type, &bi); + } + else if (bi.id == "EventorUpdateDB") { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Uppdatera löpardatabasen"); + gdi.setData("UpdateDB", 1); + bi.id = "EventorImport"; + return competitionCB(gdi, type, &bi); + } + else if (bi.id == "SynchEventor") { + if (checkEventor(gdi, bi)) + return 0; + + gdi.clearPage(true); + //gdi.setData("EventorId", (int)oe->getExtIdentifier()); + //gdi.setData("UpdateDB", 1); + gdi.addString("", boldLarge, "Utbyt tävlingsdata med Eventor"); + gdi.dropLine(); + + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + + gdi.fillRight(); + gdi.addButton("EventorEntries", "Hämta efteranmälningar", CompetitionCB); + gdi.addButton("EventorUpdateDB", "Uppdatera löpardatabasen", CompetitionCB); + gdi.addButton("EventorStartlist", "Publicera startlista", CompetitionCB, "Publicera startlistan på Eventor"); + + if (!cnf.hasStartTimes()) + gdi.disableInput("EventorStartlist"); + + gdi.addButton("EventorResult", "Publicera resultat", CompetitionCB, "Publicera resultat och sträcktider på Eventor och WinSplits online"); + + if (!cnf.hasResults()) + gdi.disableInput("EventorResult"); + + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.popX(); + gdi.dropLine(2); + bi.id = "EventorImport"; + //competitionCB(gdi, type, &bi); + } + else if (bi.id == "EventorEntries") { + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + if (cnf.hasResults()) { + if (!gdi.ask("Tävlingen har redan resultat. Vill du verkligen hämta anmälningar?")) + return 0; + } + gdi.enableEditControls(false); + gdi.enableInput("Cancel"); + gdi.dropLine(2); + gdi.setData("EventorId", (int)oe->getExtIdentifier()); + gdi.setData("UpdateDB", DWORD(0)); + bi.id = "EventorImport"; + competitionCB(gdi, type, &bi); + } + else if (bi.id == "EventorStartlist") { + gdi.clearPage(true); + gdi.fillDown(); + gdi.dropLine(); + gdi.addString("", boldLarge, "Publicerar startlistan"); + + gdi.dropLine(); + gdi.fillDown(); + gdi.addString("", 1, "Ansluter till Internet").setColor(colorGreen); + + gdi.refreshFast(); + Download dwl; + dwl.initInternet(); + + string startlist = getTempFile(); + bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0; + oe->exportIOFStartlist(oEvent::IOF30, startlist.c_str(), eventorUTC, + set(), false, false, true); + vector fileList; + fileList.push_back(startlist); + + string zipped = getTempFile(); + zip(zipped.c_str(), 0, fileList); + ProgressWindow pw(gdi.getTarget()); + pw.init(); + vector > key; + getAPIKey(key); + + string result = getTempFile(); + try { + dwl.postFile(eventorBase + "import/startlist", zipped, result, key, pw); + } + catch (std::exception &ex) { + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 1, "Operationen misslyckades: "); + gdi.addString("", 0, ex.what()).setColor(colorRed); + gdi.dropLine(2); + gdi.popX(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.addButton(bi.id, "Försök igen", CompetitionCB); + removeTempFile(startlist); + removeTempFile(zipped); + gdi.refresh(); + return 0; + } + + removeTempFile(startlist); + removeTempFile(zipped); + gdi.addString("", 1, "Klart"); + + xmlparser xml(0); + xml.read(result.c_str()); + xmlobject obj = xml.getObject("ImportStartListResult"); + if (obj) { + string url; + obj.getObjectString("StartListUrl", url); + if (url.length()>0) { + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addString("", 0, "Länk till startlistan:"); + gdi.addString("link", 0, url, CompetitionCB).setColor(colorRed); + } + } + gdi.dropLine(3); + gdi.popX(); + + gdi.addButton("CopyLink", "Kopiera länken till urklipp", CompetitionCB); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.refresh(); + } + else if (bi.id == "EventorResult") { + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + if (cnf.hasPatrol()) { + if (!gdi.ask("När denna version av MeOS släpptes kunde Eventor " + "inte hantera resultat från patrullklasser. Vill du försöka ändå?")) + return loadPage(gdi); + } + + gdi.clearPage(true); + gdi.fillDown(); + gdi.dropLine(); + gdi.addString("", boldLarge, "Publicerar resultat"); + + gdi.dropLine(); + gdi.fillDown(); + gdi.addString("", 1, "Ansluter till Internet").setColor(colorGreen); + + gdi.refreshFast(); + Download dwl; + dwl.initInternet(); + + string resultlist = getTempFile(); + set classes; + bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0; + oe->exportIOFSplits(oEvent::IOF30, resultlist.c_str(), false, + eventorUTC, classes, -1, false, true, + false, true); + vector fileList; + fileList.push_back(resultlist); + + string zipped = getTempFile(); + zip(zipped.c_str(), 0, fileList); + ProgressWindow pw(gdi.getTarget()); + pw.init(); + vector > key; + getAPIKey(key); + + string result = getTempFile(); + + try { + dwl.postFile(eventorBase + "import/resultlist", zipped, result, key, pw); + } + catch (std::exception &ex) { + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 1, "Operationen misslyckades: "); + gdi.addString("", 0, ex.what()).setColor(colorRed); + gdi.dropLine(2); + gdi.popX(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.addButton(bi.id, "Försök igen", CompetitionCB); + removeTempFile(resultlist); + removeTempFile(zipped); + gdi.refresh(); + return 0; + } + + removeTempFile(resultlist); + removeTempFile(zipped); + gdi.addString("", 1, "Klart"); + + xmlparser xml(0); + xml.read(result.c_str()); + xmlobject obj = xml.getObject("ImportResultListResult"); + if (obj) { + string url; + obj.getObjectString("ResultListUrl", url); + if (url.length()>0) { + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addString("", 0, "Länk till resultatlistan:"); + gdi.addString("link", 0, url, CompetitionCB).setColor(colorRed); + } + } + gdi.dropLine(3); + gdi.popX(); + + gdi.addButton("CopyLink", "Kopiera länken till urklipp", CompetitionCB); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.refresh(); + } + else if (bi.id == "Eventor") { + if (checkEventor(gdi, bi)) + return 0; + + SYSTEMTIME st; + GetLocalTime(&st); + st.wYear--; // Include last years competitions + getEventorCompetitions(gdi, convertSystemDate(st), events); + gdi.clearPage(true); + + gdi.addString("", boldLarge, "Hämta data från Eventor"); + + gdi.dropLine(); + gdi.addButton("EventorAPI", "Anslutningsinställningar...", CompetitionCB); + gdi.dropLine(); + gdi.fillRight(); + gdi.pushX(); + gdi.addCheckbox("EventorCmp", "Hämta tävlingsdata", CompetitionCB, true); + gdi.addSelection("EventorSel", 300, 200); + sort(events.begin(), events.end()); + st.wYear++; // Restore current time + string now = convertSystemDate(st); + + int selected = 0; // Select next event by default + for (int k = events.size()-1; k>=0; k--) { + string n = events[k].Name + " (" + events[k].Date + ")"; + gdi.addItem("EventorSel", n, k); + if (now < events[k].Date || selected == 0) + selected = k; + } + gdi.selectItemByData("EventorSel", selected); + + gdi.dropLine(3); + gdi.popX(); + gdi.addCheckbox("EventorDb", "Uppdatera löpardatabasen", CompetitionCB, true); + gdi.dropLine(3); + gdi.popX(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.addButton("EventorNext", "Nästa >>", CompetitionCB); + } + else if (bi.id == "EventorCmp") { + gdi.setInputStatus("EventorSel", gdi.isChecked(bi.id)); + gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) | gdi.isChecked("EventorDb")); + } + else if (bi.id == "EventorDb") { + gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) | gdi.isChecked("EventorCmp")); + } + else if (bi.id == "EventorNext") { + bool cmp = gdi.isChecked("EventorCmp"); + bool db = gdi.isChecked("EventorDb"); + ListBoxInfo lbi; + gdi.getSelectedItem("EventorSel", lbi); + const CompetitionInfo *ci = 0; + if (lbi.data < events.size()) + ci = &events[lbi.data]; + + gdi.clearPage(true); + gdi.setData("UpdateDB", db); + gdi.pushX(); + if (cmp && ci) { + gdi.setData("EventIndex", lbi.data); + gdi.setData("EventorId", ci->Id); + gdi.addString("", boldLarge, "Hämta tävlingsdata för X#" + ci->Name); + gdi.dropLine(0.5); + + gdi.fillRight(); + gdi.pushX(); + + int tt = convertAbsoluteTimeHMS(ci->firstStart, -1); + string ttt = tt>0 ? ci->firstStart : ""; + gdi.addInput("FirstStart", ttt, 10, 0, "Första ordinarie starttid:", "Skriv första starttid på formen HH:MM:SS"); + + gdi.addSelection("StartType", 200, 150, 0, "Startmetod", "help:startmethod"); + gdi.addItem("StartType", lang.tl("Gemensam start"), SMCommon); + gdi.addItem("StartType", lang.tl("Lottad startlista"), SMDrawn); + gdi.addItem("StartType", lang.tl("Fria starttider"), SMFree); + gdi.addItem("StartType", lang.tl("Jag sköter lottning själv"), SMCustom); + gdi.selectFirstItem("StartType"); + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + + gdi.addInput("LastEntryDate", ci->lastNormalEntryDate, 10, 0, "Sista ordinarie anmälningsdatum:"); + + if (oe->getNumRunners() > 0) { + gdi.addCheckbox("RemoveRemoved", "Ta bort eventuella avanmälda deltagare", 0, true); + } + + gdi.addString("", boldText, "Importera banor"); + gdi.addString("", 10, "help:ocad13091"); + gdi.fillRight(); + gdi.dropLine(); + gdi.addInput("FileName", "", 48, 0, "Filnamn (OCAD banfil):"); + gdi.dropLine(); + gdi.fillDown(); + gdi.addButton("BrowseCourse", "Bläddra...", CompetitionCB); + } + else { + gdi.addString("", boldLarge, "Hämta löpardatabasen"); + gdi.dropLine(0.5); + + bi.id = "EventorImport"; + return competitionCB(gdi, type, &bi); + } + + gdi.dropLine(1); + gdi.popX(); + gdi.setRestorePoint("DoEventor"); + gdi.fillRight(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB).setCancel(); + gdi.addButton("EventorImport", "Hämta data från Eventor", CompetitionCB).setDefault(); + gdi.fillDown(); + gdi.popX(); + } + else if (bi.id == "EventorImport") { + const int diffZeroTime = 3600; + DWORD id; + DWORD db; + gdi.getData("EventorId", id); + gdi.getData("UpdateDB", db); + + DWORD eventIndex; + gdi.getData("EventIndex", eventIndex); + const CompetitionInfo *ci = 0; + if (eventIndex < events.size()) + ci = &events[eventIndex]; + + bool removeRemoved = true; + if (gdi.hasField("RemoveRemoved")) + removeRemoved = gdi.isChecked("RemoveRemoved"); + + string course = gdi.getText("FileName", true); + int startType = 0; + const bool createNew = oe->getExtIdentifier() != id && id>0; + int zeroTime = 0; + int firstStart = 0; + string lastEntry; + if (id > 0 && createNew) { + string fs = gdi.getText("FirstStart"); + int t = oEvent::convertAbsoluteTime(fs); + if (t<0) { + string msg = "Ogiltig starttid: X#" + fs; + throw std::exception(msg.c_str()); + } + firstStart = t; + zeroTime = t - diffZeroTime; + if (zeroTime<0) + zeroTime += 3600*24; + + startType = gdi.getSelectedItem("StartType").first; + lastEntry = gdi.getText("LastEntryDate"); + } + + if (gdi.hasField("EventorImport")) { + gdi.disableInput("EventorImport"); + gdi.disableInput("FileName"); + gdi.disableInput("FirstStart"); + } + + string tEvent = getTempFile(); + string tClubs = getTempFile(); + string tClass = getTempFile(); + string tEntry = getTempFile(); + string tRunnerDB = db!= 0 ? getTempFile() : ""; + gdi.dropLine(3); + try { + getEventorCmpData(gdi, id, tEvent, tClubs, tClass, tEntry, tRunnerDB); + } + catch (std::exception &ex) { + gdi.popX(); + gdi.dropLine(); + gdi.fillDown(); + gdi.addString("", 0, string("Fel: X#") + ex.what()).setColor(colorRed); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.refresh(); + return 0; + } + + gdi.fillDown(); + gdi.dropLine(); + + if (db != 0) { + gdi.addString("", 1, "Behandlar löpardatabasen").setColor(colorGreen); + vector extractedFiles; + gdi.fillRight(); + gdi.addString("", 0 , "Packar upp löpardatabas..."); + gdi.refreshFast(); + unzip(tRunnerDB.c_str(), 0, extractedFiles); + gdi.addString("", 0 , "OK"); + gdi.refreshFast(); + gdi.dropLine(); + gdi.popX(); + gdi.fillDown(); + removeTempFile(tRunnerDB); + if (extractedFiles.size() != 1) { + gdi.addString("", 0, "Unexpected file contents: X#" + tRunnerDB).setColor(colorRed); + } + if (extractedFiles.empty()) + tRunnerDB.clear(); + else + tRunnerDB = extractedFiles[0]; + } + + oe->importXML_IOF_Data(tClubs.c_str(), tRunnerDB.c_str(), true); + removeTempFile(tClubs); + + if (id > 0) { + gdi.dropLine(); + gdi.addString("", 1, "Behandlar tävlingsdata").setColor(colorGreen); + + if (createNew && id>0) { + gdi.addString("", 1, "Skapar ny tävling"); + oe->newCompetition("New"); + + oe->importXML_EntryData(gdi, tEvent.c_str(), false, false); + oe->setZeroTime(formatTimeHMS(zeroTime)); + oe->getDI().setDate("OrdinaryEntry", lastEntry); + if (ci) { + if (!ci->account.empty()) + oe->getDI().setString("Account", ci->account); + + if (!ci->url.empty()) + oe->getDI().setString("Homepage", ci->url); + } + } + removeTempFile(tEvent); + + oe->importXML_EntryData(gdi, tClass.c_str(), false, false); + removeTempFile(tClass); + + oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved); + removeTempFile(tEntry); + + if (!course.empty()) { + gdi.dropLine(); + TabCourse::runCourseImport(gdi, course, oe, true); + } + + bool drawn = false; + if (createNew && startType>0) { + gdi.scrollToBottom(); + gdi.dropLine(); + + switch (startType) { + case SMCommon: + oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), "0", "0", false, false, 1); + drawn = true; + break; + + case SMDrawn: + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + bool skip = false; + if (!cnf.classWithoutCourse.empty()) { + string cls = ""; + for (size_t k = 0; k < cnf.classWithoutCourse.size(); k++) { + if (k>=5) { + cls += "..."; + break; + } + if (k>0) + cls += ", "; + cls += cnf.classWithoutCourse[k]; + } + if (!gdi.ask("ask:missingcourse#" + cls)) { + gdi.addString("", 0, "Skipper lottning"); + skip = true; + } + } + if (!skip) + oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), "2:00", "2", true, true, 1); + drawn = true; + break; + } + } + } + + gdi.dropLine(); + gdi.addString("", 1, "Klart").setColor(colorGreen); + + if (id > 0) { + oe->getMeOSFeatures().useFeature(MeOSFeatures::Speaker, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Economy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::EditClub, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Network, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Vacancy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::InForest, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::DrawStartList, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Bib, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::RunnerDb, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *oe); + + if (oe->hasTeam()) { + oe->getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *oe); + } + } + gdi.scrollToBottom(); + gdi.dropLine(); + if (gdi.hasField("Cancel")) + gdi.disableInput("Cancel"); // Disable "cancel" above + gdi.fillRight(); + if (id > 0) + gdi.addButton("StartIndividual", "Visa startlistan", ListsCB); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.refreshFast(); + + } + else if (bi.id == "Cancel"){ + loadPage(gdi); + } + else if (bi.id == "WelcomeOK") { + gdi.scaleSize(1.0/gdi.getScale()); + oe->setProperty("FirstTime", 0); + loadPage(gdi); + } + else if (bi.id == "dbtest") { + + } + else if (bi.id=="FreeImport") { + gdi.clearPage(true); + gdi.addString("", 2, "Fri anmälningsimport"); + gdi.addString("", 10, "help:33940"); + gdi.dropLine(0.5); + gdi.addInputBox("EntryText", 550, 280, entryText, 0, ""); + gdi.dropLine(0.5); + gdi.fillRight(); + gdi.addButton("PreviewImport", "Granska inmatning", CompetitionCB, "tooltip:analyze"); + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.addButton("Paste", "Klistra in", CompetitionCB, "tooltip:paste"); + gdi.addButton("ImportFile", "Importera fil...", CompetitionCB, "tooltip:import"); + gdi.addButton("ImportDB", "Bygg databaser...", CompetitionCB, "tooltip:builddata"); + gdi.fillDown(); + } + else if (bi.id=="ImportDB") { + if (!gdi.ask("help:146122")) + return 0; + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.xml;*.meos")); + string file = gdi.browseForOpen(ext, "xml"); + + if (file.empty()) + return 0; + gdi.setWaitCursor(true); + oe->getFreeImporter(fi); + string info; + + oe->importXMLNames(file.c_str(), fi, info); + fi.save(); + gdi.alert(info); + gdi.setWaitCursor(false); + } + else if (bi.id=="Paste") { + gdi.pasteText("EntryText"); + } + else if (bi.id=="ImportFile") { + vector< pair > ext; + ext.push_back(make_pair("Textfiler", "*.txt")); + + string file=gdi.browseForOpen(ext, "txt"); + ifstream fin(file.c_str()); + char bf[1024]; + bf[0]='\r'; + bf[1]='\n'; + entryText.clear(); + while (fin.good() && !fin.eof()) { + fin.getline(bf+2, 1024-2); + entryText+=bf; + } + entryText+="\r\n"; + fin.close(); + + gdi.setText("EntryText", entryText); + } + else if (bi.id=="PreviewImport") { + oe->getFreeImporter(fi); + entryText=gdi.getText("EntryText"); + gdi.clearPage(false); + gdi.addString("", 2, "Förhandsgranskning, import"); + gdi.dropLine(0.5); + char *bf=new char[entryText.length()+1]; + strcpy_s(bf, entryText.length()+1, entryText.c_str()); + fi.extractEntries(bf, entries); + delete[] bf; + vector cls; + oe->getClasses(cls, true); + for (size_t k = 0; k < entries.size(); k++) { + if (entries[k].eClass.empty()) { + if (!cls.empty()) { + entries[k].eClass = cls.back()->getName(); // Fallback + } + else { + entries[k].eClass = lang.tl("Klass"); + } + } + } + + fi.showEntries(gdi, entries); + gdi.fillRight(); + gdi.dropLine(1); + gdi.addButton("DoFreeImport", "Spara anmälningar", CompetitionCB); + gdi.addButton("FreeImport", "Ändra", CompetitionCB); + + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.scrollToBottom(); + } + else if (bi.id=="DoFreeImport") { + fi.addEntries(oe, entries); + entryText.clear(); + loadPage(gdi); + } + else if (bi.id=="Startlist") { + save(gdi, false); + oe->sanityCheck(gdi, false); + selectStartlistOptions(gdi); + } + else if (bi.id=="BrowseExport" || bi.id=="BrowseExportResult") { + int filterIndex = gdi.getSelectedItem("Type").first; + vector< pair > ext; + ImportFormats::getExportFilters(bi.id=="BrowseExport", ext); + /*if (bi.id=="BrowseExport") { + ext.push_back(make_pair("IOF Startlista (xml)", "*.xml")); + ext.push_back(make_pair("OE Semikolonseparerad (csv)", "*.csv")); + ext.push_back(make_pair("Webbdokument (html)", "*.html;*.htm")); + } + else { + ext.push_back(make_pair("IOF Resultat (xml)", "*.xml")); + ext.push_back(make_pair("OE Semikolonseparerad (csv)", "*.csv")); + ext.push_back(make_pair("Webbdokument (html)", "*.html")); + }*/ + string save = gdi.browseForSave(ext, "xml", filterIndex); + + if (save.length() > 0) { + gdi.setText("Filename", save); + gdi.selectItemByData("Type", filterIndex); + if (gdi.getExtra("Filename")) { + gdi.enableInput((char *)gdi.getExtra("Filename")); + } + } + } + else if (bi.id=="DoSaveStartlist") { + string save = gdi.getText("Filename"); + if (save.empty()) + throw meosException("Filnamn kan inte vara tomt"); + + bool individual = !gdi.hasField("ExportTeam") || gdi.isChecked("ExportTeam"); + + bool includeStage = true; + if (gdi.hasField("IncludeRaceNumber")) + includeStage = gdi.isChecked("IncludeRaceNumber"); + + gdi.getSelection("ClassNewEntries", allTransfer); + ImportFormats::ExportFormats filterIndex = ImportFormats::setExportFormat(*oe, gdi.getSelectedItem("Type").first); + int cSVLanguageHeaderIndex = gdi.getSelectedItem("LanguageType").first; + + gdi.setWaitCursor(true); + + if (filterIndex == ImportFormats::IOF30 || filterIndex == ImportFormats::IOF203) { + bool useUTC = oe->getDCI().getInt("UTC") != 0; + oe->exportIOFStartlist(filterIndex == ImportFormats::IOF30 ? oEvent::IOF30 : oEvent::IOF20, + save.c_str(), useUTC, allTransfer, individual, includeStage, false); + } + else if (filterIndex == ImportFormats::OE) { + oe->exportOECSV(save.c_str(), cSVLanguageHeaderIndex, false); + } + else { + oListParam par; + par.listCode = EStdStartList; + par.setLegNumberCoded(-1); + oListInfo li; + par.selection = allTransfer; + oe->generateListInfo(par, gdi.getLineHeight(), li); + gdioutput tGdi("temp", gdi.getScale(), gdi.getEncoding()); + oe->generateList(tGdi, true, li, false); + tGdi.writeTableHTML(gdi.toWide(save), oe->getName(), 0); + tGdi.openDoc(save.c_str()); + } + loadPage(gdi); + } + else if (bi.id=="Splits") { + save(gdi, false); + oe->sanityCheck(gdi, true); + selectExportSplitOptions(gdi); + } + else if (bi.id == "DoSaveSplits") { + string save = gdi.getText("Filename"); + if (save.empty()) + throw meosException("Filnamn kan inte vara tomt"); + + //bool individual = !gdi.hasField("ExportTeam") || gdi.isChecked("ExportTeam"); + gdi.getSelection("ClassNewEntries", allTransfer); + + ImportFormats::ExportFormats filterIndex = ImportFormats::setExportFormat(*oe, gdi.getSelectedItem("Type").first); + int cSVLanguageHeaderIndex = gdi.getSelectedItem("LanguageType").first; + bool includeSplits = gdi.isChecked("ExportSplitTimes"); + + bool unroll = gdi.isChecked("UnrollLoops"); // If not applicable, field does not exist. + bool includeStage = true; + if (gdi.hasField("IncludeRaceNumber")) + includeStage = gdi.isChecked("IncludeRaceNumber"); + + gdi.setWaitCursor(true); + if (filterIndex == ImportFormats::IOF30 || filterIndex == ImportFormats::IOF203) { + oEvent::IOFVersion ver = filterIndex == ImportFormats::IOF30 ? oEvent::IOF30 : oEvent::IOF20; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + bool useUTC = oe->getDCI().getInt("UTC") != 0; + + if (!cnf.hasTeamClass()) { + oe->exportIOFSplits(ver, save.c_str(), true, useUTC, + allTransfer, -1, false, unroll, includeStage, false); + } + else { + ListBoxInfo leglbi; + gdi.getSelectedItem("LegType", leglbi); + string file = save; + if (leglbi.data == 2) { + string fileBase; + string fileEnd = file.substr(file.length()-4); + if (_stricmp(fileEnd.c_str(), ".XML") == 0) + fileBase = file.substr(0, file.length() - 4); + else { + fileEnd = ".xml"; + fileBase = file; + } + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + int legMax = cnf.getNumLegsTotal(); + for (int leg = 0; legexportIOFSplits(ver, file.c_str(), true, useUTC, + allTransfer, leg, false, unroll, includeStage, false); + } + } + else if (leglbi.data == 3) { + oe->exportIOFSplits(ver, file.c_str(), true, useUTC, allTransfer, + -1, true, unroll, includeStage, false); + } + else { + int leg = leglbi.data == 1 ? -1 : leglbi.data - 10; + oe->exportIOFSplits(ver, file.c_str(), true, useUTC, allTransfer, + leg, false, unroll, includeStage, false); + } + } + } + else if (filterIndex == ImportFormats::OE) { + oe->exportOECSV(save.c_str(), cSVLanguageHeaderIndex, includeSplits); + } + else { + oListParam par; + par.listCode = EStdResultList; + par.showSplitTimes = true; + par.setLegNumberCoded(-1); + oListInfo li; + oe->generateListInfo(par, gdi.getLineHeight(), li); + gdioutput tGdi("temp", gdi.getScale(), gdi.getEncoding()); + oe->generateList(tGdi, true, li, false); + tGdi.writeTableHTML(gdi.toWide(save), oe->getName(), 0); + tGdi.openDoc(save.c_str()); + } + + loadPage(gdi); + } + else if (bi.id=="SaveAs") { + oe->sanityCheck(gdi, false); + save(gdi, true); + exportFileAs(hWndMain, gdi); + } + else if (bi.id=="Duplicate") { + oe->duplicate(); + gdi.alert("Skapade en lokal kopia av tävlingen."); + } + else if (bi.id=="Import") { + //Import complete competition + importFile(hWndMain, gdi); + loadPage(gdi); + } + else if (bi.id=="Restore") { + listBackups(gdi); + } + else if (bi.id=="Save") { + save(gdi, true); + resetSaveTimer(); + } + else if (bi.id=="CloseCmp") { + gdi.setWaitCursor(true); + if (!showConnectionPage) + save(gdi, false); + oe->save(); + oe->newCompetition(""); + resetSaveTimer(); + gdi.setWindowTitle(""); + if (showConnectionPage) + loadConnectionPage(gdi); + else + loadPage(gdi); + gdi.setWaitCursor(false); + } + else if (bi.id=="Delete" && + gdi.ask("Vill du verkligen radera tävlingen?")) { + + if (oe->isClient()) + oe->dropDatabase(); + else if (!oe->deleteCompetition()) + gdi.alert("Operation failed. It is not possible to delete competitions on server"); + + oe->clearListedCmp(); + oe->newCompetition(""); + gdi.setWindowTitle(""); + loadPage(gdi); + } + else if (bi.id=="NewCmp") { + bool guideMode = true; + if (guideMode) { + newCompetitionGuide(gdi, 0); + return 0; + } + + oe->newCompetition(lang.tl("Ny tävling")); + gdi.setWindowTitle(""); + + if (useEventor()) { + int age = getRelativeDay() - oe->getPropertyInt("DatabaseUpdate", 0); + if (age>60 && gdi.ask("help:dbage")) { + bi.id = "EventorUpdateDB"; + if (checkEventor(gdi, bi)) + return 0; + return competitionCB(gdi, type, &bi); + } + } + + loadPage(gdi); + return 0; + } + else if (bi.id=="OpenCmp") { + ListBoxInfo lbi; + int id=0; + bool frontPage=true; + if (!gdi.getSelectedItem("CmpSel", lbi)) { + frontPage=false; + if ( gdi.getSelectedItem("ServerCmp", lbi) ) + id=lbi.data; + else if ( gdi.getSelectedItem("LocalCmp", lbi) ) + id=lbi.data; + } + else id=lbi.data; + + if (id==0) + throw meosException("Ingen tävling vald."); + + openCompetition(gdi, id); + + if (frontPage) + loadPage(gdi); + else { + oe->setProperty("UseDirectSocket", gdi.isChecked("UseDirectSocket")); + oe->verifyConnection(); + oe->validateClients(); + loadConnectionPage(gdi); + } + + if (oe->isClient() && oe->getPropertyInt("UseDirectSocket", true) != 0) { + oe->getDirectSocket().startUDPSocketThread(gdi.getMain()); + } + return 0; + } + else if (bi.id=="BrowseCourse") { + vector< pair > ext; + ext.push_back(make_pair("Banor, OCAD semikolonseparerat", "*.csv;*.txt")); + ext.push_back(make_pair("Banor, IOF (xml)", "*.xml")); + + string file = gdi.browseForOpen(ext, "csv"); + if (file.length()>0) + gdi.setText("FileName", file); + } + else if (bi.id=="BrowseEntries") { + vector< pair > ext; + ext.push_back(make_pair("Importerbara", "*.xml;*.csv")); + ext.push_back(make_pair("IOF (xml)", "*.xml")); + ext.push_back(make_pair("OE Semikolonseparerad (csv)", "*.csv")); + + string file = gdi.browseForOpen(ext, "xml"); + if (file.length()>0) { + const char *ctrl = bi.getExtra(); + if (ctrl != 0) + gdi.setText(ctrl, file); + } + } + else if (bi.id=="Entries") { + if (!save(gdi, false)) + return 0; + + gdi.clearPage(false); + + entryForm(gdi, false); + + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("DoImport", "Importera", CompetitionCB); + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB); + gdi.popX(); + gdi.refresh(); + } + else if (bi.id=="DoImport") { + gdi.enableEditControls(false); + gdi.disableInput("DoImport"); + gdi.disableInput("Cancel"); + gdi.disableInput("BrowseEntries"); + bool removeRemoved = gdi.isChecked("RemoveRemoved"); + + try { + gdi.autoRefresh(true); + saveEntries(gdi, removeRemoved, false); + } + catch (std::exception &) { + gdi.enableEditControls(true); + gdi.enableInput("DoImport"); + gdi.enableInput("Cancel"); + gdi.enableInput("BrowseEntries"); + gdi.refresh(); + throw; + } + + gdi.addButton("Cancel", "OK", CompetitionCB); + gdi.refresh(); + } + else if (bi.id=="Courses") { + if (!save(gdi, false)) + return 0; + TabCourse::setupCourseImport(gdi, CompetitionCB); + } + else if (bi.id=="DoImportCourse") { + string filename = gdi.getText("FileName"); + if (filename.empty()) + return 0; + gdi.disableInput("DoImportCourse"); + gdi.disableInput("Cancel"); + gdi.disableInput("BrowseCourse"); + gdi.disableInput("AddClasses"); + + try { + TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses")); + } + catch (std::exception &) { + gdi.enableInput("DoImportCourse"); + gdi.enableInput("Cancel"); + gdi.enableInput("BrowseCourse"); + gdi.enableInput("AddClasses"); + throw; + } + gdi.dropLine(); + gdi.addButton("Cancel", "OK", CompetitionCB); + gdi.refresh(); + } + else if (bi.id=="About") { + loadAboutPage(gdi); + } + else if (bi.id == "DBEntry") { + int classId = gdi.getSelectedItem("Classes").first; + + DWORD data; + gdi.getData("RunnerIx", data); + RunnerDBEntry *dbr = oe->getRunnerDatabase().getRunnerByIndex(data); + + // Construct runner from database + oRunner sRunner(oe, 0); + sRunner.init(*dbr); + pRunner added = oe->addRunnerFromDB(&sRunner, classId, true); + if (added) + added->synchronize(); + loadRunnerDB(gdi, 1, false); + } + else if (bi.id == "CancelRunnerDatabase") { + if (!oe->empty()) + loadRunnerDB(gdi, 0, false); + else + loadPage(gdi); + } + else if (bi.id == "CancelEntry") { + loadRunnerDB(gdi, 1, false); + } + else if (bi.id == "RunnerDB") { + loadRunnerDB(gdi, 1, true); + } + else if (bi.id == "ClubDB") { + loadRunnerDB(gdi, 2, true); + } + else if (bi.id == "ExportRunnerDB") { + xmlparser xml(gdi.getEncoding() == ANSI ? 0 : &gdi); + vector< pair > ext; + ext.push_back(make_pair("IOF Löpardatabas, version 3.0 (xml)", "*.xml")); + int ix; + string fileName = gdi.browseForSave(ext, "xml", ix); + if (fileName.empty()) + return false; + + gdi.setWaitCursor(true); + xml.openOutput(fileName.c_str(), false); + IOF30Interface writer(oe, false); + writer.writeRunnerDB(oe->getRunnerDatabase(), xml); + gdi.setWaitCursor(false); + } + else if (bi.id == "ExportClubDB") { + xmlparser xml(gdi.getEncoding() == ANSI ? 0 : &gdi); + vector< pair > ext; + ext.push_back(make_pair("IOF Klubbdatabas, version 3.0 (xml)", "*.xml")); + int ix; + string fileName = gdi.browseForSave(ext, "xml", ix); + if (fileName.empty()) + return false; + + gdi.setWaitCursor(true); + xml.openOutput(fileName.c_str(), false); + IOF30Interface writer(oe, false); + writer.writeClubDB(oe->getRunnerDatabase(), xml); + gdi.setWaitCursor(false); + } + else if (bi.id == "ClearDB") { + if (gdi.ask("ask:cleardb")) { + oe->getRunnerDatabase().clearClubs(); + oe->saveRunnerDatabase("database", true); + if (oe->isClient()) { + msUploadRunnerDB(oe); + } + loadRunnerDB(gdi, 0, false); + } + } + } + else if (type==GUI_LISTBOXSELECT) { + ListBoxInfo lbi=*(ListBoxInfo *)data; + if (lbi.id == "LocalCmp") { + gdi.selectItemByData("ServerCmp", -1); + gdi.sendCtrlMessage("OpenCmp"); + } + else if (lbi.id == "ServerCmp") { + gdi.selectItemByData("LocalCmp", -1); + gdi.sendCtrlMessage("OpenCmp"); + } + } + else if (type==GUI_LISTBOX) { + ListBoxInfo lbi=*(ListBoxInfo *)data; + + if (lbi.id=="LocalCmp") { + gdi.selectItemByData("ServerCmp", -1); + gdi.disableInput("Repair", true); + } + else if (lbi.id=="ServerCmp") { + gdi.selectItemByData("LocalCmp", -1); + gdi.enableInput("Repair", true); + } + else if (lbi.id=="TextSize") { + int textSize = lbi.data; + oe->setProperty("TextSize", textSize); + gdi.setFont(textSize, oe->getPropertyString("TextFont", "Arial"), interpetEncoding(lang.tl("encoding"))); + PostMessage(gdi.getTarget(), WM_USER + 2, TCmpTab, 0); + } + else if (lbi.id == "Language") { + lang.get().loadLangResource(lbi.text); + oe->updateTabs(true); + oe->setProperty("Language", lbi.text); + //gdi.setEncoding(interpetEncoding(lang.tl("encoding"))); + gdi.setFont(oe->getPropertyInt("TextSize", 0), oe->getPropertyString("TextFont", "Arial"), interpetEncoding(lang.tl("encoding"))); + PostMessage(gdi.getTarget(), WM_USER + 2, TCmpTab, 0); + } + else if (lbi.id == "PreEvent") { + gdi.setInputStatus("OpenPre", int(lbi.data)>0); + } + else if (lbi.id == "PostEvent") { + bool hasPost = int(lbi.data)>0; + gdi.setInputStatus("OpenPost", hasPost); + gdi.setInputStatus("TransferData", hasPost); + gdi.setInputStatus("CloneCmp", !hasPost); + } + else if (lbi.id == "StageNumber") { + int nr = int(lbi.data); + oe->setStageNumber(nr); + oe->synchronize(true); + } + else if (lbi.id == "Type") { + setExportOptionsStatus(gdi, lbi.data); + } + } + else if (type== GUI_INPUT) { + InputInfo ii=*(InputInfo *)data; + if (ii.id == "Filename") { + if (ii.getExtra()) { + gdi.setInputStatus((char *)ii.getExtra(), !ii.text.empty()); + } + } + else if (ii.id == "NumStages") { + int ns = gdi.getTextNo("NumStages"); + oe->setNumStages(ns); + oe->synchronize(true); + } + } + else if (type == GUI_INPUTCHANGE) { + InputInfo ii=*(InputInfo *)data; + if (ii.id == "Filename") { + if (ii.getExtra()) { + gdi.setInputStatus((char *)ii.getExtra(), !ii.text.empty()); + } + } + } + else if (type==GUI_EVENT) { + EventInfo ei=*(EventInfo *)data; + + if ( ei.id=="Connections" ) { + string s=gdi.getText("ClientName"); + loadConnectionPage(gdi); + gdi.setText("ClientName", s); + } + else if (ei.id=="CellAction") { + string org = ei.getOrigin(); + if (org == "runnerdb") { + int ix = ei.getExtraInt(); + const RunnerDBEntry *pRdb = oe->getRunnerDatabase().getRunnerByIndex(ix); + if (pRdb == 0) + throw meosException("Internal error"); + + const RunnerDBEntry &rdb = *pRdb; + vector classes; + bool suggest = oe->getClassesFromBirthYear(rdb.getBirthYear(), interpretSex(rdb.getSex()), classes); + + gdi.clearPage(true, false); + if (suggest || find(classes.begin(), classes.end(), lastSelectedClass) == classes.end()) { + if (classes.empty()) + lastSelectedClass = -1; + else + lastSelectedClass = classes.back(); + } + + string name; + rdb.getName(name); + gdi.addString("", boldLarge, "Anmäl X#" + name); + gdi.setData("RunnerIx", ix); + gdi.dropLine(); + gdi.addSelection("Classes", 200, 300, 0, "Klasser:"); + oe->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterNone); + + if (lastSelectedClass != -1) + gdi.selectItemByData("Classes", lastSelectedClass); + else + gdi.selectFirstItem("Classes"); + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("DBEntry", "Anmäl", CompetitionCB).setDefault(); + gdi.addButton("CancelEntry", "Avbryt", CompetitionCB).setCancel(); + gdi.refresh(); + } + } + } + else if (type==GUI_CLEAR) { + if (gdi.isInputChanged("")) { + if (gdi.hasField("SaveSettings")) { + gdi.sendCtrlMessage("SaveSettings"); + } + else { + string name=gdi.getText("Name"); + + if (!name.empty() && !oe->empty()) + save(gdi, false); + } + } + return 1; + } + return 0; +} + +void TabCompetition::openCompetition(gdioutput &gdi, int id) { + gdi.setWaitCursor(true); + string err; + try { + if (!oe->open(id)) { + gdi.alert("Kunde inte öppna tävlingen."); + return; + } + } + catch (const meosException &ex) { + err = ex.what(); + } + + if (gSI) gSI->SetZeroTime(oe->getZeroTimeNum()); + resetSaveTimer(); + oe->setProperty("LastCompetition", id); + gdi.setWindowTitle(oe->getTitleName()); + oe->updateTabs(); + + if (!err.empty()) { + gdi.alert(err); + } +} + +int TabCompetition::restoreCB(gdioutput &gdi, int type, void *data) { + TextInfo &ti = *(TextInfo *)data; + int id = ti.getExtraInt(); + const BackupInfo &bi = oe->getBackup(id); + + if (ti.id == "") { + string fi(bi.FullPath); + if (!oe->open(fi.c_str(), false)) { + gdi.alert("Kunde inte öppna tävlingen."); + } + else { + if (gSI) gSI->SetZeroTime(oe->getZeroTimeNum()); + + const string &name = oe->getName(); + if (name.find_last_of("}") != name.length()-1) + oe->setName(name + " {" + lang.tl("återställd") +"}"); + + oe->restoreBackup(); + + gdi.setWindowTitle(oe->getTitleName()); + oe->updateTabs(); + resetSaveTimer(); + loadPage(gdi); + } + } + else if (ti.id == "EraseBackup") { + if (gdi.ask("Vill du ta bort alla säkerhetskopior på X?#" + bi.Name)) { + gdi.setWaitCursor(true); + oe->deleteBackups(bi); + listBackups(gdi); + } + } + return 0; +} + +void TabCompetition::listBackups(gdioutput &gdi) { + char bf[260]; + getUserFile(bf, ""); + int yo = gdi.GetOffsetY(); + gdi.clearPage(false); + oe->enumerateBackups(bf); + + gdi.addString("", boldLarge|Capitalize, "Lagrade säkerhetskopior"); + gdi.addString("", 0, "help:restore_backup"); + gdi.dropLine(0.4); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + gdi.dropLine(); + oe->listBackups(gdi, ::restoreCB); + gdi.scrollTo(0, yo); + gdi.refresh(); +} + +void TabCompetition::copyrightLine(gdioutput &gdi) const +{ + gdi.pushX(); + gdi.fillRight(); + + gdi.addButton("Help", "Hjälp", CompetitionCB, ""); + gdi.addButton("About", "Om MeOS...", CompetitionCB); + + gdi.dropLine(0.4); + gdi.fillDown(); + gdi.addString("", 0, MakeDash("#Copyright © 2007-2017 Melin Software HB")); + gdi.dropLine(1); + gdi.popX(); + + gdi.addString("", 0, getMeosFullVersion()).setColor(colorDarkRed); + gdi.dropLine(0.2); +} + +void TabCompetition::loadAboutPage(gdioutput &gdi) const +{ + gdi.clearPage(false); + gdi.addString("", 2, MakeDash("Om MeOS - ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue); + gdi.dropLine(2); + gdi.addStringUT(1, MakeDash("Copyright © 2007-2017 Melin Software HB")); + gdi.dropLine(); + gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright " + "(c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by MySQL AB," + "\nand (c) 2004-2007 by Educational Technology Resources, Inc.\n" + "The database used is MySQL, Copyright (c) 2008-2017 Oracle, Inc." + "\n\nGerman Translation by Erik Nilsson-Simkovics" + "\n\nDanish Translation by Michael Leth Jess and Chris Bagge" + "\n\nRussian Translation by Paul A. Kazakov and Albert Salihov" + "\n\nOriginal French Translation by Jerome Monclard" + "\n\nAdaption to French conditions and extended translation by Pierre Gaufillet"); + + gdi.dropLine(); + gdi.addString("", 0, "Det här programmet levereras utan någon som helst garanti. Programmet är "); + gdi.addString("", 0, "fritt att använda och du är välkommen att distribuera det under vissa villkor,"); + gdi.addString("", 0, "se license.txt som levereras med programmet."); + + gdi.dropLine(); + gdi.addString("", 1, "Vi stöder MeOS"); + vector supp; + getSupporters(supp); + for (size_t k = 0; kgetPropertyInt("UseEventor", 0) == 1; +} + +bool TabCompetition::loadPage(gdioutput &gdi) +{ + if (oe->getPropertyInt("FirstTime", 1) == 1) { + welcomeToMeOS(gdi); + return true; + } + showConnectionPage=false; + oe->checkDB(); + gdi.clearPage(true); + gdi.fillDown(); + + if (oe->empty()) { + gdi.addString("", 2, "Välkommen till MeOS"); + gdi.addString("", 1, MakeDash("#- ")+ lang.tl("ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue); + gdi.dropLine(); + + if (oe->getPropertyInt("UseEventor", 0) == 0) { + if ( gdi.ask("eventor:question#" + lang.tl("eventor:help")) ) + oe->setProperty("UseEventor", 1); + else + oe->setProperty("UseEventor", 2); + } + + gdi.fillRight(); + gdi.pushX(); + + gdi.addSelection("CmpSel", 300, 400, CompetitionCB, "Välj tävling:"); + + char bf[260]; + getUserFile(bf, ""); + oe->enumerateCompetitions(bf, "*.meos"); + oe->fillCompetitions(gdi, "CmpSel",0); + gdi.autoGrow("CmpSel"); + gdi.selectFirstItem("CmpSel"); + + int lastCmp = oe->getPropertyInt("LastCompetition", 0); + gdi.selectItemByData("CmpSel", lastCmp); + + gdi.dropLine(); + gdi.addButton("OpenCmp", "Öppna", CompetitionCB, "Öppna vald tävling").setDefault(); + + gdi.dropLine(4); + gdi.popX(); + + gdi.addButton("NewCmp", "Ny tävling", CompetitionCB, "Skapa en ny, tom, tävling"); + if (useEventor()) + gdi.addButton("Eventor", "Tävling från Eventor...", CompetitionCB, "Skapa en ny tävling med data från Eventor"); + gdi.addButton("ConnectMySQL", "Databasanslutning...", CompetitionCB, "Anslut till en server"); + + gdi.popX(); + gdi.dropLine(2.5); + gdi.addButton("Import", "Importera tävling...", CompetitionCB, "Importera en tävling från fil"); + gdi.addButton("Restore", "Återställ säkerhetskopia...", CompetitionCB, "Visa tillgängliga säkerhetskopior"); + gdi.addButton("LocalSettings", "Ändra lokala inställningar...", CompetitionCB); + + gdi.popX(); + gdi.dropLine(3); + + gdi.dropLine(2.3); + textSizeControl(gdi); + + gdi.popX(); + gdi.dropLine(3); + if (enableTests) { + gdi.fillRight(); + gdi.addButton("SaveTest", "#Save test", CompetitionCB); + gdi.addButton("RunTest", "#Run tests", CompetitionCB); + gdi.addSelection("Tests", 200, 200, 0); + vector< pair > tests; + TestMeOS tm(oe, "ALL"); + tm.getTests(tests); + gdi.addItem("Tests", tests); + gdi.selectFirstItem("Tests"); + gdi.addButton("RunSpecificTest", "#Run", CompetitionCB); + + gdi.dropLine(2); + gdi.popX(); + } + + gdi.fillDown(); + + copyrightLine(gdi); + + gdi.addButton(gdi.GetPageX()-gdi.scaleLength(180), + gdi.getCY()-gdi.getButtonHeight(), + "Exit", "Avsluta", CompetitionCB); + gdi.setInputFocus("CmpSel", true); + } + else { + oe->checkNecessaryFeatures(); + gdi.selectTab(tabId); + + gdi.addString("", 3, "MeOS"); + gdi.dropLine(); + oe->synchronize(); + + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("Name", oe->getName(), 24, 0, "Tävlingsnamn:"); + gdi.fillDown(); + + gdi.addInput("Annotation", oe->getAnnotation(), 20, 0, "Kommentar / version:") + .setBgColor(colorLightCyan); + gdi.popX(); + + gdi.fillRight(); + gdi.addInput("Date", oe->getDate(), 8, 0, "Datum:"); + gdi.addInput("ZeroTime", oe->getZeroTime(), 8, 0, "Nolltid:"); + + gdi.fillDown(); + gdi.dropLine(1.2); + gdi.addCheckbox("LongTimes", "Aktivera stöd för tider över 24 timmar", CompetitionCB, oe->useLongTimes()); + + if (oe->isClient()) { + gdi.popX(); + gdi.disableInput("ZeroTime"); + gdi.disableInput("LongTimes"); + if (oe->useLongTimes()) + gdi.disableInput("Date"); + } + else { + gdi.popX(); + if (!oe->useLongTimes()) + gdi.addString("ZeroTimeHelp", 0, "help:zero_time"); + else { + gdi.addString("ZeroTimeHelp", 0, "help:long_times"); + gdi.disableInput("ZeroTime"); + } + } + + gdi.fillRight(); + gdi.dropLine(); + + if (oe->getExtIdentifier() > 0 && useEventor()) { + gdi.addButton("SynchEventor", "Eventorkoppling", CompetitionCB, "Utbyt tävlingsdata med Eventor"); + } + + gdi.addButton("Settings", "Tävlingsinställningar", CompetitionCB); + gdi.addButton("Report", "Tävlingsrapport", CompetitionCB); + gdi.addButton("Features", "MeOS Funktioner", CompetitionCB); + +#ifdef _DEBUG + gdi.addButton("Test", "Test", CompetitionCB); +#endif + + gdi.fillDown(); + gdi.popX(); + + gdi.dropLine(3); + + //gdi.fillRight(); + //gdi.addCheckbox("UseEconomy", "Hantera klubbar och ekonomi", CompetitionCB, oe->useEconomy()); + //gdi.addCheckbox("UseSpeaker", "Använd speakerstöd", CompetitionCB, oe->getDCI().getInt("UseSpeaker")!=0); + //gdi.popX(); + //gdi.dropLine(2); + + //gdi.addCheckbox("UseRunnerDb", "Använd löpardatabasen", CompetitionCB, oe->useRunnerDb()); + + //gdi.popX(); + //gdi.dropLine(2); + textSizeControl(gdi); + + gdi.dropLine(4); + gdi.popX(); + gdi.fillRight(); + gdi.addButton("Save", "Spara", CompetitionCB, "help:save"); + gdi.addButton("SaveAs", "Spara som fil...", CompetitionCB, ""); + gdi.addButton("Duplicate", "Duplicera", CompetitionCB, "help:duplicate"); + + gdi.addButton("Delete", "Radera", CompetitionCB); + gdi.addButton("CloseCmp", "Stäng", CompetitionCB); + + gdi.dropLine(2.5); + gdi.popX(); + +#ifdef D_DEBUG + gdi.dropLine(2.5); + gdi.popX(); + gdi.addButton("CloneEvent", "#! Klona", CompetitionCB); +#endif + + gdi.fillDown(); + gdi.popX(); + + gdi.newColumn(); + gdi.dropLine(3); + gdi.setCX(gdi.getCX()+gdi.scaleLength(60)); + + RECT rc; + rc.top = gdi.getCY() - gdi.scaleLength(30); + rc.left = gdi.getCX() - gdi.scaleLength(30); + + int bw = gdi.scaleLength(150); + gdi.addString("", 1, "Importera tävlingsdata"); + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "Entries", "Anmälningar", + CompetitionCB, "", false, false); + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "FreeImport", "Fri anmälningsimport", + CompetitionCB, "", false, false); + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "Courses", "Banor", + CompetitionCB, "", false, false); + + gdi.dropLine(); + gdi.addString("", 1, "Exportera tävlingsdata"); + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "Startlist", "Startlista", + CompetitionCB, "Exportera startlista på fil", false, false); + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "Splits", "Resultat && sträcktider", + CompetitionCB, "Exportera resultat på fil", false, false); + + gdi.dropLine(); + gdi.addString("", 1, "Funktioner"); + if (oe->useRunnerDb()) { + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "RunnerDatabase", "Löpardatabasen", + CompetitionCB, "Visa och hantera löpardatabasen", false, false); + } + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::SeveralStages)) { + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "MultiEvent", "Hantera flera etapper", + CompetitionCB, "", false, false); + } + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "SaveAs", "Säkerhetskopiera", + CompetitionCB, "", false, false); + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Network)) { + gdi.addButton(gdi.getCX(), gdi.getCY(), bw, "ConnectMySQL", "Databasanslutning", + CompetitionCB, "", false, false); + } + rc.bottom = gdi.getCY() + gdi.scaleLength(30); + rc.right = rc.left + bw + gdi.scaleLength(60); + + gdi.addRectangle(rc, colorLightBlue); + + gdi.popX(); + + gdi.dropLine(3); + copyrightLine(gdi); + + gdi.setOnClearCb(CompetitionCB); + } + gdi.refresh(); + return true; +} + +void TabCompetition::textSizeControl(gdioutput &gdi) const +{ + gdi.dropLine(); + int s = oe->getPropertyInt("TextSize", 0); + const char *id="TextSize"; + gdi.fillRight(); + RECT rc; + int x = gdi.getCX() + gdi.scaleLength(15); + gdi.dropLine(-0.5); + rc.top = gdi.getCY() - gdi.scaleLength(10); + rc.left = gdi.getCX(); + + gdi.setCX(x); + + gdi.addString("", 1, "Programinställningar"); + gdi.dropLine(2); + gdi.setCX(x); + //gdi.addString("", 0, "Textstorlek:"); + + gdi.addSelection(id, 90, 200, CompetitionCB, "Textstorlek:"); + gdi.addItem(id, lang.tl("Normal"), 0); + gdi.addItem(id, lang.tl("Stor"), 1); + gdi.addItem(id, lang.tl("Större"), 2); + gdi.addItem(id, lang.tl("Störst"), 3); + gdi.selectItemByData(id, s); + + id = "Language"; + gdi.addSelection(id, 150, 300, CompetitionCB, "Språk:"); + vector ln = lang.get().getLangResource(); + string current = oe->getPropertyString("Language", "Svenska"); + int ix = -1; + for (size_t k = 0; kempty()) { + gdi.setCX(gdi.getCX()+gdi.getLineHeight()*2); + gdi.dropLine(); + gdi.addButton("Setup", "Inställningar...", CompetitionCB); + + rc.right = gdi.getCX() + gdi.scaleLength(15); + + gdi.setCX(x); + gdi.dropLine(3); + + gdi.addCheckbox("UseEventor", "Använd Eventor", CompetitionCB, + useEventor(), "eventor:help"); + + rc.bottom = gdi.getCY() + gdi.scaleLength(25); + } + else { + rc.right = gdi.getWidth();//gdi.getCX() + gdi.scaleLength(10); + rc.bottom = gdi.getCY() + gdi.scaleLength(50); + } + + gdi.addRectangle(rc, colorLightYellow); + gdi.dropLine(); +} + +int TabCompetition::getOrganizer(bool updateEvent) { + string apikey = oe->getPropertyStringDecrypt("apikey", ""); + if (apikey.empty()) + return 0; + if (!isAscii(apikey)) + return 0; + + Download dwl; + dwl.initInternet(); + vector< pair > key; + string file = getTempFile(); + key.push_back(pair("ApiKey", apikey)); + string url = eventorBase + "organisation/apiKey"; + try { + dwl.downloadFile(url, file, key); + } + catch (dwException &ex) { + if (ex.code == 403) + return 0; + else { + throw std::exception("Kunde inte ansluta till Eventor."); + } + } + catch (std::exception &) { + throw std::exception("Kunde inte ansluta till Eventor."); + } + + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(50); + } + + int clubId = 0; + + xmlparser xml(0); + xmlList xmlEvents; + try { + xml.read(file.c_str()); + xmlobject obj = xml.getObject("Organisation"); + if (obj) { + clubId = obj.getObjectInt("OrganisationId"); + obj.getObjectString("Name", eventor.name); + + xmlobject ads = obj.getObject("Address"); + if (ads) { + ads.getObjectString("careOf", eventor.careOf); + ads.getObjectString("street", eventor.street); + ads.getObjectString("city", eventor.city); + ads.getObjectString("zipCode", eventor.zipCode); + } + + xmlobject tele = obj.getObject("Tele"); + + if (tele) { + tele.getObjectString("mailAddress", eventor.email); + } + + xmlobject aco = obj.getObject("Account"); + if (aco) { + aco.getObjectString("AccountNo", eventor.account); + } + } + } + catch (std::exception &) { + removeTempFile(file); + throw; + } + + removeTempFile(file); + + return clubId; +} + +void TabCompetition::getAPIKey(vector< pair > &key) const { + string apikey = oe->getPropertyStringDecrypt("apikey", ""); + + if (apikey.empty() || organizorId == 0) + throw std::exception("Internal error"); + + key.clear(); + key.push_back(pair("ApiKey", apikey)); +} + +void TabCompetition::getEventorCompetitions(gdioutput &gdi, + const string &fromDate, + vector &events) const +{ + events.clear(); + + vector< pair > key; + getAPIKey(key); + + string file = getTempFile(); + string url = eventorBase + "events?fromDate=" + fromDate + + "&organisationIds=" + itos(organizorId) + "&includeEntryBreaks=true"; + Download dwl; + dwl.initInternet(); + + try { + dwl.downloadFile(url, file, key); + } + catch (std::exception &) { + removeTempFile(file); + throw; + } + + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(100); + } + xmlparser xml(0); + xmlList xmlEvents; + + try { + xml.read(file.c_str()); + xmlobject obj = xml.getObject("EventList"); + obj.getObjects("Event", xmlEvents); + } + catch (std::exception &) { + removeTempFile(file); + throw; + } + + removeTempFile(file); + + for (size_t k = 0; k < xmlEvents.size(); k++) { + CompetitionInfo ci; + xmlEvents[k].getObjectString("Name", ci.Name); + ci.Id = xmlEvents[k].getObjectInt("EventId"); + xmlobject date = xmlEvents[k].getObject("StartDate"); + date.getObjectString("Date", ci.Date); + if (date.getObject("Clock")) + date.getObjectString("Clock", ci.firstStart); + + if (useEventorUTC()) { + int offset = getTimeZoneInfo(ci.Date); + int t = convertAbsoluteTimeISO(ci.firstStart); + int nt = t - offset; + int dayOffset = 0; + if (nt < 0) { + nt += 24*3600; + dayOffset = -1; + } + else if (nt > 24*3600) { + nt -= 24*3600; + dayOffset = 1; + } + ci.firstStart = formatTimeHMS(nt); + //TODO: Take dayoffset into account + } + + xmlEvents[k].getObjectString("WebURL", ci.url); + xmlobject aco = xmlEvents[k].getObject("Account"); + if (aco) { + string type = aco.getAttrib("type").get(); + string no; + aco.getObjectString("AccountNo", no); + + if (type == "bankGiro") + ci.account = "BG " + no; + else if (type == "postalGiro") + ci.account = "PG " + no; + else + ci.account = no; + } + + ci.lastNormalEntryDate = ""; + xmlList entryBreaks; + xmlEvents[k].getObjects("EntryBreak", entryBreaks); + /* Mats Troeng explains Entry Break 2011-04-03: + Efteranmälan i detta fall är satt som en tilläggsavgift (+50%) på ordinarie avgift. + Tilläggsavgiften är aktiv 2011-04-13 -- 2011-04-20, medan den ordinarie avgiften är aktiv -- 2011-04-20. Man kan också + definiera enligt ditt andra exempel i Eventor om man vill, men då måste man sätta ett fixt belopp i stället för en + procentsats för efteranmälan eftersom det inte finns något belopp att beräkna procentsatsen på. + + För att få ut anmälningsstoppen för en tävling tittar man alltså på unionen av alla (ValidFromDate - 1 sekund) + samt ValidToDate. I normalfallet är det två stycken, varav det första är ordinarie anmälningsstopp. + För t ex O-Ringen som har flera anmälningsstopp blir det mer än två EntryBreaks. + */ + for (size_t k = 0; k= breakDate) + ci.lastNormalEntryDate = breakDate; + } + + eBreak = entryBreaks[k].getObject("ValidToDate"); + if (eBreak) { + string breakDate; + eBreak.getObjectString("Date", breakDate); + if (ci.lastNormalEntryDate.empty() || ci.lastNormalEntryDate >= breakDate) + ci.lastNormalEntryDate = breakDate; + + } + } + + events.push_back(ci); + } +} + +void TabCompetition::getEventorCmpData(gdioutput &gdi, int id, + const string &eventFile, + const string &clubFile, + const string &classFile, + const string &entryFile, + const string &dbFile) const +{ + ProgressWindow pw(gdi.getHWND()); + pw.init(); + gdi.fillDown(); + gdi.addString("", 1, "Ansluter till Internet").setColor(colorGreen); + gdi.dropLine(0.5); + gdi.refreshFast(); + Download dwl; + dwl.initInternet(); + + pw.setProgress(1); + vector< pair > key; + string apikey = oe->getPropertyStringDecrypt("apikey", ""); + key.push_back(pair("ApiKey", apikey)); + + gdi.fillRight(); + + int prg = 0; + int event_prg = dbFile.empty() ? 1000 / 4 : 1000/6; + int club_prg = event_prg; + + if (id > 0) { + gdi.addString("", 0, "Hämtar tävling..."); + gdi.refreshFast(); + dwl.downloadFile(eventorBase + "export/event?eventId=" + itos(id) + iofExportVersion, eventFile, key); + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(100); + } + if (!dwl.successful()) + throw std::exception("Download failed"); + + prg += int(event_prg * 0.2); + pw.setProgress(prg); + gdi.addString("", 0, "OK"); + gdi.popX(); + gdi.dropLine(); + + gdi.addString("", 0, "Hämtar klasser..."); + gdi.refreshFast(); + dwl.downloadFile(eventorBase + "export/classes?eventId=" + itos(id) + iofExportVersion, classFile, key); + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(100); + } + + if (!dwl.successful()) + throw std::exception("Download failed"); + + prg += event_prg; + pw.setProgress(prg); + gdi.addString("", 0, "OK"); + gdi.popX(); + gdi.dropLine(); + + + gdi.addString("", 0, "Hämtar anmälda..."); + gdi.refreshFast(); + dwl.downloadFile(eventorBase + "export/entries?eventId=" + itos(id) + iofExportVersion, entryFile, key); + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(100); + } + if (!dwl.successful()) + throw std::exception("Download failed"); + + prg += int(event_prg * 1.8); + pw.setProgress(prg); + gdi.addString("", 0, "OK"); + gdi.popX(); + gdi.dropLine(); + } + + + gdi.addString("", 0, "Hämtar klubbar..."); + gdi.refreshFast(); + dwl.downloadFile(eventorBase + "export/clubs?" + iofExportVersion, clubFile, key); + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(100); + } + if (!dwl.successful()) + throw std::exception("Download failed"); + + prg += club_prg; + pw.setProgress(prg); + gdi.addString("", 0, "OK"); + gdi.popX(); + gdi.dropLine(); + + if (dbFile.length() > 0) { + gdi.addString("", 0, "Hämtar löpardatabasen..."); + gdi.refreshFast(); + dwl.downloadFile(eventorBase + "export/cachedcompetitors?organisationIds=1&includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key); + dwl.createDownloadThread(); + while (dwl.isWorking()) { + Sleep(100); + } + + if (!dwl.successful()) + throw std::exception("Download failed"); + + pw.setProgress(1000); + gdi.addString("", 0, "OK"); + } + + gdi.popX(); + gdi.dropLine(); +} + +void TabCompetition::saveMultiEvent(gdioutput &gdi) { + ListBoxInfo lbiPre, lbiPost; + + gdi.getSelectedItem("PreEvent", lbiPre); + gdi.getSelectedItem("PostEvent", lbiPost); + + int idPost = lbiPost.data; + int idPre = lbiPre.data; + + string nameIdPost = oe->getNameId(idPost); + string nameIdPre = oe->getNameId(idPre); + string nameId = oe->getNameId(0); + if (nameIdPost == nameId || nameIdPre == nameId || (nameIdPost == nameIdPre && !nameIdPost.empty())) + throw meosException("Ogiltig föregående/efterföljande etapp."); + + if (idPost == -2) + oe->getDI().setString("PostEvent", ""); + else if (!nameIdPost.empty()) + oe->getDI().setString("PostEvent", nameIdPost); + + if (idPre == -2) + oe->getDI().setString("PreEvent", ""); + else if (!nameIdPre.empty()) + oe->getDI().setString("PreEvent", nameIdPre); +} + +void TabCompetition::loadMultiEvent(gdioutput &gdi) { + if (oe->isClient()) { + throw meosException("info:multieventnetwork"); + } + + gdi.clearPage(false); + gdi.addString("", boldLarge, "Hantera flera etapper"); + + gdi.setRestorePoint("MultiHeader"); + gdi.dropLine(); + + gdi.pushX(); + gdi.fillRight(); + + string preEvent = oe->getDCI().getString("PreEvent"); + string postEvent = oe->getDCI().getString("PostEvent"); + + gdi.addSelection("PreEvent", 300, 200, CompetitionCB, "Föregående etapp:", "Välj den etapp som föregår denna tävling"); + char bf[260]; + getUserFile(bf, ""); + oe->enumerateCompetitions(bf, "*.meos"); + + oe->fillCompetitions(gdi, "PreEvent", 1, preEvent); + gdi.addItem("PreEvent", lang.tl("Ingen / okänd"), -2); + bool hasPre = !gdi.getText("PreEvent").empty(); + if (!hasPre) + gdi.selectItemByData("PreEvent", -2); + + gdi.addSelection("PostEvent", 300, 200, CompetitionCB, "Nästa etapp:", "Välj den etapp som kommer efter denna tävling"); + oe->fillCompetitions(gdi, "PostEvent", 1, postEvent); + gdi.addItem("PostEvent", lang.tl("Ingen / okänd"), -2); + bool hasPost = !gdi.getText("PostEvent").empty(); + + if (!hasPost) + gdi.selectItemByData("PostEvent", -2); + + gdi.dropLine(5); + gdi.popX(); + gdi.fillRight(); + + int numStages = oe->getNumStages(); + gdi.addSelection("StageNumber", 100, 200, CompetitionCB, "Denna etapps nummer:"); + gdi.addItem("StageNumber", lang.tl("Inget nummer"), -2); + for (int k = 1; k <= 52; k++) + gdi.addItem("StageNumber", lang.tl("Etapp X#" + itos(k)), k); + int sn = oe->getStageNumber(); + if (sn>=1 && sn <= 52) { + gdi.selectItemByData("StageNumber", sn); + if (oe->hasNextStage()) + numStages = max(numStages, sn+1); + else + numStages = max(numStages, sn); + + oe->setNumStages(numStages); + oe->synchronize(true); + } + else + gdi.selectFirstItem("StageNumber"); + + gdi.fillDown(); + gdi.addInput("NumStages", numStages > 0 ? itos(numStages) : _EmptyString, 4, CompetitionCB, "Totalt antal etapper:"); + + gdi.fillRight(); + gdi.dropLine(2); + gdi.addButton("OpenPre", "Öppna föregående", CompetitionCB, "Öppna nästa etapp"); + gdi.addButton("OpenPost", "Öppna nästa", CompetitionCB, "Öppna föregående etapp"); + + gdi.dropLine(3); + gdi.popX(); + + gdi.addButton("SaveMulti", "Spara", CompetitionCB); + gdi.addButton("CloneCmp", "Lägg till ny etapp...", CompetitionCB); + gdi.addButton("TransferData", "Överför resultat till nästa etapp", CompetitionCB); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + + gdi.setInputStatus("OpenPre", hasPre); + gdi.setInputStatus("OpenPost", hasPost); + gdi.setInputStatus("TransferData", hasPost); + gdi.setInputStatus("CloneCmp", !hasPost); + + gdi.refresh(); +} + +void TabCompetition::loadRunnerDB(gdioutput &gdi, int tableToShow, bool updateTableOnly) { + if (!updateTableOnly) { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Löpardatabasen"); + + gdi.setRestorePoint("DBHeader"); + } + else { + gdi.restore("DBHeader", false); + } + gdi.dropLine(); + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("RunnerDB", "Personer", CompetitionCB, "Visa löpardatabasen"); + gdi.addButton("ClubDB", "Klubbar", CompetitionCB, "Visa klubbdatabasen"); + gdi.addButton("DBaseIn", "Importera", CompetitionCB, "Importera IOF (xml)"); + if (useEventor()) + gdi.addButton("EventorUpdateDB", "Uppdatera", CompetitionCB, "Uppdatera från Eventor"); + gdi.addButton("ExportSetup", "Exportera", CompetitionCB, "Exportera på fil"); + gdi.addButton("Cancel", "Återgå", CompetitionCB); + + gdi.dropLine(3); + gdi.popX(); + + //if (tableToShow != 0) { + gdi.fillRight(); + gdi.addButton("ExportRunnerDB", "Exportera personer (IOF-XML)", CompetitionCB); + gdi.addButton("ExportClubDB", "Exportera klubbar (IOF-XML)", CompetitionCB); + gdi.addButton("ClearDB", "Töm databasen", CompetitionCB); + gdi.dropLine(3); + gdi.popX(); + + if (oe->isClient()) { + gdi.fillDown(); + gdi.addString("", 10, "info:runnerdbonline"); + gdi.dropLine(); + //gdi.disableInput("ExportRunnerDB"); + //gdi.disableInput("ExportClubDB"); + gdi.disableInput("ClearDB"); + } + //} + + if (tableToShow == 1) { + oe->updateRunnerDatabase(); + Table *tb = oe->getRunnerDatabase().getRunnerTB(); + gdi.addTable(tb, 40, gdi.getCY()); + gdi.registerEvent("CellAction", CompetitionCB); + } + else if (tableToShow == 2) { + oe->updateRunnerDatabase(); + Table *tb = oe->getRunnerDatabase().getClubTB(); + gdi.addTable(tb, 40, gdi.getCY()); + } + + gdi.refresh(); +} + +void TabCompetition::welcomeToMeOS(gdioutput &gdi) { + gdi.clearPage(false, false); + gdi.scaleSize(1.8/gdi.getScale()); + gdi.dropLine(5); + gdi.setCX(gdi.getCX() + 5*gdi.getLineHeight()); + + gdi.addString("", 2, "Välkommen till MeOS"); + gdi.addString("", 1, MakeDash("#- ")+ lang.tl("ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue); + gdi.dropLine(); + gdi.addString("", 0, getMeosFullVersion()); + gdi.dropLine(2); + gdi.addStringUT(0, "Välj språk / Preferred language / Sprache"); + gdi.dropLine(); + gdi.fillRight(); + const char *id = "Language"; + gdi.addSelection(id, 90, 200, CompetitionCB); + vector ln = lang.get().getLangResource(); + string current = oe->getPropertyString("Language", "Svenska"); + int ix = -1; + for (size_t k = 0; k &changedClass) const { + for (size_t k = 0; kgetName() + " (" + changedClass[k]->getClass() +", " + + changedClass[k]->getStartTimeS()+ ")"); + } +} + +void TabCompetition::selectTransferClasses(gdioutput &gdi, bool expand) { + gdi.restore("SelectTClass", false); + gdi.setRestorePoint("SelectTClass"); + + gdi.fillDown(); + gdi.addSelection("ChangeClassType", 300, 400, 0, "Hantera deltagare som bytt klass:"); + gdi.addItem("ChangeClassType", lang.tl("Byt till vakansplats i rätt klass (om möjligt)"), oEvent::ChangeClassVacant); + gdi.addItem("ChangeClassType", lang.tl("Byt till rätt klass (behåll eventuell starttid)"), oEvent::ChangeClass); + gdi.addItem("ChangeClassType", lang.tl("Tillåt ny klass, inget totalresultat"), oEvent::TransferNoResult); + gdi.addItem("ChangeClassType", lang.tl("Tillåt ny klass, behåll resultat från annan klass"), oEvent::TransferAnyway); + gdi.selectItemByData("ChangeClassType", lastChangeClassType); + + if (expand) { + gdi.fillDown(); + gdi.addListBox("ClassNewEntries", 200, 400, 0, "Klasser där nyanmälningar ska överföras:", "", true); + oe->fillClasses(gdi, "ClassNewEntries", oEvent::extraNone, oEvent::filterNone); + + gdi.setSelection("ClassNewEntries", allTransfer); + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("SelectAll", "Välj allt", CompetitionCB); + gdi.fillDown(); + gdi.addButton("SelectNone", "Välj inget", CompetitionCB); + gdi.popX(); + gdi.addCheckbox("TransferEconomy", "Överför nya deltagare i ej valda klasser med status \"deltar ej\""); + gdi.fillRight(); + } + else { + gdi.fillRight(); + gdi.addButton("ExpandTResults", "Välj klasser med nya anmälningar", CompetitionCB); + } + + gdi.addButton("DoTransferData", "Överför resultat", CompetitionCB); + gdi.addButton("MultiEvent", "Återgå", CompetitionCB); + gdi.popX(); + gdi.dropLine(); + gdi.refresh(); +} + +static int ClearFeaturesCB(gdioutput *gdi, int type, void *data) +{ + TabCompetition &tc = dynamic_cast(*gdi->getTabs().get(TCmpTab)); + tc.saveMeosFeatures(*gdi, true); + return 1; +} + +static int CheckFeaturesCB(gdioutput *gdi, int type, void *data) +{ + TabCompetition &tc = dynamic_cast(*gdi->getTabs().get(TCmpTab)); + tc.saveMeosFeatures(*gdi, false); + tc.updateFeatureStatus(*gdi); + return 0; +} + +void TabCompetition::meosFeatures(gdioutput &gdi, bool newGuide) { + if (!newGuide) { + oe->checkNecessaryFeatures(); + gdi.clearPage(false); + gdi.addString("", boldLarge, MakeDash("MeOS - Funktioner")); + } + else { + gdi.dropLine(); + gdi.addString("", fontMediumPlus, MakeDash("MeOS - Funktioner")); + } + gdi.dropLine(0.5); + + const MeOSFeatures &mf = oe->getMeOSFeatures(); + int yp = gdi.getCY(); + int tx, ty; + gdi.getTargetDimension(tx, ty); + ty = max(ty-gdi.scaleLength(150), 300); + int nf = mf.getNumFeatures(); + int maxLen = gdi.scaleLength(150); + for (int k = 0; k < nf; k++) { + if (mf.isHead(k)) { + if (gdi.getCY() > ty) { + //gdi.newColumn(); + gdi.setCX(gdi.getCX() + maxLen + gdi.scaleLength(10)); + maxLen = gdi.scaleLength(150); + gdi.setCY(yp); + } + gdi.dropLine(0.6); + TextInfo &ti = gdi.addString("", fontMediumPlus, mf.getHead(k)); + maxLen = max(maxLen, ti.textRect.right - ti.textRect.left); + gdi.dropLine(0.4); + } + else { + MeOSFeatures::Feature f = mf.getFeature(k); + ButtonInfo &bi = gdi.addCheckbox("feat" + mf.getCode(f), mf.getDescription(f), + CheckFeaturesCB, mf.hasFeature(f)); + maxLen = max(maxLen, bi.width); + + if (mf.isRequired(f, *oe)) + gdi.setInputStatus("feat" + mf.getCode(f), false); + } + } + + gdi.dropLine(); + + if (!newGuide) { + gdi.fillRight(); + gdi.addButton("SaveFeaures", "Spara", CompetitionCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB).setCancel(); + gdi.setOnClearCb(ClearFeaturesCB); + + gdi.refresh(); + } + +} + +void TabCompetition::updateFeatureStatus(gdioutput &gdi) { + const MeOSFeatures &mf = oe->getMeOSFeatures(); + int nf = mf.getNumFeatures(); + for (int k = 0; k < nf; k++) { + if (!mf.isHead(k)) { + MeOSFeatures::Feature f = mf.getFeature(k); + string id = "feat" + mf.getCode(f); + gdi.check(id, mf.hasFeature(f)); + gdi.setInputStatus(id, !mf.isRequired(f, *oe)); + } + } + gdi.refresh(); +} + + +void TabCompetition::saveMeosFeatures(gdioutput &gdi, bool write) { + MeOSFeatures &mf = oe->getMeOSFeatures(); + + int nf = mf.getNumFeatures(); + for (int k = 0; k < nf; k++) { + if (!mf.isHead(k)) { + MeOSFeatures::Feature f = mf.getFeature(k); + string key = "feat" + mf.getCode(f); + mf.useFeature(f, gdi.isChecked(key), *oe); + } + } + if (write) { + oe->getDI().setString("Features", mf.serialize()); + oe->synchronize(true); + } +} + +void TabCompetition::entryForm(gdioutput &gdi, bool isGuide) { + if (isGuide) { + gdi.dropLine(1); + gdi.addString("", fontMediumPlus, "Importera tävlingsdata"); + } + else + gdi.addString("", 2, "Importera tävlingsdata"); + + gdi.dropLine(0.5); + gdi.addString("", 10, "help:import_entry_data"); + gdi.dropLine(); + + gdi.pushX(); + + gdi.fillRight(); + gdi.addInput("FileNameCmp", "", 48, 0, "Tävlingsinställningar (IOF, xml)"); + gdi.dropLine(); + gdi.addButton("BrowseEntries", "Bläddra...", CompetitionCB).setExtra("FileNameCmp"); + gdi.popX(); + + gdi.dropLine(2.5); + gdi.addInput("FileNameCls", "", 48, 0, "Klasser (IOF, xml)"); + gdi.dropLine(); + gdi.addButton("BrowseEntries", "Bläddra...", CompetitionCB).setExtra("FileNameCls"); + gdi.popX(); + + gdi.dropLine(2.5); + gdi.addInput("FileNameClb", "", 48, 0, "Klubbar (IOF, xml)"); + gdi.dropLine(); + gdi.addButton("BrowseEntries", "Bläddra...", CompetitionCB).setExtra("FileNameClb"); + gdi.popX(); + + gdi.dropLine(2.5); + gdi.addInput("FileName", "", 48, 0, "Anmälningar (IOF (xml) eller OE-CSV)"); + gdi.dropLine(); + gdi.addButton("BrowseEntries", "Bläddra...", CompetitionCB).setExtra("FileName"); + + gdi.popX(); + gdi.dropLine(3.2); + + if (!isGuide && oe->getNumRunners() > 0) { + gdi.addCheckbox("RemoveRemoved", "Ta bort eventuella avanmälda deltagare", 0, true); + } + gdi.popX(); + + gdi.dropLine(2.5); + gdi.addInput("FileNameRank", "", 48, 0, "Ranking (IOF, xml)"); + gdi.dropLine(); + gdi.addButton("BrowseEntries", "Bläddra...", CompetitionCB).setExtra("FileNameRank"); + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(3); +} + +void TabCompetition::saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide) { + string filename[5]; + filename[0] = gdi.getText("FileNameCmp"); + filename[1] = gdi.getText("FileNameCls"); + filename[2] = gdi.getText("FileNameClb"); + filename[3] = gdi.getText("FileName"); + filename[4] = gdi.getText("FileNameRank"); + + csvparser csv; + + for (int i = 0; i<5; i++) { + if (filename[i].empty()) + continue; + + gdi.addString("", 0, "Behandlar: X#" + filename[i]); + + int type=csv.iscsv(filename[i].c_str()); + + if (type) { + const char *File = filename[i].c_str(); + + if (type==1) { + gdi.addString("", 0, "Importerar OE2003 csv-fil..."); + gdi.refresh(); + gdi.setWaitCursor(true); + if (csv.ImportOE_CSV(*oe, File)) { + gdi.addString("", 0, "Klart. X deltagare importerade.#" + itos(csv.nimport)); + } + else gdi.addString("", 0, "Försöket misslyckades."); + } + else if (type==2) { + gdi.addString("", 0, "Importerar OS2003 csv-fil..."); + gdi.refresh(); + gdi.setWaitCursor(true); + if (csv.ImportOS_CSV(*oe, File)) { + gdi.addString("", 0, "Klart. X lag importerade.#" + itos(csv.nimport)); + } + else gdi.addString("", 0, "Försöket misslyckades."); + } + else if (type==3) { + gdi.addString("", 0, "Importerar RAID patrull csv-fil..."); + gdi.setWaitCursor(true); + if (csv.ImportRAID(*oe, File)) { + gdi.addString("", 0, "Klart. X patruller importerade.#" + itos(csv.nimport)); + } + else gdi.addString("", 0, "Försöket misslyckades."); + + } + } + else { + oe->importXML_EntryData(gdi, filename[i].c_str(), false, removeRemoved); + } + if (!isGuide) { + gdi.setWindowTitle(oe->getTitleName()); + oe->updateTabs(); + } + } +} + + +void TabCompetition::selectStartlistOptions(gdioutput &gdi) { + gdi.clearPage(true); + gdi.addString("", boldLarge, "Exportera startlista"); + gdi.pushY(); + gdi.addListBox("ClassNewEntries", 250, 400, 0, "Klassval:", "", true); + oe->fillClasses(gdi, "ClassNewEntries", oEvent::extraNone, oEvent::filterNone); + + gdi.setSelection("ClassNewEntries", allTransfer); + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("SelectAll", "Välj allt", CompetitionCB); + gdi.fillDown(); + gdi.addButton("SelectNone", "Välj inget", CompetitionCB); + gdi.popX(); + + gdi.newColumn(); + gdi.pushX(); + gdi.popY(); + gdi.addSelection("Type", 250, 200, CompetitionCB, "Exporttyp:"); + + vector< pair > types; + ImportFormats::getExportFormats(types, false); + gdi.addItem("Type", types); + ImportFormats::ExportFormats format = ImportFormats::getDefaultExportFormat(*oe); + gdi.selectItemByData("Type", format); + + vector< pair > typeLanguages; + ImportFormats::getOECSVLanguage(typeLanguages); + + gdi.addSelection("LanguageType", 250, 200, CompetitionCB, "Export language:"); + gdi.addItem("LanguageType", typeLanguages); + + gdi.selectItemByData("LanguageType", ImportFormats::getDefaultCSVLanguage(*oe)); + + + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + + if (oe->hasTeam()) { + gdi.addCheckbox("ExportTeam", "Exportera individuella lopp istället för lag", 0, false); + } + if (oe->hasMultiRunner() || oe->getStageNumber() > 0) + gdi.addCheckbox("IncludeRaceNumber", "Inkludera information om flera lopp per löpare", 0, true); + + setExportOptionsStatus(gdi, format); + + gdi.addInput("Filename", "", 48, CompetitionCB, "Filnamn:").setExtra("DoSaveStartlist"); + gdi.fillRight(); + gdi.dropLine(); + gdi.addButton("BrowseExport", "Bläddra...", CompetitionCB); + gdi.addButton("DoSaveStartlist", "Exportera", CompetitionCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB).setCancel(); + gdi.disableInput("DoSaveStartlist"); + gdi.refresh(); +} + +void TabCompetition::selectExportSplitOptions(gdioutput &gdi) { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Export av resultat/sträcktider"); + gdi.dropLine(); + gdi.pushY(); + gdi.addListBox("ClassNewEntries", 250, 400, 0, "Klassval:", "", true); + oe->fillClasses(gdi, "ClassNewEntries", oEvent::extraNone, oEvent::filterNone); + + gdi.setSelection("ClassNewEntries", allTransfer); + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("SelectAll", "Välj allt", CompetitionCB); + gdi.fillDown(); + gdi.addButton("SelectNone", "Välj inget", CompetitionCB); + gdi.popX(); + gdi.newColumn(); + gdi.popY(); + gdi.pushX(); + gdi.addSelection("Type", 250, 200, CompetitionCB, "Exporttyp:"); + + vector< pair > types; + ImportFormats::getExportFormats(types, true); + + gdi.addItem("Type", types); + ImportFormats::ExportFormats format = ImportFormats::getDefaultExportFormat(*oe); + gdi.selectItemByData("Type", format); + + vector< pair > typeLanguages; + ImportFormats::getOECSVLanguage(typeLanguages); + + gdi.addSelection("LanguageType", 250, 200, CompetitionCB, "Export language:"); + gdi.addItem("LanguageType", typeLanguages); + + gdi.selectItemByData("LanguageType", ImportFormats::getDefaultCSVLanguage(*oe)); + + gdi.addCheckbox("ExportSplitTimes", "Export split times", 0, oe->getPropertyInt("ExportCSVSplits", false) != 0); + + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + + if (oe->hasTeam()) { + gdi.addSelection("LegType", 300, 100, 0, "Exportval, IOF-XML"); + gdi.addItem("LegType", lang.tl("Totalresultat"), 1); + gdi.addItem("LegType", lang.tl("Alla lopp som individuella"), 3); + gdi.addItem("LegType", lang.tl("Alla sträckor/lopp i separata filer"), 2); + int legMax = cnf.getNumLegsTotal(); + for (int k = 0; k crs; + oe->getCourses(crs); + for (size_t k = 0; k < crs.size(); k++) { + if (crs[k]->getCommonControl() != 0) + hasLoops = true; + } + if (hasLoops) + gdi.addCheckbox("UnrollLoops", "Unroll split times for loop courses", 0, true); + + if (oe->hasMultiRunner() || oe->getStageNumber() > 0) + gdi.addCheckbox("IncludeRaceNumber", "Inkludera information om flera lopp per löpare", 0, true); + + setExportOptionsStatus(gdi, format); + gdi.addInput("Filename", "", 48, CompetitionCB, "Filnamn:").setExtra("DoSaveSplits"); + gdi.fillRight(); + gdi.dropLine(); + gdi.addButton("BrowseExportResult", "Bläddra...", CompetitionCB); + gdi.addButton("DoSaveSplits", "Exportera", CompetitionCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB).setCancel(); + + gdi.disableInput("DoSaveSplits"); + gdi.refresh(); +} + +void TabCompetition::setExportOptionsStatus(gdioutput &gdi, int format) const { + if (gdi.hasField("LegType")) { + gdi.setInputStatus("LegType", format == ImportFormats::IOF30 || format == ImportFormats::IOF203); // Enable on IOF-XML + } + if (gdi.hasField("ExportTeam")) { + gdi.setInputStatus("ExportTeam", format == ImportFormats::IOF30); // Enable on IOF-XML + } + + if (gdi.hasField("ExportSplitTimes")) { + gdi.setInputStatus("ExportSplitTimes", format == ImportFormats::OE); + if (format == ImportFormats::IOF203 || format == ImportFormats::IOF30) + gdi.check("ExportSplitTimes", true); + } + + if (gdi.hasField("IncludeRaceNumber")) { + gdi.setInputStatus("IncludeRaceNumber", format == ImportFormats::IOF30); // Enable on IOF-XML + } + + gdi.setInputStatus("LanguageType", format == ImportFormats::OE); +} + +void TabCompetition::clearCompetitionData() { +} + +void TabCompetition::loadSettings(gdioutput &gdi) { + gdi.clearPage(false); + + gdi.addString("", boldLarge, "Tävlingsinställningar"); + gdi.dropLine(0.5); + vector fields; + gdi.pushY(); + gdi.addString("", 1, "Adress och kontakt"); + fields.push_back("Organizer"); + fields.push_back("CareOf"); + fields.push_back("Street"); + fields.push_back("Address"); + fields.push_back("EMail"); + fields.push_back("Homepage"); + + oe->getDI().buildDataFields(gdi, fields); + + gdi.dropLine(); + gdi.addString("", 1, "Tidszon"); + + gdi.dropLine(0.3); + gdi.addCheckbox("UTC", "Exportera tider i UTC", 0, + oe->getDCI().getInt("UTC") == 1); + + gdi.newColumn(); + gdi.popY(); + + gdi.addString("", 1, "Avgifter"); + fields.clear(); + gdi.fillRight(); + gdi.pushX(); + fields.push_back("CardFee"); + fields.push_back("EliteFee"); + fields.push_back("EntryFee"); + fields.push_back("YouthFee"); + + oe->getDI().buildDataFields(gdi, fields); + + gdi.popX(); + gdi.dropLine(3); + + fields.clear(); + fields.push_back("OrdinaryEntry"); + fields.push_back("LateEntryFactor"); + + oe->getDI().buildDataFields(gdi, fields); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + + gdi.addString("", 1, "Åldersgränser, reducerad anmälningsavgift"); + fields.clear(); + fields.push_back("YouthAge"); + fields.push_back("SeniorAge"); + gdi.fillRight(); + oe->getDI().buildDataFields(gdi, fields); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + + + gdi.addString("", 1, "Valuta"); + fields.clear(); + fields.push_back("CurrencySymbol"); + fields.push_back("CurrencyCode"); + + gdi.fillRight(); + oe->getDI().buildDataFields(gdi, fields); + + gdi.dropLine(); + gdi.addCheckbox("PreSymbol", "Valutasymbol före", 0, + oe->getDCI().getInt("CurrencyPreSymbol") == 1); + + gdi.popX(); + gdi.dropLine(3); + bool useFrac = oe->getDCI().getInt("CurrencyFactor") == 100; + gdi.addCheckbox("UseFraction", "Tillåt decimaler", CompetitionCB, + useFrac, "Tillåt valutauttryck med decimaler"); + + fields.clear(); + gdi.dropLine(-1); + fields.push_back("CurrencySeparator"); + oe->getDI().buildDataFields(gdi, fields); + + gdi.setInputStatus("CurrencySeparator_odc", useFrac); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + + gdi.addString("", 1, "Betalningsinformation"); + fields.clear(); + fields.push_back("Account"); + fields.push_back("PaymentDue"); + + oe->getDI().buildDataFields(gdi, fields); + + gdi.fillDown(); + gdi.addString("", 1, "Tävlingsregler"); + fields.clear(); + gdi.fillRight(); + gdi.pushX(); + fields.push_back("MaxTime"); + oe->getDI().buildDataFields(gdi, fields); + oe->getDI().fillDataFields(gdi); + + gdi.dropLine(3); + int bottom = gdi.getCY(); + + + gdi.newColumn(); + gdi.popY(); + gdi.pushX(); + gdi.fillDown(); + gdi.addString("", 1, "Betalningsmetoder"); + gdi.dropLine(); + gdi.addString("", 10, "help:paymentmodes"); + gdi.dropLine(); + vector< pair > modes; + oe->getPayModes(modes); + for (size_t k = 0; k < modes.size(); k++) { + gdi.fillRight(); + string ms = itos(modes[k].second); + gdi.addInput("M" + itos(k), modes[k].first, 24).setExtra(modes[k].second); + if (k > 0) + gdi.addButton(gdi.getCX(), gdi.getCY(), gdi.scaleLength(20), + "RemovePayMode", MakeDash("-"), CompetitionCB, + "Ta bort", false, false).setExtra(modes[k].second); + if (k == 0) + gdi.addButton(gdi.getCX(), gdi.getCY(), gdi.scaleLength(20), + "AddPayMode", "+", CompetitionCB, + "Lägg till", false, false); + + gdi.dropLine(2.5); + gdi.popX(); + } + bottom = max(bottom, gdi.getCY()); + + gdi.popX(); + gdi.setCY(bottom); + gdi.fillRight(); + gdi.addButton("SaveSettings", "Spara", CompetitionCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", CompetitionCB).setCancel(); + gdi.dropLine(2); + gdi.setOnClearCb(CompetitionCB); + gdi.refresh(); + +} + +void TabCompetition::saveSettings(gdioutput &gdi) { + vector fields; + vector fees(4); + fields.push_back("CardFee"); + fields.push_back("EliteFee"); + fields.push_back("EntryFee"); + fields.push_back("YouthFee"); + + for (int k = 0; k<4; k++) + fees[k] = oe->getDCI().getInt(fields[k]); + string factor = oe->getDCI().getString("LateEntryFactor"); + oe->getDI().saveDataFields(gdi); + + bool changedFee = false; + bool changedCardFee = false; + + for (int k = 0; k<4; k++) { + if (fees[k] != oe->getDCI().getInt(fields[k])) { + if (k > 0) + changedFee = true; + else { + changedCardFee = true; + if (oe->getDCI().getInt(fields[k]) == 0) + oe->getDI().setInt(fields[k].c_str(), -1); // Disallow zero card fee. -1 means no fee. + } + } + } + if (factor != oe->getDCI().getString("LateEntryFactor")) + changedFee = true; + + oe->getDI().setInt("UTC", gdi.isChecked("UTC") ? 1 : 0); + + oe->getDI().setInt("CurrencyFactor", gdi.isChecked("UseFraction") ? 100 : 1); + oe->getDI().setInt("CurrencyPreSymbol", gdi.isChecked("PreSymbol") ? 1 : 0); + oe->setCurrency(-1, "", "", false); + + vector< pair > modes; + oe->getPayModes(modes); + for (size_t k = 0; k < modes.size(); k++) { + string field = "M"+itos(k); + if (gdi.hasField(field)) { + string mode = gdi.getText("M"+itos(k)); + int id = gdi.getBaseInfo(field.c_str()).getExtraInt(); + oe->setPayMode(id, mode); + } + } + + // Read from model + if (oe->isChanged()) { + oe->setProperty("Organizer", oe->getDCI().getString("Organizer")); + oe->setProperty("Street", oe->getDCI().getString("Street")); + oe->setProperty("Address", oe->getDCI().getString("Address")); + oe->setProperty("EMail", oe->getDCI().getString("EMail")); + oe->setProperty("Homepage", oe->getDCI().getString("Homepage")); + + oe->setProperty("CardFee", oe->getDCI().getInt("CardFee")); + oe->setProperty("EliteFee", oe->getDCI().getInt("EliteFee")); + oe->setProperty("EntryFee", oe->getDCI().getInt("EntryFee")); + oe->setProperty("YouthFee", oe->getDCI().getInt("YouthFee")); + + oe->setProperty("YouthAge", oe->getDCI().getInt("YouthAge")); + oe->setProperty("SeniorAge", oe->getDCI().getInt("SeniorAge")); + + oe->setProperty("Account", oe->getDCI().getString("Account")); + oe->setProperty("LateEntryFactor", oe->getDCI().getString("LateEntryFactor")); + + oe->setProperty("CurrencySymbol", oe->getDCI().getString("CurrencySymbol")); + oe->setProperty("CurrencyFactor", oe->getDCI().getInt("CurrencyFactor")); + oe->setProperty("CurrencyPreSymbol", oe->getDCI().getInt("CurrencyPreSymbol")); + oe->setProperty("CurrencySeparator", oe->getDCI().getString("CurrencySeparator")); + + oe->setProperty("PayModes", oe->getDCI().getString("PayModes")); + } + oe->synchronize(true); + set dummy; + if (changedFee && oe->getNumClasses() > 0) { + bool updateFee = gdi.ask("ask:changedcmpfee"); + + if (updateFee) + oe->applyEventFees(true, true, changedCardFee, dummy); + } + else if (changedCardFee) + oe->applyEventFees(false, false, true, dummy); +} diff --git a/code/TabCompetition.h b/code/TabCompetition.h new file mode 100644 index 0000000..cb07347 --- /dev/null +++ b/code/TabCompetition.h @@ -0,0 +1,150 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "tabbase.h" + +#include "oFreeImport.h" + +class PrefsEditor; +class ImportFormats; + +class TabCompetition : + public TabBase +{ + string eventorBase; + string iofExportVersion; + void textSizeControl(gdioutput &gdi) const; + + bool showConnectionPage; + bool importFile(HWND hWnd, gdioutput &gdi); + bool exportFileAs(HWND hWnd, gdioutput &gdi); + + bool save(gdioutput &gdi, bool write = true); + + void loadRunnerDB(gdioutput &gdi, int tableToShow, bool updateTableOnly); + + // Events from Eventor + vector events; + list prefsEditor; + + oFreeImport fi; + string entryText; + vector entries; + void loadConnectionPage(gdioutput &gdi); + + string defaultServer; + string defaultName; + string defaultPwd; + string defaultPort; + + void copyrightLine(gdioutput &gdi) const; + void loadAboutPage(gdioutput &gdi) const; + + int organizorId; + + int lastChangeClassType; + + struct { + string name; + string careOf; + string street; + string city; + string zipCode; + string account; + string email; + } eventor; + + int getOrganizer(bool updateEvent); + void getAPIKey(vector< pair > &key) const; + void getEventorCompetitions(gdioutput &gdi, + const string &fromDate, + vector &events) const; + + void saveSettings(gdioutput &gdi); + void loadSettings(gdioutput &gdi); + + void getEventorCmpData(gdioutput &gdi, int id, + const string &eventFile, + const string &clubFile, + const string &classFile, + const string &entryFile, + const string &dbFile) const; + + void loadMultiEvent(gdioutput &gdi); + void saveMultiEvent(gdioutput &gdi); + + string eventorOrigin; // The command used when checking eventor + bool checkEventor(gdioutput &gdi, ButtonInfo &bi); + + bool useEventor() const; + bool useEventorUTC() const; + + void openCompetition(gdioutput &gdi, int id); + void selectTransferClasses(gdioutput &gdi, bool expand); + + // Welcome page for new users + void welcomeToMeOS(gdioutput &gdi); + + // Class id for last selected class for entry + int lastSelectedClass; + + set allTransfer; + + void displayRunners(gdioutput &gdi, const vector &changedClass) const; + + void meosFeatures(gdioutput &gdi, bool newGuide); + + void newCompetitionGuide(gdioutput &gdi, int step); + + void entryForm(gdioutput &gdi, bool isGuide); + void saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide); + void setExportOptionsStatus(gdioutput &gdi, int format) const; + + void selectStartlistOptions(gdioutput &gdi); + void selectExportSplitOptions(gdioutput &gdi); + + void entryChoice(gdioutput &gdi); + void createCompetition(gdioutput &gdi); + + void listBackups(gdioutput &gdi); +protected: + void clearCompetitionData(); + +public: + const char * getTypeStr() const {return "TCmpTab";} + TabType getType() const {return TCmpTab;} + + void saveMeosFeatures(gdioutput &gdi, bool write); + void updateFeatureStatus(gdioutput &gdi); + + void setEventorServer(const string &server); + void setEventorUTC(bool useUTC); + + int competitionCB(gdioutput &gdi, int type, void *data); + int restoreCB(gdioutput &gdi, int type, void *data); + int newGuideCB(gdioutput &gdi, int type, void *data); + + bool loadPage(gdioutput &gdi); + TabCompetition(oEvent *oe); + ~TabCompetition(void); +}; diff --git a/code/TabControl.cpp b/code/TabControl.cpp new file mode 100644 index 0000000..cc9d367 --- /dev/null +++ b/code/TabControl.cpp @@ -0,0 +1,529 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include "meos_util.h" +#include "gdifonts.h" +#include "table.h" +#include +#include "MeOSFeatures.h" + +#include "TabControl.h" + +TabControl::TabControl(oEvent *poe):TabBase(poe) +{ + clearCompetitionData(); +} + +TabControl::~TabControl(void) +{ +} + +void TabControl::selectControl(gdioutput &gdi, pControl pc) +{ + if (pc) { + pc->synchronize(); + + if (pc->getStatus() == oControl::StatusStart || + pc->getStatus() == oControl::StatusFinish) { + gdi.selectItemByData("Controls", pc->getId()); + gdi.selectItemByData("Status", oControl::StatusOK); + gdi.setText("ControlID", "-", true); + + gdi.setText("Code", ""); + gdi.setText("Name", pc->getName()); + gdi.setText("TimeAdjust", "00:00"); + gdi.setText("MinTime", "-"); + gdi.setText("Point", ""); + controlId = pc->getId(); + + gdi.enableInput("Remove"); + gdi.enableInput("Save"); + gdi.enableEditControls(false); + gdi.enableInput("Name"); + } + else { + gdi.selectItemByData("Controls", pc->getId()); + gdi.selectItemByData("Status", pc->getStatus()); + const int numVisit = pc->getNumVisitors(true); + const int numVisitExp = pc->getNumVisitors(false); + + string info; + if (numVisit > 0) { + info = "Antal besökare X, genomsnittlig bomtid Y, största bomtid Z#" + + itos(numVisit) + " (" + itos(numVisitExp) + ")#" + getTimeMS(pc->getMissedTimeTotal() / numVisit) + + "#" + getTimeMS(pc->getMissedTimeMax()); + } + else if (numVisitExp > 0) { + info = "Förväntat antal besökare: X#" + itos(numVisitExp); + } + gdi.setText("ControlID", itos(pc->getId()), true); + + gdi.setText("Info", lang.tl(info), true); + gdi.setText("Code", pc->codeNumbers()); + gdi.setText("Name", pc->getName()); + gdi.setText("TimeAdjust", pc->getTimeAdjustS()); + gdi.setText("MinTime", pc->getMinTimeS()); + if (gdi.hasField("Point")) + gdi.setText("Point", pc->getRogainingPointsS()); + + controlId = pc->getId(); + + gdi.enableInput("Remove"); + gdi.enableInput("Save"); + gdi.enableInput("Visitors"); + gdi.enableInput("Courses"); + gdi.enableEditControls(true); + + oControl::ControlStatus st = pc->getStatus(); + if (st == oControl::StatusRogaining || st == oControl::StatusNoTiming) + gdi.disableInput("MinTime"); + + if (st == oControl::StatusNoTiming) + gdi.disableInput("TimeAdjust"); + + if (gdi.hasField("Point") && st != oControl::StatusRogaining) + gdi.disableInput("Point"); + } + } + else { + gdi.selectItemByData("Controls", -1); + gdi.selectItemByData("Status", oControl::StatusOK); + gdi.setText("Code", ""); + gdi.setText("Name", ""); + controlId = 0; + + gdi.setText("ControlID", "-", true); + gdi.setText("TimeAdjust", "00:00"); + if (gdi.hasField("Point")) + gdi.setText("Point", ""); + + gdi.disableInput("Remove"); + gdi.disableInput("Save"); + gdi.disableInput("Visitors"); + gdi.disableInput("Courses"); + + gdi.enableEditControls(false); + } +} + +int ControlsCB(gdioutput *gdi, int type, void *data) +{ + TabControl &tc = dynamic_cast(*gdi->getTabs().get(TControlTab)); + return tc.controlCB(*gdi, type, data); +} + +void TabControl::save(gdioutput &gdi) +{ + if (controlId==0) + return; + + DWORD pcid = controlId; + + pControl pc; + pc = oe->getControl(pcid, false); + + if (!pc) + throw std::exception("Internal error"); + if (pc->getStatus() != oControl::StatusFinish && pc->getStatus() != oControl::StatusStart) { + if (!pc->setNumbers(gdi.getText("Code"))) + gdi.alert("Kodsiffran måste vara ett heltal. Flera kodsiffror måste separeras med komma."); + + pc->setStatus(oControl::ControlStatus(gdi.getSelectedItem("Status").first)); + pc->setTimeAdjust(gdi.getText("TimeAdjust")); + if (pc->getStatus() != oControl::StatusRogaining) { + if (pc->getStatus() != oControl::StatusNoTiming) + pc->setMinTime(gdi.getText("MinTime")); + pc->setRogainingPoints(0); + } + else { + if (gdi.hasField("Point")) { + pc->setMinTime(0); + pc->setRogainingPoints(gdi.getTextNo("Point")); + } + } + } + + pc->setName(gdi.getText("Name")); + + pc->synchronize(); + vector< pair > d; + oe->fillControls(d, oEvent::CTAll); + gdi.addItem("Controls", d); + + oe->reEvaluateAll(set(), true); + + selectControl(gdi, pc); +} + +static void visitorTable(Table &table, void *ptr) { + TabControl *view = (TabControl *)ptr; + view->visitorTable(table); +} + +static void courseTable(Table &table, void *ptr) { + TabControl *view = (TabControl *)ptr; + view->courseTable(table); +} + +void TabControl::courseTable(Table &table) const { + vector r; + oe->getRunners(0, 0, r, false); + map runnersPerCourse; + for (size_t k = 0; k < r.size(); k++) { + pCourse c = r[k]->getCourse(false); + int id = c != 0 ? c->getId() : 0; + ++runnersPerCourse[id]; + } + + vector crs; + oe->getCourses(crs); + + int ix = 1; + for (size_t k = 0; k < crs.size(); k++) { + vector pc; + crs[k]->getControls(pc); + int used = 0; + for (size_t j = 0; j < pc.size(); j++) { + if (pc[j]->getId() == controlId) { + used++; + } + } + + oCourse &it = *crs[k]; + if (used > 0) { + table.addRow(ix++, &it); + + int row = 0; + table.set(row++, it, TID_ID, itos(it.getId()), false); + table.set(row++, it, TID_MODIFIED, it.getTimeStamp(), false); + + table.set(row++, it, TID_COURSE, crs[k]->getName(), false); + table.set(row++, it, TID_INDEX, itos(used), false); + table.set(row++, it, TID_RUNNER, itos(runnersPerCourse[crs[k]->getId()]), false); + } + } +} + +void TabControl::visitorTable(Table &table) const { + vector c; + oe->getCards(c); + pControl pc = oe->getControl(controlId, false); + + if (!pc) + return; + vector n; + pc->getNumbers(n); + struct PI { + PI(int c, int type, int t) : card(c), code(type), time(t) {} + int card; + int code; + int time; + bool operator<(const PI&c) const { + if (card != c.card) + return card < c.card; + else if (code != c.code) + return code < c.code; + else + return time < c.time; + } + bool operator==(const PI&c) const { + return c.card == card && c.code == code && c.time == time; + } + }; + set registeredPunches; + vector p; + int ix=1; + for (size_t k = 0; k< c.size(); k++) { + oCard &it = *c[k]; + + it.getPunches(p); + //oPunch *punch = it.getPunchByType(pc->getFirstNumber()); //XXX + + for (size_t j = 0; j < p.size(); j++) { + + vector::iterator res = find(n.begin(), n.end(), p[j]->getTypeCode()); + if (res != n.end()) { + oPunch *punch = p[j]; + registeredPunches.insert(PI(it.getCardNo(), p[j]->getTypeCode(), p[j]->getAdjustedTime())); + table.addRow(ix++, &it); + + int row = 0; + table.set(row++, it, TID_ID, itos(it.getId()), false); + table.set(row++, it, TID_MODIFIED, it.getTimeStamp(), false); + + pRunner r = it.getOwner(); + if (r) { + table.set(row++, it, TID_RUNNER, r->getName(), false); + table.set(row++, it, TID_COURSE, r->getCourseName(), false); + } + else { + table.set(row++, it, TID_RUNNER, "-", false); + table.set(row++, it, TID_COURSE, "-", false); + } + table.set(row++, it, TID_FEE, punch->isUsedInCourse() ? + lang.tl("Ja") : lang.tl("Nej"), false); + table.set(row++, it, TID_CARD, it.getCardNoString(), false); + + table.set(row++, it, TID_STATUS, punch->getTime(), false); + table.set(row++, it, TID_CONTROL, punch->getType(), false); + table.set(row++, it, TID_CODES, j>0 ? p[j-1]->getType() : "-", true); + } + } + } +} + +int TabControl::controlCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="Save") + save(gdi); + else if (bi.id=="Add") { + bool rogaining = false; + if (controlId>0) { + save(gdi); + pControl pc = oe->getControl(controlId, false); + rogaining = pc && pc->getStatus() == oControl::StatusRogaining; + } + pControl pc = oe->addControl(0,oe->getNextControlNumber(), ""); + + if (rogaining) + pc->setStatus(oControl::StatusRogaining); + vector< pair > d; + oe->fillControls(d, oEvent::CTAll); + gdi.addItem("Controls", d); + selectControl(gdi, pc); + } + else if (bi.id=="Remove") { + + DWORD cid = controlId; + if (cid==0) { + gdi.alert("Ingen kontroll vald vald."); + return 0; + } + + if (oe->isControlUsed(cid)) + gdi.alert("Kontrollen används och kan inte tas bort."); + else + oe->removeControl(cid); + + vector< pair > d; + oe->fillControls(d, oEvent::CTAll); + gdi.addItem("Controls", d); + selectControl(gdi, 0); + } + else if (bi.id=="SwitchMode") { + if (!tableMode) + save(gdi); + tableMode = !tableMode; + loadPage(gdi); + } + else if (bi.id=="Visitors") { + save(gdi); + + Table *table=new Table(oe, 20, "Kontroll X#" + itos(controlId), "controlvisitor"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 150, false); + table->addColumn("Bana", 70, false); + table->addColumn("På banan", 70, false); + table->addColumn("Bricka", 70, true, true); + + table->addColumn("Tidpunkt", 70, false); + table->addColumn("Stämpelkod", 70, true); + table->addColumn("Föregående kontroll", 70, false); + table->setGenerator(::visitorTable, this); + table->setTableProp(0); + table->update(); + gdi.clearPage(false); + int xp=gdi.getCX(); + gdi.fillDown(); + gdi.addButton("Show", "Återgå", ControlsCB); + gdi.addTable(table, xp, gdi.getCY()); + gdi.refresh(); + } + else if (bi.id=="Courses") { + Table *table=new Table(oe, 20, "Kontroll X#" + itos(controlId), "controlcourse"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Bana", 70, false, true); + table->addColumn("Förekomst", 70, true, true); + table->addColumn("Antal deltagare", 70, true, true); + + table->setGenerator(::courseTable, this); + table->setTableProp(0); + table->update(); + gdi.clearPage(false); + int xp=gdi.getCX(); + gdi.fillDown(); + gdi.addButton("Show", "Återgå", ControlsCB); + gdi.addTable(table, xp, gdi.getCY()); + gdi.refresh(); + } + else if (bi.id=="Show") { + loadPage(gdi); + } + } + else if (type==GUI_LISTBOX){ + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Controls") { + if (gdi.isInputChanged("")) + save(gdi); + + pControl pc=oe->getControl(bi.data, false); + if (!pc) + throw std::exception("Internal error"); + + selectControl(gdi, pc); + } + else if (bi.id == "Status" ) { + gdi.setInputStatus("MinTime", bi.data != oControl::StatusRogaining && bi.data != oControl::StatusNoTiming, true); + gdi.setInputStatus("Point", bi.data == oControl::StatusRogaining, true); + gdi.setInputStatus("TimeAdjust", bi.data != oControl::StatusNoTiming, true); + } + } + else if (type==GUI_CLEAR) { + if (controlId>0) + save(gdi); + + return true; + } + return 0; +} + + +bool TabControl::loadPage(gdioutput &gdi) +{ + oe->checkDB(); + gdi.selectTab(tabId); + gdi.clearPage(false); + int xp=gdi.getCX(); + + const int button_w=gdi.scaleLength(90); + string switchMode; + switchMode=tableMode ? "Formulärläge" : "Tabelläge"; + gdi.addButton(2, 2, button_w, "SwitchMode", switchMode, + ControlsCB, "Välj vy", false, false).fixedCorner(); + + if (tableMode) { + Table *tbl=oe->getControlTB(); + gdi.addTable(tbl, xp, 30); + return true; + } + + gdi.fillDown(); + gdi.addString("", boldLarge, "Kontroller"); + + gdi.pushY(); + gdi.addListBox("Controls", 250, 530, ControlsCB).isEdit(false).ignore(true); + gdi.setTabStops("Controls", 40, 160); + + vector< pair > d; + oe->fillControls(d, oEvent::CTAll); + gdi.addItem("Controls", d); + + gdi.newColumn(); + gdi.fillDown(); + gdi.popY(); + + gdi.pushX(); + gdi.fillRight(); + gdi.addString("", 1, "Kontrollens ID-nummer:"); + gdi.fillDown(); + gdi.addString("ControlID", 1, "#-").setColor(colorGreen); + gdi.popX(); + + gdi.fillRight(); + gdi.addInput("Name", "", 16, 0, "Kontrollnamn:"); + + gdi.addSelection("Status", 150, 100, ControlsCB, "Status:", "Ange om kontrollen fungerar och hur den ska användas."); + oe->fillControlStatus(gdi, "Status"); + + gdi.addInput("TimeAdjust", "", 6, 0, "Tidsjustering:"); + gdi.fillDown(); + gdi.addInput("MinTime", "", 6, 0, "Minsta sträcktid:"); + + gdi.popX(); + gdi.dropLine(0.5); + gdi.addString("", 10, "help:9373"); + + gdi.fillRight(); + + gdi.dropLine(0.5); + gdi.addInput("Code", "", 16, 0, "Stämpelkod(er):"); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining)) { + gdi.addInput("Point", "", 6, 0, "Rogaining-poäng:"); + } + gdi.popX(); + gdi.dropLine(3.5); + + gdi.fillRight(); + gdi.addButton("Save", "Spara", ControlsCB, "help:save"); + gdi.disableInput("Save"); + gdi.addButton("Remove", "Radera", ControlsCB); + gdi.disableInput("Remove"); + gdi.addButton("Courses", "Banor...", ControlsCB); + gdi.addButton("Visitors", "Besökare...", ControlsCB); + gdi.addButton("Add", "Ny kontroll", ControlsCB); + + gdi.dropLine(2.5); + gdi.popX(); + + gdi.fillDown(); + + gdi.addString("Info", 0, "").setColor(colorGreen); + + gdi.dropLine(1.5); + gdi.addString("", 10, "help:89064"); + + selectControl(gdi, oe->getControl(controlId, false)); + + gdi.setOnClearCb(ControlsCB); + + gdi.refresh(); + return true; +} + +void TabControl::clearCompetitionData() { + tableMode = false; + controlId = 0; +} diff --git a/code/TabControl.h b/code/TabControl.h new file mode 100644 index 0000000..a966bc9 --- /dev/null +++ b/code/TabControl.h @@ -0,0 +1,52 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "tabbase.h" + +class TabControl : + public TabBase +{ + int controlCB(gdioutput &gdi, int type, void *data); + + bool tableMode; + int controlId; + void save(gdioutput &gdi); + + +protected: + void clearCompetitionData(); + +public: + void visitorTable(Table &table) const; + void courseTable(Table &table) const; + void selectControl(gdioutput &gdi, pControl pc); + + const char * getTypeStr() const {return "TControlTab";} + TabType getType() const {return TControlTab;} + + bool loadPage(gdioutput &gdi); + TabControl(oEvent *oe); + ~TabControl(void); + + friend int ControlsCB(gdioutput *gdi, int type, void *data); +}; diff --git a/code/TabCourse.cpp b/code/TabCourse.cpp new file mode 100644 index 0000000..bd08d19 --- /dev/null +++ b/code/TabCourse.cpp @@ -0,0 +1,1158 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include "gdifonts.h" +#include "IOF30Interface.h" +#include "meosexception.h" +#include "MeOSFeatures.h" +#include "oEventDraw.h" +#include "oListInfo.h" + +#include "TabCourse.h" +#include "TabCompetition.h" +#include "meos_util.h" +#include "pdfwriter.h" + +TabCourse::TabCourse(oEvent *poe):TabBase(poe) +{ + clearCompetitionData(); +} + +TabCourse::~TabCourse(void) +{ +} + +void LoadCoursePage(gdioutput &gdi); +void LoadClassPage(gdioutput &gdi); + +void TabCourse::selectCourse(gdioutput &gdi, pCourse pc) +{ + if (gdi.hasField("Rogaining")) { + gdi.setText("TimeLimit", ""); + gdi.disableInput("TimeLimit"); + gdi.setText("PointLimit", ""); + gdi.disableInput("PointLimit"); + gdi.setText("PointReduction", ""); + gdi.disableInput("PointReduction"); + gdi.check("ReductionPerMinute", false); + gdi.disableInput("ReductionPerMinute"); + gdi.selectItemByData("Rogaining", 0); + } + + if (pc) { + pc->synchronize(); + + string uis = pc->getControlsUI(); + gdi.setText("Controls", uis); + + gdi.setText("CourseExpanded", encodeCourse(uis, pc->useFirstAsStart(), pc->useLastAsFinish()), true); + + gdi.setText("Name", pc->getName()); + + gdi.setTextZeroBlank("Length", pc->getLength()); + gdi.setTextZeroBlank("Climb", pc->getDI().getInt("Climb")); + gdi.setTextZeroBlank("NumberMaps", pc->getNumberMaps()); + + gdi.check("FirstAsStart", pc->useFirstAsStart()); + gdi.check("LastAsFinish", pc->useLastAsFinish()); + + if (gdi.hasField("Rogaining")) { + int rt = pc->getMaximumRogainingTime(); + int rp = pc->getMinimumRogainingPoints(); + + if ( rt > 0 ) { + gdi.selectItemByData("Rogaining", 1); + gdi.enableInput("TimeLimit"); + gdi.setText("TimeLimit", formatTimeHMS(rt)); + gdi.enableInput("PointReduction"); + gdi.setText("PointReduction", itos(pc->getRogainingPointsPerMinute())); + gdi.enableInput("ReductionPerMinute"); + gdi.check("ReductionPerMinute", pc->getDCI().getInt("RReductionMethod") != 0); + } + else if (rp > 0) { + gdi.selectItemByData("Rogaining", 2); + gdi.enableInput("PointLimit"); + gdi.setText("PointLimit", itos(rp)); + } + } + + courseId = pc->getId(); + gdi.enableInput("Remove"); + gdi.enableInput("Save"); + + gdi.selectItemByData("Courses", pc->getId()); + gdi.setText("CourseProblem", lang.tl(pc->getCourseProblems()), true); + vector cls; + vector crs; + oe->getClasses(cls, true); + string usedInClasses; + for (size_t k = 0; k < cls.size(); k++) { + int nleg = max(cls[k]->getNumStages(), 1); + int nlegwithcrs = 0; + vector usage; + set allClassCrs; + for (int j = 0; j < nleg; j++) { + cls[k]->getCourses(j, crs); + if (!crs.empty()) + nlegwithcrs++; + + bool done = false; + for (size_t i = 0; i < crs.size(); i++) { + if (!crs[i]) + continue; + allClassCrs.insert(crs[i]->getId()); + if (!done && crs[i] == pc) { + usage.push_back(cls[k]->getLegNumber(j)); + done = true; // Cannot break, fill allClasssCrs + } + } + } + string add; + if (usage.size() == nleg || + usage.size() == nlegwithcrs || + (!usage.empty() && allClassCrs.size() == 1)) { + add = cls[k]->getName(); + } + else if (!usage.empty()) { + add = cls[k]->getName(); + add += " ("; + for (size_t i = 0; i < usage.size(); i++) { + if (i > 0) + add += ", "; + add += usage[i]; + } + add += ")"; + } + + if (!add.empty()) { + if (!usedInClasses.empty()) + usedInClasses += ", "; + usedInClasses += add; + } + } + gdi.setText("CourseUse", usedInClasses, true); + pCourse shortens = pc->getLongerVersion(); + if (shortens) + gdi.setTextTranslate("Shortens", "Avkortar: X#" + shortens->getName(), true); + else + gdi.setText("Shortens", "", true); + + gdi.enableEditControls(true); + + fillCourseControls(gdi, pc->getControlsUI()); + int cc = pc->getCommonControl(); + gdi.check("WithLoops", cc != 0); + gdi.setInputStatus("CommonControl", cc != 0); + if (cc) { + gdi.selectItemByData("CommonControl", cc); + } + + fillOtherCourses(gdi, *pc); + pCourse sh = pc->getShorterVersion(); + gdi.check("Shorten", sh != 0); + gdi.setInputStatus("ShortCourse", sh != 0); + if (sh) { + gdi.selectItemByData("ShortCourse", sh->getId()); + } + } + else { + gdi.setText("Name", ""); + gdi.setText("Controls", ""); + gdi.setText("CourseExpanded", ""); + + gdi.setText("Length", ""); + gdi.setText("Climb", ""); + gdi.setText("NumberMaps", ""); + gdi.check("FirstAsStart", false); + gdi.check("LastAsFinish", false); + courseId = 0; + gdi.disableInput("Remove"); + gdi.disableInput("Save"); + gdi.selectItemByData("Courses", -1); + gdi.setText("CourseProblem", "", true); + gdi.setText("CourseUse", "", true); + gdi.setText("Shortens", "", true); + gdi.check("WithLoops", false); + gdi.clearList("CommonControl"); + gdi.setInputStatus("CommonControl", false); + gdi.check("Shorten", false); + gdi.clearList("ShortCourse"); + gdi.setInputStatus("ShortCourse", false); + + gdi.enableEditControls(false); + } + gdi.setInputStatus("DrawCourse", pc != 0); +} + +int CourseCB(gdioutput *gdi, int type, void *data) +{ + TabCourse &tc = dynamic_cast(*gdi->getTabs().get(TCourseTab)); + + return tc.courseCB(*gdi, type, data); +} + +void TabCourse::save(gdioutput &gdi, int canSwitchViewMode) +{ + DWORD cid = courseId; + + pCourse pc; + string name=gdi.getText("Name"); + + if (name.empty()) { + gdi.alert("Banan måste ha ett namn."); + return; + } + + bool create=false; + if (cid>0) + pc=oe->getCourse(cid); + else { + pc=oe->addCourse(name); + create=true; + } + + bool firstAsStart = gdi.isChecked("FirstAsStart"); + bool lastAsFinish = gdi.isChecked("LastAsFinish"); + bool oldFirstAsStart = pc->useFirstAsStart(); + if (!oldFirstAsStart && firstAsStart) { + vector cr; + oe->getRunners(0, pc->getId(), cr, false); + bool hasRes = false; + for (size_t k = 0; k < cr.size(); k++) { + if (cr[k]->getCard() != 0) { + hasRes = true; + break; + } + } + if (hasRes) { + firstAsStart = gdi.ask("ask:firstasstart"); + } + } + + + pc->setName(name); + bool changedCourse = pc->importControls(gdi.getText("Controls"), true); + pc->setLength(gdi.getTextNo("Length")); + pc->getDI().setInt("Climb", gdi.getTextNo("Climb")); + pc->setNumberMaps(gdi.getTextNo("NumberMaps")); + pc->firstAsStart(firstAsStart); + pc->lastAsFinish(lastAsFinish); + + if (gdi.isChecked("WithLoops")) { + int cc = gdi.getTextNo("CommonControl"); + if (cc == 0) + throw meosException("Ange en varvningskontroll för banan"); + pc->setCommonControl(cc); + } + else + pc->setCommonControl(0); + + if (gdi.isChecked("Shorten")) { + ListBoxInfo ci; + if (gdi.getSelectedItem("ShortCourse", ci) && oe->getCourse(ci.data)) { + pc->setShorterVersion(oe->getCourse(ci.data)); + } + else + throw meosException("Ange en avkortad banvariant"); + } + else + pc->setShorterVersion(0); + + if (gdi.hasField("Rogaining")) { + string t; + pc->setMaximumRogainingTime(convertAbsoluteTimeMS(gdi.getText("TimeLimit"))); + pc->setMinimumRogainingPoints(atoi(gdi.getText("PointLimit").c_str())); + int pr = atoi(gdi.getText("PointReduction").c_str()); + pc->setRogainingPointsPerMinute(pr); + if (pr > 0) { + int rmethod = gdi.isChecked("ReductionPerMinute") ? 1 : 0; + pc->getDI().setInt("RReductionMethod", rmethod); + } + } + + pc->synchronize();//Update SQL + + oe->fillCourses(gdi, "Courses"); + oe->reEvaluateCourse(pc->getId(), true); + + if (canSwitchViewMode != 2 && changedCourse && pc->getLegLengths().size() > 2) { + if (canSwitchViewMode == 1) { + if(gdi.ask("ask:updatelegs")) { + gdi.sendCtrlMessage("LegLengths"); + return; + } + } + else { + gdi.alert("warn:updatelegs"); + } + } + + if (gdi.getData("FromClassPage", cid)) { + assert(false); + } + else if (addedCourse || create) + selectCourse(gdi, 0); + else + selectCourse(gdi, pc); +} + +int TabCourse::courseCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="Save") { + save(gdi, 1); + } + else if (bi.id == "LegLengths") { + save(gdi, 2); + + pCourse pc = oe->getCourse(courseId); + if (!pc || pc->getNumControls() == 0) { + return 0; + } + gdi.clearPage(false); + gdi.addString("", boldLarge, "Redigera sträcklängder för X#" + pc->getName()); + gdi.dropLine(); + int w = gdi.scaleLength(120); + int xp = gdi.getCX() + w; + int yp = gdi.getCY(); + gdi.addString("", 1, "Sträcka:"); + gdi.addString("", yp, xp, 1, "Längd:"); + + for (int i = 0; i <= pc->getNumControls(); i++) { + int len = pc->getLegLength(i); + pControl cbegin = pc->getControl(i-1); + string begin = i == 0 ? lang.tl("Start") : (cbegin ? cbegin->getName() : ""); + pControl cend = pc->getControl(i); + string end = i == pc->getNumControls() ? lang.tl("Mål") : (cend ? cend->getName() : ""); + gdi.pushX(); + gdi.fillRight(); + gdi.addStringUT(0, begin + MakeDash(" - ") + end + ":").xlimit = w-10; + gdi.setCX(xp); + gdi.fillDown(); + gdi.addInput("c" + itos(i), len > 0 ? itos(len) : "", 8); + gdi.popX(); + if (i < pc->getNumControls()) { + RECT rc; + rc.left = gdi.getCX() + gdi.getLineHeight(); + rc.right = rc.left + (3*w)/2; + rc.top = gdi.getCY() + 2; + rc.bottom = gdi.getCY() + 4; + gdi.addRectangle(rc, colorDarkBlue, false); + } + } + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("Cancel", "Avbryt", CourseCB).setCancel(); + gdi.addButton("SaveLegLen", "Spara", CourseCB).setDefault(); + gdi.setOnClearCb(CourseCB); + gdi.setData("EditLengths", 1); + gdi.refresh(); + } + else if (bi.id == "SaveLegLen") { + saveLegLengths(gdi); + loadPage(gdi); + } + else if (bi.id=="BrowseCourse") { + vector< pair > ext; + ext.push_back(make_pair("Alla banfiler", "*.xml;*.csv;*.txt")); + ext.push_back(make_pair("Banor, OCAD semikolonseparerat", "*.csv;*.txt")); + ext.push_back(make_pair("Banor, IOF (xml)", "*.xml")); + + string file=gdi.browseForOpen(ext, "csv"); + + if (file.length()>0) + gdi.setText("FileName", file); + } + else if (bi.id=="Print") { + gdi.print(oe); + } + else if (bi.id=="PDF") { + vector< pair > ext; + ext.push_back(make_pair("Portable Document Format (PDF)", "*.pdf")); + + int index; + string file=gdi.browseForSave(ext, "pdf", index); + + if (!file.empty()) { + pdfwriter pdf; + pdf.generatePDF(gdi, gdi.toWide(file), "Report", "MeOS", gdi.getTL()); + gdi.openDoc(file.c_str()); + } + } + else if (bi.id == "WithLoops") { + bool w = gdi.isChecked(bi.id); + gdi.setInputStatus("CommonControl", w); + if (w && gdi.getTextNo("CommonControl") == 0) + gdi.selectFirstItem("CommonControl"); + } + else if (bi.id == "Shorten") { + bool w = gdi.isChecked(bi.id); + gdi.setInputStatus("ShortCourse", w); + if (w) { + ListBoxInfo clb; + if (!gdi.getSelectedItem("ShortCoursse", clb) || clb.data <= 0) + gdi.selectFirstItem("CommonControl"); + } + } + else if (bi.id == "ExportCourses") { + int FilterIndex=0; + vector< pair > ext; + ext.push_back(make_pair("IOF CourseData, version 3.0 (xml)", "*.xml")); + string save = gdi.browseForSave(ext, "xml", FilterIndex); + if (save.length()>0) { + IOF30Interface iof30(oe, false); + xmlparser xml(gdi.getEncoding() == ANSI ? 0 : &gdi); + xml.openOutput(save.c_str(), false); + iof30.writeCourses(xml); + xml.closeOut(); + } + } + else if (bi.id=="ImportCourses") { + setupCourseImport(gdi, CourseCB); + } + else if (bi.id=="DoImportCourse") { + string filename = gdi.getText("FileName"); + if (filename.empty()) + return 0; + gdi.disableInput("DoImportCourse"); + gdi.disableInput("Cancel"); + gdi.disableInput("BrowseCourse"); + gdi.disableInput("AddClasses"); + + try { + TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses")); + } + catch (std::exception &) { + gdi.enableInput("DoImportCourse"); + gdi.enableInput("Cancel"); + gdi.enableInput("BrowseCourse"); + gdi.enableInput("AddClasses"); + throw; + } + gdi.addButton("Cancel", "OK", CourseCB); + gdi.dropLine(); + gdi.refresh(); + } + else if (bi.id == "DrawCourse") { + save(gdi, true); + pCourse crs = oe->getCourse(courseId); + if (crs == 0) + throw meosException("Ingen bana vald."); + vector cls; + oe->getClasses(cls, true); + string clsNames; + bool hasAsked = false; + courseDrawClasses.clear(); + for (size_t k = 0; k < cls.size(); k++) { + if (cls[k]->getCourseId() != courseId) + continue; + if (!hasAsked &&oe->classHasResults(cls[k]->getId())) { + hasAsked = true; + if (!gdi.ask("warning:drawresult")) + return 0; + } + courseDrawClasses.push_back(ClassDrawSpecification(cls[k]->getId(), 0, -1, -1, 0)); + if (!clsNames.empty()) + clsNames += ", "; + clsNames += cls[k]->getName(); + } + if (courseDrawClasses.empty()) + throw meosException("Ingen klass använder banan."); + + gdi.clearPage(false); + gdi.addString("", boldLarge, "Lotta klasser med banan X#" + crs->getName()); + gdi.addStringUT(0, clsNames); + gdi.dropLine(); + gdi.pushX(); + + gdi.fillRight(); + int firstStart = 3600; + int interval = 2*60; + int vac = 1; + gdi.addInput("FirstStart", oe->getAbsTime(firstStart), 10, 0, "Första start:"); + gdi.addInput("Interval", formatTime(interval), 10, 0, "Startintervall (min):"); + gdi.addInput("Vacances", itos(vac), 10, 0, "Antal vakanser:"); + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + gdi.addSelection("Method", 200, 200, 0, "Metod:"); + gdi.addItem("Method", lang.tl("Lottning"), DMRandom); + gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); + + gdi.selectItemByData("Method", getDefaultMethod()); + gdi.dropLine(0.9); + gdi.fillRight(); + gdi.addButton("DoDrawCourse", "Lotta", CourseCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", CourseCB).setCancel(); + gdi.dropLine(); + gdi.fillDown(); + gdi.refresh(); + } + else if (bi.id == "DoDrawCourse") { + string firstStart = gdi.getText("FirstStart"); + string minInterval = gdi.getText("Interval"); + int vacances = gdi.getTextNo("Vacances"); + int fs = oe->getRelativeTime(firstStart); + int iv = convertAbsoluteTimeMS(minInterval); + DrawMethod method = DrawMethod(gdi.getSelectedItem("Method").first); + courseDrawClasses[0].firstStart = fs; + courseDrawClasses[0].vacances = vacances; + courseDrawClasses[0].interval = iv; + + for (size_t k = 1; k < courseDrawClasses.size(); k++) { + vector r; + oe->getRunners(courseDrawClasses[k-1].classID, 0, r, false); + int vacDelta = vacances; + for (size_t i = 0; i < r.size(); i++) { + if (r[i]->isVacant()) + vacDelta--; + } + + courseDrawClasses[k].firstStart = courseDrawClasses[k-1].firstStart + (r.size() + vacDelta) * iv; + courseDrawClasses[k].vacances = vacances; + courseDrawClasses[k].interval = iv; + } + + oe->drawList(courseDrawClasses, method == DMSOFT, 1, oEvent::drawAll); + + oe->addAutoBib(); + + gdi.clearPage(false); + gdi.addButton("Cancel", "Återgå", CourseCB); + + oListParam par; + oListInfo info; + par.listCode = EStdStartList; + for (size_t k=0; kgenerateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + gdi.refresh(); + } + else if (bi.id=="Add") { + if (courseId>0) { + string ctrl = gdi.getText("Controls"); + string name = gdi.getText("Name"); + pCourse pc = oe->getCourse(courseId); + if (pc && !name.empty() && !ctrl.empty() && pc->getControlsUI() != ctrl) { + if (name == pc->getName()) { + // Make name unique if same name + int len = name.length(); + if (len > 2 && (isdigit(name[len-1]) || isdigit(name[len-2]))) { + ++name[len-1]; // course 1 -> course 2, course 1a -> course 1b + } + else + name += " 2"; + } + if (gdi.ask("Vill du lägga till banan 'X' (Y)?#" + name + "#" + ctrl)) { + pc = oe->addCourse(name); + courseId = pc->getId(); + gdi.setText("Name", name); + save(gdi, 1); + return true; + } + } + save(gdi, 1); + } + pCourse pc = oe->addCourse(oe->getAutoCourseName()); + pc->synchronize(); + oe->fillCourses(gdi, "Courses"); + selectCourse(gdi, pc); + gdi.setInputFocus("Name", true); + addedCourse = true; + } + else if (bi.id=="Remove"){ + DWORD cid = courseId; + if (cid==0) + throw meosException("Ingen bana vald."); + + if (oe->isCourseUsed(cid)) + gdi.alert("Banan används och kan inte tas bort."); + else + oe->removeCourse(cid); + + oe->fillCourses(gdi, "Courses"); + + selectCourse(gdi, 0); + } + else if (bi.id == "FirstAsStart" || bi.id == "LastAsFinish") { + refreshCourse(gdi.getText("Controls"), gdi); + } + else if (bi.id=="Cancel"){ + LoadPage("Banor"); + } + } + else if (type==GUI_LISTBOX){ + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Courses") { + if (gdi.isInputChanged("")) + save(gdi, 0); + + pCourse pc=oe->getCourse(bi.data); + selectCourse(gdi, pc); + addedCourse = false; + } + else if (bi.id=="Rogaining") { + string t; + t = gdi.getText("TimeLimit"); + if (!t.empty() && t != "-") + time_limit = t; + t = gdi.getText("PointLimit"); + if (!t.empty()) + point_limit = t; + t = gdi.getText("PointReduction"); + if (!t.empty()) + point_reduction = t; + + string tl, pl, pr; + if (bi.data == 1) { + tl = time_limit; + pr = point_reduction; + } + else if (bi.data == 2) { + pl = point_limit; + } + + gdi.setInputStatus("TimeLimit", !tl.empty()); + gdi.setText("TimeLimit", tl); + + gdi.setInputStatus("PointLimit", !pl.empty()); + gdi.setText("PointLimit", pl); + + gdi.setInputStatus("PointReduction", !pr.empty()); + gdi.setInputStatus("ReductionPerMinute", !pr.empty()); + gdi.setText("PointReduction", pr); + + } + } + else if (type == GUI_INPUT) { + InputInfo ii=*(InputInfo *)data; + if (ii.id == "Controls") { + int current = gdi.getTextNo("CommonControl"); + fillCourseControls(gdi, ii.text); + if (gdi.isChecked("WithLoops") && current != 0) + gdi.selectItemByData("CommonControl", current); + } + } + else if (type == GUI_INPUTCHANGE) { + InputInfo &ii=*(InputInfo *)data; + + if (ii.id == "Controls") { + refreshCourse(ii.text, gdi); + } + } + else if (type==GUI_CLEAR) { + if (gdi.hasData("EditLengths")) { + saveLegLengths(gdi); + return true; + } + if (courseId>0) + save(gdi, 0); + + return true; + } + return 0; +} + +bool TabCourse::loadPage(gdioutput &gdi) { + oe->checkDB(); + gdi.selectTab(tabId); + + DWORD ClassID=0, RunnerID=0; + + time_limit = "01:00:00"; + point_limit = "10"; + point_reduction = "1"; + + gdi.getData("ClassID", ClassID); + gdi.getData("RunnerID", RunnerID); + + gdi.clearPage(false); + + gdi.setData("ClassID", ClassID); + gdi.setData("RunnerID", RunnerID); + gdi.addString("", boldLarge, "Banor"); + gdi.pushY(); + + gdi.fillDown(); + gdi.addListBox("Courses", 250, 360, CourseCB, "Banor (antal kontroller)").isEdit(false).ignore(true); + gdi.setTabStops("Courses", 240); + + oe->fillCourses(gdi, "Courses"); + + gdi.dropLine(0.7); + gdi.pushX(); + gdi.addString("", boldText, "Funktioner"); + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("ImportCourses", "Importera från fil...", CourseCB); + gdi.addButton("ExportCourses", "Exportera...", CourseCB); + gdi.popX(); + gdi.dropLine(2.5); + gdi.addButton("DrawCourse", "Lotta starttider..", CourseCB); + gdi.disableInput("DrawCourse"); + gdi.newColumn(); + gdi.fillDown(); + + gdi.popY(); + + gdi.addString("", 10, "help:25041"); + + gdi.dropLine(0.5); + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("Name", "", 20, 0, "Namn:"); + gdi.fillDown(); + gdi.addInput("NumberMaps", "", 6, 0, "Antal kartor:"); + + gdi.popX(); + + vector allCrs; + oe->getCourses(allCrs); + size_t mlen = 0; + for (size_t k = 0; k < allCrs.size(); k++) { + mlen = max(allCrs[k]->getControlsUI().length()/2+5, mlen); + } + + gdi.addInput("Controls", "", max(48u, mlen), CourseCB, "Kontroller:"); + gdi.dropLine(0.3); + gdi.addString("CourseExpanded", 0, "...").setColor(colorDarkGreen); + gdi.dropLine(0.5); + gdi.addString("", 10, "help:12662"); + gdi.dropLine(1); + + gdi.fillRight(); + gdi.addInput("Climb", "", 8, 0, "Climb (m):"); + gdi.addInput("Length", "", 8, 0, "Längd (m):"); + gdi.dropLine(0.9); + gdi.fillDown(); + gdi.addButton("LegLengths", "Redigera sträcklängder...", CourseCB).isEdit(true); + gdi.dropLine(0.5); + gdi.popX(); + + gdi.fillRight(); + gdi.addCheckbox("FirstAsStart", "Använd första kontrollen som start", CourseCB); + gdi.fillDown(); + gdi.addCheckbox("LastAsFinish", "Använd sista kontrollen som mål", CourseCB); + gdi.popX(); + + gdi.fillRight(); + gdi.addCheckbox("WithLoops", "Bana med slingor", CourseCB); + gdi.setCX(gdi.getCX()+ gdi.scaleLength(20)); + gdi.addString("", 0, "Varvningskontroll:"); + gdi.fillDown(); + gdi.dropLine(-0.2); + gdi.addSelection("CommonControl", 50, 200, 0, "", "En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning"); + + gdi.dropLine(0.2); + gdi.popX(); + + gdi.fillRight(); + gdi.addCheckbox("Shorten", "Med avkortning", CourseCB); + gdi.setCX(gdi.getCX()+ gdi.scaleLength(20)); + gdi.addString("", 0, "Avkortad banvariant:"); + gdi.dropLine(-0.2); + gdi.addSelection("ShortCourse", 150, 200, 0, "", "info_shortening"); + gdi.addString("Shortens", 0, ""); + + gdi.fillDown(); + + gdi.dropLine(2.5); + gdi.popX(); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining)) { + RECT rc; + rc.top = gdi.getCY() -5; + rc.left = gdi.getCX(); + gdi.setCX(gdi.getCX()+gdi.scaleLength(10)); + + gdi.addString("", 1, "Rogaining"); + gdi.dropLine(0.5); + gdi.fillRight(); + gdi.addSelection("Rogaining", 120, 80, CourseCB); + gdi.addItem("Rogaining", lang.tl("Ingen rogaining"), 0); + gdi.addItem("Rogaining", lang.tl("Tidsgräns"), 1); + gdi.addItem("Rogaining", lang.tl("Poänggräns"), 2); + + gdi.setCX(gdi.getCX()+gdi.scaleLength(20)); + gdi.dropLine(-0.8); + int cx = gdi.getCX(); + gdi.addInput("PointLimit", "", 8, 0, "Poänggräns:").isEdit(false); + gdi.addInput("TimeLimit", "", 8, 0, "Tidsgräns:").isEdit(false); + gdi.addInput("PointReduction", "", 8, 0, "Poängavdrag (per minut):").isEdit(false); + gdi.dropLine(3.5); + rc.right = gdi.getCX() + 5; + gdi.setCX(cx); + gdi.fillDown(); + gdi.addCheckbox("ReductionPerMinute", "Poängavdrag per påbörjad minut"); + + rc.bottom = gdi.getCY() + 5; + gdi.addRectangle(rc, colorLightBlue, true); + } + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(1); + gdi.addString("CourseUse", 0, "").setColor(colorDarkBlue); + gdi.dropLine(); + gdi.addString("CourseProblem", 1, "").setColor(colorRed); + gdi.dropLine(2); + gdi.fillRight(); + gdi.addButton("Save", "Spara", CourseCB, "help:save").setDefault(); + gdi.addButton("Remove", "Radera", CourseCB); + gdi.addButton("Add", "Ny bana", CourseCB); + gdi.disableInput("Remove"); + gdi.disableInput("Save"); + + selectCourse(gdi, oe->getCourse(courseId)); + gdi.setOnClearCb(CourseCB); + + gdi.refresh(); + + return true; +} + +void TabCourse::runCourseImport(gdioutput& gdi, const string &filename, + oEvent *oe, bool addClasses) { + csvparser csv; + if (csv.iscsv(filename.c_str())) { + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 0, "Importerar OCAD csv-fil..."); + gdi.refreshFast(); + + if (csv.ImportOCAD_CSV(*oe, filename.c_str(), addClasses)) { + gdi.addString("", 1, "Klart.").setColor(colorGreen); + } + else gdi.addString("", 0, "Operationen misslyckades.").setColor(colorRed); + gdi.popX(); + gdi.dropLine(2.5); + gdi.fillDown(); + } + else { + oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false); + } + if (addClasses) { + // There is specific course-class matching inside the import of each format, + // that uses additional information. Here we try to match based on a generic approach. + vector cls; + vector crs; + oe->getClasses(cls, false); + oe->getCourses(crs); + + map name2Course; + map > course2Class; + for (size_t k = 0; k < crs.size(); k++) + name2Course[crs[k]->getName()] = crs[k]; + bool hasMissing = false; + for (size_t k = 0; k < cls.size(); k++) { + vector usedCrs; + cls[k]->getCourses(-1, usedCrs); + + if (usedCrs.empty()) { + map::iterator res = name2Course.find(cls[k]->getName()); + if (res != name2Course.end()) { + usedCrs.push_back(res->second); + if (cls[k]->getNumStages()==0) { + cls[k]->setCourse(res->second); + } + else { + for (size_t i = 0; igetNumStages(); i++) + cls[k]->addStageCourse(i, res->second->getId()); + } + } + else { + hasMissing = true; + } + } + + for (size_t j = 0; j < usedCrs.size(); j++) { + course2Class[usedCrs[j]->getId()].push_back(cls[k]); + } + } + + for (size_t k = 0; k < crs.size(); k++) { + pClass bestClass; + if (hasMissing && (bestClass = oe->getBestClassMatch(crs[k]->getName())) != 0) { + vector usedCrs; + bestClass->getCourses(-1, usedCrs); + if (usedCrs.empty()) { + course2Class[crs[k]->getId()].push_back(bestClass); + if (bestClass->getNumStages()==0) { + bestClass->setCourse(crs[k]); + } + else { + for (size_t i = 0; igetNumStages(); i++) + bestClass->addStageCourse(i, crs[k]->getId()); + } + } + } + } + + gdi.addString("", 1, "Klasser"); + int yp = gdi.getCY(); + int xp = gdi.getCX(); + int w = gdi.scaleLength(200); + for (size_t k = 0; k < cls.size(); k++) { + vector usedCrs; + cls[k]->getCourses(-1, usedCrs); + string c; + for (size_t j = 0; j < usedCrs.size(); j++) { + if (j>0) + c += ", "; + c += usedCrs[j]->getName(); + } + TextInfo &ci = gdi.addStringUT(yp, xp, 0, cls[k]->getName(), w); + if (c.empty()) { + c = MakeDash("-"); + ci.setColor(colorRed); + } + gdi.addStringUT(yp, xp + w, 0, c); + yp += gdi.getLineHeight(); + } + + gdi.dropLine(); + gdi.addString("", 1, "Banor"); + yp = gdi.getCY(); + for (size_t k = 0; k < crs.size(); k++) { + string c; + vector usedCls = course2Class[crs[k]->getId()]; + for (size_t j = 0; j < usedCls.size(); j++) { + if (j>0) + c += ", "; + c += usedCls[j]->getName(); + } + TextInfo &ci = gdi.addStringUT(yp, xp, 0, crs[k]->getName(), w); + if (c.empty()) { + c = MakeDash("-"); + ci.setColor(colorRed); + } + gdi.addStringUT(yp, xp + w, 0, c); + yp += gdi.getLineHeight(); + } + gdi.dropLine(); + } + + gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(120), + "Print", "Skriv ut...", CourseCB, + "Skriv ut listan.", true, false); + gdi.addButton(gdi.getWidth()+20, 75, gdi.scaleLength(120), + "PDF", "PDF...", CourseCB, + "Spara som PDF.", true, false); + + gdi.setWindowTitle(oe->getTitleName()); + oe->updateTabs(); + gdi.refresh(); +} + +void TabCourse::setupCourseImport(gdioutput& gdi, GUICALLBACK cb) { + + gdi.clearPage(true); + gdi.addString("", 2, "Importera banor/klasser"); + gdi.addString("", 0, "help:importcourse"); + gdi.dropLine(); + + gdi.fillRight(); + gdi.pushX(); + gdi.addInput("FileName", "", 48, 0, "Filnamn:"); + gdi.dropLine(); + gdi.fillDown(); + gdi.addButton("BrowseCourse", "Bläddra...", CourseCB); + + gdi.dropLine(0.5); + gdi.popX(); + + gdi.fillDown(); + gdi.addCheckbox("AddClasses", "Lägg till klasser", 0, true); + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("DoImportCourse", "Importera", cb).setDefault(); + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", cb).setCancel(); + gdi.setInputFocus("FileName"); + gdi.popX(); +} + +void TabCourse::fillCourseControls(gdioutput &gdi, const string &ctrl) { + vector nr; + oCourse::splitControls(ctrl, nr); + + vector< pair > item; + map used; + for (size_t k = 0; k < nr.size(); k++) { + pControl pc = oe->getControl(nr[k], false); + if (pc) { + if (pc->getStatus() == oControl::StatusOK) + ++used[pc->getFirstNumber()]; + } + else + ++used[nr[k]]; + } + + set added; + for (int i = 10; i > 0; i--) { + for (map::iterator it = used.begin(); it != used.end(); ++it) { + if (it->second >= i && !added.count(it->first)) { + added.insert(it->first); + item.push_back(make_pair(itos(it->first), it->first)); + } + } + } + + gdi.clearList("CommonControl"); + gdi.addItem("CommonControl", item); +} + +void TabCourse::fillOtherCourses(gdioutput &gdi, oCourse &crs) { + vector< pair > ac; + oe->fillCourses(ac, true); + set skipped; + skipped.insert(crs.getId()); + pCourse longer = crs.getLongerVersion(); + int iter = 20; + while (longer && --iter>0) { + skipped.insert(longer->getId()); + longer = longer->getLongerVersion(); + } + + vector< pair > out; + for (size_t k = 0; k < ac.size(); k++) { + if (!skipped.count(ac[k].second)) + out.push_back(ac[k]); + } + + gdi.clearList("ShortCourse"); + gdi.addItem("ShortCourse", out); +} + +void TabCourse::saveLegLengths(gdioutput &gdi) { + pCourse pc = oe->getCourse(courseId); + if (!pc) + return; + + pc->synchronize(false); + string lstr; + bool gotAny = false; + for (int i = 0; i <= pc->getNumControls(); i++) { + string t = trim(gdi.getText("c" + itos(i))); + if (t.empty()) + t = "0"; + else + gotAny = true; + + if (i == 0) + lstr = t; + else + lstr += ";" + t; + } + if (!gotAny) + lstr = ""; + + pc->importLegLengths(lstr, true); + pc->synchronize(true); +} + +DrawMethod TabCourse::getDefaultMethod() const { + int dm = oe->getPropertyInt("DefaultDrawMethod", DMSOFT); + if (dm == DMRandom) + return DMRandom; + else + return DMSOFT; +} + +void TabCourse::clearCompetitionData() { + courseId = 0; + addedCourse = false; +} + +void TabCourse::refreshCourse(const string &text, gdioutput &gdi) { + bool firstAsStart = gdi.isChecked("FirstAsStart"); + bool lastAsFinish = gdi.isChecked("LastAsFinish"); + string controls = encodeCourse(text, firstAsStart, lastAsFinish); + if (controls != gdi.getText("CourseExpanded")) + gdi.setText("CourseExpanded", controls, true); +} +string TabCourse::encodeCourse(const string &in, bool firstStart, bool lastFinish) { + vector newC; + oCourse::splitControls(in, newC); + string dash = MakeDash("-"); + string out; + out.reserve(in.length() * 2); + string bf; + for (size_t i = 0; i < newC.size(); ++i) { + if (i == 0) { + out += lang.tl("Start"); + if (firstStart) + out += "(" + itos(newC[i]) + ")"; + else + out += dash + formatControl(newC[i], bf); + + if (newC.size() == 1) { + out += dash + lang.tl("Mål"); + break; + } + continue; + } + else + out += dash; + + if (i+1 == newC.size()) { + if (lastFinish) + out += lang.tl("Mål") + "(" + itos(newC[i]) + ")"; + else + out += formatControl(newC[i], bf) + dash + lang.tl("Mål"); + } + else { + out += formatControl(newC[i], bf); + } + } + return out; +} + +const string &TabCourse::formatControl(int id, string &bf) const { + pControl ctrl = oe->getControl(id, false); + if (ctrl) { + bf = ctrl->getString(); + return bf; + } + else + return itos(id); +} diff --git a/code/TabCourse.h b/code/TabCourse.h new file mode 100644 index 0000000..174962b --- /dev/null +++ b/code/TabCourse.h @@ -0,0 +1,77 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "tabbase.h" + +struct ClassDrawSpecification; +enum DrawMethod; + +class TabCourse : + public TabBase +{ + int courseId; + /** canSwitchViewMode: 0 = no, 1 = yes, 2 = switching to legs */ + void save(gdioutput &gdi, int canSwitchViewMode); + int courseCB(gdioutput &gdi, int type, void *data); + bool addedCourse; + + string time_limit; + string point_limit; + string point_reduction; + + void fillCourseControls(gdioutput &gdi, const string &ctrl); + void fillOtherCourses(gdioutput &gdi, oCourse &crs); + + void saveLegLengths(gdioutput &gdi); + + vector courseDrawClasses; + + DrawMethod getDefaultMethod() const; + + string encodeCourse(const string &in, bool firstStart, bool lastFinish); + void refreshCourse(const string &text, gdioutput &gdi); + + const string &formatControl(int id, string &bf) const; + +protected: + void clearCompetitionData(); + + +public: + void selectCourse(gdioutput &gdi, pCourse pc); + + bool loadPage(gdioutput &gdi); + + const char * getTypeStr() const {return "TCourseTab";} + TabType getType() const {return TCourseTab;} + + TabCourse(oEvent *oe); + ~TabCourse(void); + + static void runCourseImport(gdioutput& gdi, const string &filename, + oEvent *oe, bool addClasses); + + static void setupCourseImport(gdioutput& gdi, GUICALLBACK cb); + + friend int CourseCB(gdioutput *gdi, int type, void *data); +}; diff --git a/code/TabList.cpp b/code/TabList.cpp new file mode 100644 index 0000000..dd57c0f --- /dev/null +++ b/code/TabList.cpp @@ -0,0 +1,2106 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" +#include "oListInfo.h" +#include "TabList.h" +#include "TabRunner.h" +#include "TabTeam.h" +#include "TabSI.h" +#include "TabAuto.h" +#include "meos_util.h" +#include +#include "classconfiginfo.h" +#include "metalist.h" +#include "gdifonts.h" +#include "listeditor.h" +#include "meosexception.h" +#include "pdfwriter.h" +#include "methodeditor.h" +#include "MeOSFeatures.h" +#include "liveresult.h" +#include + +const static int CUSTOM_OFFSET = 10; + +TabList::TabList(oEvent *poe):TabBase(poe) +{ + listEditor = 0; + methodEditor = 0; + clearCompetitionData(); +} + +TabList::~TabList(void) +{ + delete listEditor; + delete methodEditor; + listEditor = 0; + methodEditor = 0; + + for (size_t k = 0; k < liveResults.size(); k++) { + delete liveResults[k]; + liveResults[k] = 0; + } + liveResults.clear(); +} + +int ListsCB(gdioutput *gdi, int type, void *data); + +int ListsEventCB(gdioutput *gdi, int type, void *data) +{ + if (type!=GUI_EVENT) + return -1; + + TabList &tc = dynamic_cast(*gdi->getTabs().get(TListTab)); + + tc.rebuildList(*gdi); + + return 0; +} + +void TabList::rebuildList(gdioutput &gdi) +{ + if (!SelectedList.empty()) { + ButtonInfo bi; + bi.id=SelectedList; + noReEvaluate = true; + ListsCB(&gdi, GUI_BUTTON, &bi); + noReEvaluate = false; + } +} + +int openRunnerTeamCB(gdioutput *gdi, int type, void *data) +{ + if (type==GUI_LINK && data) { + TextInfo *ti = static_cast(data); + int id = ti->getExtraInt(); + + if (id != 0 && ti->id == "T" && gdi->canClear()) { + TabTeam &tt = dynamic_cast(*gdi->getTabs().get(TTeamTab)); + tt.loadPage(*gdi, id); + } + else if (id != 0 && ti->id == "R" && gdi->canClear()) { + TabRunner &tr = dynamic_cast(*gdi->getTabs().get(TRunnerTab)); + tr.loadPage(*gdi, id); + } + } + return 0; +} + +int NoStartRunnerCB(gdioutput *gdi, int type, void *data) +{ + if (type==GUI_LINK) + { + TextInfo *ti=(TextInfo *)data; + int id=atoi(ti->id.c_str()); + + TabList &tc = dynamic_cast(*gdi->getTabs().get(TListTab)); + pRunner p = tc.getEvent()->getRunner(id, 0); + + if (p){ + p->setStatus(StatusDNS, true, false); + p->synchronize(); + ti->callBack=0; + ti->highlight=false; + ti->active=false; + ti->color=RGB(255,0,0); + gdi->setText(ti->id, "Ej start", true); + } + } + return 0; +} + +int ListsCB(gdioutput *gdi, int type, void *data) +{ + TabList &tc = dynamic_cast(*gdi->getTabs().get(TListTab)); + + return tc.listCB(*gdi, type, data); +} + +int TabList::baseButtons(gdioutput &gdi, int extraButtons) { + gdi.addButton(gdi.getWidth()+20, 15, gdi.scaleLength(120), + "Cancel", ownWindow ? "Stäng" : "Återgå", ListsCB, "", true, false); + + gdi.addButton(gdi.getWidth()+20, 18+gdi.getButtonHeight(), gdi.scaleLength(120), + "Print", "Skriv ut...", ListsCB, "Skriv ut listan.", true, false); + gdi.addButton(gdi.getWidth()+20, 21+2*gdi.getButtonHeight(), gdi.scaleLength(120), + "HTML", "Webb...", ListsCB, "Spara för webben.", true, false); + gdi.addButton(gdi.getWidth()+20, 24+3*gdi.getButtonHeight(), gdi.scaleLength(120), + "PDF", "PDF...", ListsCB, "Spara som PDF.", true, false); + gdi.addButton(gdi.getWidth()+20, 27+4*gdi.getButtonHeight(), gdi.scaleLength(120), + "Copy", "Kopiera", ListsCB, "Kopiera till urklipp.", true, false); + + int ypos = 30+5*gdi.getButtonHeight(); + + if (extraButtons == 1) { + int w, h; + gdi.addButton(gdi.getWidth()+20, ypos, gdi.scaleLength(120), + "EditInForest", "edit_in_forest", ListsCB, "", true, false).getDimension(gdi, w, h); + ypos += h + 3; + } + + return ypos; +} + +void TabList::generateList(gdioutput &gdi) +{ + if (currentList.getListCode() == EFixedLiveResult) { + liveResult(gdi, currentList); + + int baseY = 15; + if (!gdi.isFullScreen()) { + gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120), + "Cancel", ownWindow ? "Stäng" : "Återgå", ListsCB, "", true, false); + + baseY += 3 + gdi.getButtonHeight(); + gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120), + "FullScreenLive", "Fullskärm", ListsCB, "Visa listan i fullskärm", true, false); + } + SelectedList="GeneralList"; + + return; + } + + DWORD storedWidth = 0; + int oX = 0; + int oY = 0; + if (gdi.hasData("GeneralList")) { + if (!currentList.needRegenerate(*oe)) + return; + gdi.takeShownStringsSnapshot(); + oX=gdi.GetOffsetX(); + oY=gdi.GetOffsetY(); + gdi.getData("GeneralList", storedWidth); + gdi.restoreNoUpdate("GeneralList"); + } + else + gdi.clearPage(false); + + gdi.setRestorePoint("GeneralList"); + + currentList.setCallback(ownWindow ? 0 : openRunnerTeamCB); + try { + oe->generateList(gdi, !noReEvaluate, currentList, false); + } + catch (const meosException &ex) { + string err = lang.tl(ex.what()); + gdi.addString("", 1, "List Error: X#" + err).setColor(colorRed); + } + + gdi.setOffset(oX, oY, false); + int currentWidth = gdi.getWidth(); + gdi.setData("GeneralList", currentWidth); + + if (!hideButtons) { + int extra = 0; + if (currentList.getListCode() == EFixedInForest) + extra = 1; + + int baseY = baseButtons(gdi, extra); + + if (!ownWindow) { + gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120), + "Window", "Eget fönster", ListsCB, "Öppna i ett nytt fönster.", true, false); + + gdi.addButton(gdi.getWidth()+20, baseY + 3 + 1*gdi.getButtonHeight(), gdi.scaleLength(120), + "Automatic", "Automatisera", ListsCB, "Skriv ut eller exportera listan automatiskt.", true, false); + + baseY += 2*(3+gdi.getButtonHeight()); + } + baseY += 3 + gdi.getButtonHeight(); + gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120), + "AutoScroll", "Automatisk skroll", ListsCB, "Rulla upp och ner automatiskt", true, false); + + baseY += 3 + gdi.getButtonHeight(); + gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120), + "FullScreen", "Fullskärm", ListsCB, "Visa listan i fullskärm", true, false); + + if (!currentList.getParam().saved && !oe->isReadOnly()) { + baseY += 3 + gdi.getButtonHeight(); + gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120), + "Remember", "Kom ihåg listan", ListsCB, "Spara den här listan som en favoritlista", true, false); + } + } + + gdi.registerEvent("DataUpdate", ListsEventCB); + gdi.setData("DataSync", 1); + if (currentList.needPunchCheck()) + gdi.setData("PunchSync", 1); + gdi.registerEvent("GeneralList", ListsCB); + gdi.setOnClearCb(ListsCB); + SelectedList="GeneralList"; + + if (abs(int(currentWidth - storedWidth)) < 5) { + gdi.refreshSmartFromSnapshot(true); + } + else + gdi.refresh(); +} + +int TabList::listCB(gdioutput &gdi, int type, void *data) +{ + int index; + if (type==GUI_BUTTON || type==GUI_EVENT) { + BaseInfo *tbi = 0; + ButtonInfo button; + EventInfo evnt; + if (type == GUI_BUTTON) { + button = *(ButtonInfo *)data; + tbi = &button; + } + else if (type == GUI_EVENT) { + evnt = *(EventInfo *)data; + tbi = &evnt; + } + else + throw 0; + + BaseInfo &bi=*tbi; + + if (bi.id=="Cancel") { + if (ownWindow) + gdi.closeWindow(); + else { + SelectedList = ""; + currentListType = EStdNone; + loadPage(gdi); + } + } + else if (bi.id=="Print") { + gdi.print(oe); + } + else if (bi.id=="HTML") { + vector< pair > ext; + ext.push_back(make_pair("Strukturerat webbdokument (html)", "*.html;*.htm")); + ext.push_back(make_pair("Formaterat webbdokument (html)", "*.html;*.htm")); + + string file=gdi.browseForSave(ext, "html", index); + + if (!file.empty()) { + if (index == 1) + gdi.writeTableHTML(gdi.toWide(file), oe->getName(), 0); + else { + assert(index == 2); + gdi.writeHTML(gdi.toWide(file), oe->getName(), 0); + } + gdi.openDoc(file.c_str()); + } + } + else if (bi.id=="Copy") { + ostringstream fout; + gdi.writeTableHTML(fout, "MeOS", true, 0); + string res = fout.str(); + gdi.copyToClipboard(res, false, ""); + } + else if (bi.id=="PDF") { + vector< pair > ext; + ext.push_back(make_pair("Portable Document Format (PDF)", "*.pdf")); + + string file=gdi.browseForSave(ext, "pdf", index); + + if (!file.empty()) { + pdfwriter pdf; + pdf.generatePDF(gdi, gdi.toWide(file), oe->getName() + ", " + currentList.getName(), oe->getDCI().getString("Organizer"), gdi.getTL()); + gdi.openDoc(file.c_str()); + } + } + else if (bi.id == "Window" || bi.id == "AutoScroll" || + bi.id == "FullScreen" || bi.id == "FullScreenLive") { + gdioutput *gdi_new; + TabList *tl_new = this; + if (!ownWindow) { + gdi_new = createExtraWindow(uniqueTag("list"), MakeDash("MeOS - " + currentList.getName()), gdi.getWidth() + 64 + gdi.scaleLength(120)); + if (gdi_new) { + TabList &tl = dynamic_cast(*gdi_new->getTabs().get(TListTab)); + tl.currentList = currentList; + tl.SelectedList = SelectedList; + tl.ownWindow = true; + tl.loadPage(*gdi_new); + tl_new = &tl; + SelectedList = ""; + currentList = oListInfo(); + loadPage(gdi); + } + } + else + gdi_new = &gdi; + + if (gdi_new && bi.id == "AutoScroll" || bi.id == "FullScreen") { + tl_new->hideButtons = true; + + gdi_new->alert("help:fullscreen"); + + if (bi.id == "FullScreen") + gdi_new->setFullScreen(true); + + int h = gdi_new->setHighContrastMaxWidth(); + tl_new->loadPage(*gdi_new); + double sec = 6.0; + double delta = h * 20. / (1000. * sec); + gdi_new->setAutoScroll(delta); + } + else if (gdi_new && bi.id == "FullScreenLive") { + gdi_new->setFullScreen(true); + tl_new->hideButtons = true; + tl_new->loadPage(*gdi_new); + } + } + else if (bi.id == "Remember") { + oListParam &par = currentList.getParam(); + string baseName = par.getDefaultName(); + baseName = oe->getListContainer().makeUniqueParamName(baseName); + par.setName(baseName); + oe->synchronize(false); + oe->getListContainer().addListParam(currentList.getParam()); + oe->synchronize(true); + gdi.removeControl(bi.id); + } + else if (bi.id == "ShowSaved") { + ListBoxInfo lbi; + if (gdi.getSelectedItem("SavedInstance", lbi)) { + oListParam &par = oe->getListContainer().getParam(lbi.data); + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + } + } + else if (bi.id == "RenameSaved") { + ListBoxInfo lbi; + if (gdi.getSelectedItem("SavedInstance", lbi)) { + const oListParam &par = oe->getListContainer().getParam(lbi.data); + gdi.clearPage(true); + gdi.addString("", boldLarge, "Döp om X#" + par.getName()); + gdi.setData("ParamIx", lbi.data); + gdi.dropLine(); + gdi.fillRight(); + gdi.addInput("Name", par.getName(), 36); + gdi.setInputFocus("Name", true); + gdi.addButton("DoRenameSaved", "Döp om", ListsCB); + gdi.addButton("Cancel", "Avbryt", ListsCB); + gdi.dropLine(3); + } + } + else if (bi.id == "DoRenameSaved") { + int ix = int(gdi.getData("ParamIx")); + oListParam &par = oe->getListContainer().getParam(ix); + string name = gdi.getText("Name"); + par.setName(name); + loadPage(gdi); + } + else if (bi.id == "MergeSaved") { + ListBoxInfo lbi; + if (gdi.getSelectedItem("SavedInstance", lbi)) { + //oe->getListContainer().mergeParam(0, lbi.data); + const oListParam &par = oe->getListContainer().getParam(lbi.data); + gdi.clearPage(true); + gdi.addString("", boldLarge, "Slå ihop X#" + par.getName()); + gdi.setData("ParamIx", lbi.data); + gdi.dropLine(); + gdi.addListBox("Merge", 350, 250, 0, "Slå ihop med:"); + vector < pair > cand; + oe->getListContainer().getMergeCandidates(lbi.data, cand); + gdi.addItem("Merge", cand); + gdi.addCheckbox("ShowTitle", "Visa rubrik mellan listorna", 0, false); + gdi.fillRight(); + gdi.addButton("DoMerge", "Slå ihop", ListsCB); + gdi.addButton("Cancel", "Avbryt", ListsCB); + gdi.dropLine(3); + } + } + else if (bi.id == "DoMerge") { + ListBoxInfo lbi; + if (gdi.getSelectedItem("Merge", lbi)) { + int mergeWidth = lbi.data; + int base = (int)gdi.getData("ParamIx"); + oe->synchronize(false); + bool showTitle = gdi.isChecked("ShowTitle"); + oe->getListContainer().mergeParam(mergeWidth, base, showTitle); + oe->synchronize(true); + loadPage(gdi); + } + return 0; + } + else if (bi.id == "SplitSaved") { + ListBoxInfo lbi; + if (gdi.getSelectedItem("SavedInstance", lbi)) { + oe->synchronize(false); + oe->getListContainer().split(lbi.data); + oe->synchronize(true); + loadPage(gdi); + return 0; + } + } + else if (bi.id == "RemoveSaved") { + ListBoxInfo lbi; + if (gdi.getSelectedItem("SavedInstance", lbi)) { + oe->synchronize(false); + oe->getListContainer().removeParam(lbi.data); + oe->synchronize(true); + loadPage(gdi); + } + return 0; + } + else if (bi.id == "Automatic") { + PrintResultMachine prm(60*10, currentList); + tabAutoAddMachinge(prm); + gdi.getTabs().get(TAutoTab)->loadPage(gdi); + } + else if (bi.id == "WideFormat") { + enableWideFormat(gdi, gdi.isChecked(bi.id)); + } + else if (bi.id=="SelectAll") { + set lst; + lst.insert(-1); + gdi.setSelection("ListSelection", lst); + + if (gdi.hasField("ResultType")) { + ListBoxInfo entry; + gdi.getSelectedItem("ResultType", entry); + gdi.setInputStatus("Generate", int(entry.data) >= 0); + } + } + else if (bi.id=="SelectNone") { + set lst; + gdi.setSelection("ListSelection", lst); + if (gdi.hasField("ResultType")) { + gdi.setInputStatus("Generate", false); + } + } + else if (bi.id=="CancelPS") { + gdi.getTabs().get(TabType(bi.getExtraInt()))->loadPage(gdi); + } + else if (bi.id=="SavePS") { + const char *ctype = (char *)gdi.getData("Type"); + saveExtraLines(*oe, ctype, gdi); + + if (gdi.hasField("SplitAnalysis")) { + int aflag = (gdi.isChecked("SplitAnalysis") ? 0 : 1) + (gdi.isChecked("Speed") ? 0 : 2) + + (gdi.isChecked("Results") ? 0 : 4); + oe->getDI().setInt("Analysis", aflag); + } + + + if (gdi.hasField("WideFormat")) { + bool wide = gdi.isChecked("WideFormat"); + oe->setProperty("WideSplitFormat", wide); + + if (wide && gdi.hasField("NumPerPage")) { + pair res = gdi.getSelectedItem("NumPerPage"); + if (res.second) + oe->setProperty("NumSplitsOnePage", res.first); + + int no = gdi.getTextNo("MaxWaitTime"); + if (no >= 0) + oe->setProperty("SplitPrintMaxWait", no); + } + } + gdi.getTabs().get(TabType(bi.getExtraInt()))->loadPage(gdi); + } + else if (bi.id == "PrinterSetup") { + ((TabSI *)gdi.getTabs().get(TSITab))->printerSetup(gdi); + } + else if (bi.id=="Generate") { + ListBoxInfo lbi; + bool advancedResults = false; + if (gdi.getSelectedItem("ListType", lbi)) { + currentListType=EStdListType(lbi.data); + } + else if (gdi.getSelectedItem("ResultType", lbi)) { + currentListType = getTypeFromResultIndex(lbi.data); + lastSelectedResultList = lbi.data; + advancedResults = true; + } + else return 0; + + oListParam par; + gdi.getSelectedItem("ResultSpecialTo", lbi); + par.useControlIdResultTo = lbi.data; + + gdi.getSelectedItem("ResultSpecialFrom", lbi); + par.useControlIdResultFrom = lbi.data; + + gdi.getSelectedItem("LegNumber", lbi); + par.setLegNumberCoded(lbi.data); + lastLeg = lbi.data; + + gdi.getSelection("ListSelection", par.selection); + if (advancedResults) + lastResultClassSelection = par.selection; + par.filterMaxPer = gdi.getTextNo("ClassLimit"); + par.inputNumber = gdi.getTextNo("InputNumber"); + lastInputNumber = itos(par.inputNumber); + + par.pageBreak = gdi.isChecked("PageBreak"); + par.listCode = (EStdListType)currentListType; + par.showInterTimes = gdi.isChecked("ShowInterResults"); + par.showSplitTimes = gdi.isChecked("ShowSplits"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.setCustomTitle(gdi.getText("Title")); + par.useLargeSize = gdi.isChecked("UseLargeSize"); + + lastLimitPer = par.filterMaxPer; + lastInterResult = par.showInterTimes; + lastSplitState = par.showSplitTimes; + lastLargeSize = par.useLargeSize; + + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="GeneralList") { + if (SelectedList=="GeneralList") { + generateList(gdi); + } + else + loadGeneralList(gdi); + } + else if (bi.id == "EditList") { + if (!listEditor) + listEditor = new ListEditor(oe); + + gdi.clearPage(false); + listEditor->show(gdi); + gdi.refresh(); + } + else if (bi.id == "EditMethod") { + if (!methodEditor) + methodEditor = new MethodEditor(oe); + + gdi.clearPage(false); + methodEditor->show(gdi); + gdi.refresh(); + } + else if (bi.id=="ResultIndividual") { + oe->sanityCheck(gdi, true); + oListParam par; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getIndividual(par.selection); + par.listCode = EStdResultList; + par.showInterTimes = true; + par.setLegNumberCoded(-1); + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + + ListBoxInfo lbi; + gdi.getSelectedItem("ClassLimit", lbi); + par.filterMaxPer = lbi.data; + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="ResultIndSplit") { + oe->sanityCheck(gdi, true); + oListParam par; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getIndividual(par.selection); + par.listCode = EStdResultList; + par.showSplitTimes = true; + par.setLegNumberCoded(-1); + par.pageBreak = gdi.isChecked("PageBreak"); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="StartIndividual") { + oe->sanityCheck(gdi, false); + oListParam par; + par.listCode = EStdStartList; + par.setLegNumberCoded(-1); + par.pageBreak = gdi.isChecked("PageBreak"); + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getIndividual(par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="StartClub") { + oe->sanityCheck(gdi, false); + oListParam par; + par.listCode = EStdClubStartList; + par.pageBreak = gdi.isChecked("PageBreak"); + par.setLegNumberCoded(-1); + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + //cnf.getIndividual(par.selection); + //cnf.getPatrol(par.selection); + + // oListInfo foo = currentList; + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + //currentList.addList(foo); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="ResultClub") { + oe->sanityCheck(gdi, false); + oListParam par; + par.listCode = EStdClubResultList; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.setLegNumberCoded(-1); + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getIndividual(par.selection); + cnf.getPatrol(par.selection); + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="PreReport") { + SelectedList=bi.id; + gdi.clearPage(false); + oe->generatePreReport(gdi); + baseButtons(gdi, 0); + gdi.refresh(); + } + else if (bi.id=="InForestList") { + SelectedList=bi.id; + gdi.clearPage(false); + + gdi.registerEvent("DataUpdate", ListsEventCB); + gdi.setData("DataSync", 1); + gdi.registerEvent(bi.id, ListsCB); + + oe->generateInForestList(gdi, openRunnerTeamCB, NoStartRunnerCB); + baseButtons(gdi, 1); + gdi.refresh(); + } + else if (bi.id=="TeamStartList") { + oe->sanityCheck(gdi, false); + oListParam par; + par.listCode = EStdTeamStartList; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRelay(par.selection); + par.pageBreak = gdi.isChecked("PageBreak"); + par.setLegNumberCoded(0); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="RaceNStart") { + oe->sanityCheck(gdi, false); + oListParam par; + int race = int(bi.getExtra()); + par.setLegNumberCoded(race); + par.listCode = EStdIndMultiStartListLeg; + par.pageBreak = gdi.isChecked("PageBreak"); + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRaceNStart(race, par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="LegNStart") { + oe->sanityCheck(gdi, false); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + int race = bi.getExtraInt(); + par.setLegNumberCoded(race); + par.listCode = EStdTeamStartListLeg; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getLegNStart(race, par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="PatrolStartList") { + oe->sanityCheck(gdi, false); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.listCode = EStdPatrolStartList; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getPatrol(par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="TeamResults") { + oe->sanityCheck(gdi, true); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.listCode = EStdTeamResultListAll; + + par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; + + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRelay(par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="MultiResults") { + oe->sanityCheck(gdi, true); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.listCode = EStdIndMultiResultListAll; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRaceNRes(0, par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="RaceNRes") { + oe->sanityCheck(gdi, true); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + int race = int(bi.getExtra()); + par.setLegNumberCoded(race); + par.listCode = EStdIndMultiResultListLeg; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRaceNRes(race, par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="LegNResult") { + oe->sanityCheck(gdi, true); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + int race = bi.getExtraInt(); + par.setLegNumberCoded(race); + par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; + par.listCode = oe->getListContainer().getType("legresult"); + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getLegNRes(race, par.selection); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="PatrolResultList") { + oe->sanityCheck(gdi, false); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.listCode = EStdPatrolResultList; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getPatrol(par.selection); + + par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="RogainingResultList") { + oe->sanityCheck(gdi, true); + oListParam par; + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.listCode = ERogainingInd; + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRogaining(par.selection); + + par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="CourseReport") { + oe->sanityCheck(gdi, false); + + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + vector par; + + if (cnf.hasTeamClass()) { + par.push_back(oListParam()); + par.back().pageBreak = gdi.isChecked("PageBreak"); + par.back().listCode = ETeamCourseList; + cnf.getTeamClass(par.back().selection); + } + + if (cnf.hasIndividual()) { + par.push_back(oListParam()); + par.back().pageBreak = gdi.isChecked("PageBreak"); + par.back().listCode = EIndCourseList; + par.back().showInterTitle = false; + cnf.getIndividual(par.back().selection); + } + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="RentedCards") { + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + oListParam par; + par.listCode = EStdRentedCard; + par.setLegNumberCoded(-1); + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="PriceList") { + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + oListParam par; + cnf.getIndividual(par.selection); + par.listCode = EIndPriceList; + par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id=="MinuteStartList") { + oe->sanityCheck(gdi, false); + SelectedList=bi.id; + gdi.clearPage(false); + + gdi.registerEvent("DataUpdate", ListsEventCB); + gdi.setData("DataSync", 1); + gdi.registerEvent(bi.id, ListsCB); + + oe->generateMinuteStartlist(gdi); + baseButtons(gdi, 0); + gdi.refresh(); + } + else if (bi.id=="ResultList") { + settingsResultList(gdi); + } + else if (bi.id.substr(0, 7) == "Result:" || + bi.id.substr(0, 7) == "StartL:" || + bi.id.substr(0, 7) == "GenLst:") { + bool isReport = bi.id.substr(0, 7) == "GenLst:"; + bool allClasses = bi.getExtraInt() == 1; + bool rogaining = bi.getExtraInt() == 2; + oe->sanityCheck(gdi, bi.id.substr(0, 7) == "Result:"); + oListParam par; + par.listCode = oe->getListContainer().getType(bi.id.substr(7)); + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + + par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; + + par.setLegNumberCoded(-1); + + if (rogaining) { + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getRogaining(par.selection); + } + else if (!isReport && !allClasses) { + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + cnf.getIndividual(par.selection); + cnf.getPatrol(par.selection); + } + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id == "CustomList") { + oe->synchronize(); + oe->sanityCheck(gdi, false); + oListParam par; + int index = bi.getExtraInt(); + par.listCode = oe->getListContainer().getType(index); + par.pageBreak = gdi.isChecked("PageBreak"); + par.splitAnalysis = gdi.isChecked("SplitAnalysis"); + par.setLegNumberCoded(-1); + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + + oListInfo::EBaseType type = oe->getListContainer().getList(index).getListType(); + if (oListInfo::addRunners(type)) + cnf.getIndividual(par.selection); + if (oListInfo::addPatrols(type)) + cnf.getPatrol(par.selection); + if (oListInfo::addTeams(type)) + cnf.getTeamClass(par.selection); + + oe->generateListInfo(par, gdi.getLineHeight(), currentList); + currentList.setCallback(openRunnerTeamCB); + generateList(gdi); + gdi.refresh(); + } + else if (bi.id == "ImportCustom") { + + MetaListContainer &lc = oe->getListContainer(); + vector< pair > installedLists; + set installedId; + for (int k = 0; k < lc.getNumLists(); k++) { + if (lc.isExternal(k)) { + MetaList &mc = lc.getList(k); + installedLists.push_back(make_pair(mc.getListName(), k)); + mc.initUniqueIndex(); + if (!mc.getUniqueId().empty()) + installedId.insert(mc.getUniqueId()); + } + } + + vector< pair > > lists; + lc.enumerateLists(lists); + if (lists.empty() && installedLists.empty()) { + bi.id = "BrowseList"; + return listCB(gdi, GUI_BUTTON, &bi); + } + + + gdi.clearPage(false); + gdi.addString("", boldLarge, "Tillgängliga listor"); + int xx = gdi.getCX() + gdi.scaleLength(360); + int bx = gdi.getCX(); + if (!installedLists.empty()) { + gdi.dropLine(); + gdi.addString("", 1, "Listor i tävlingen"); + gdi.fillRight(); + gdi.pushX(); + for (size_t k = 0; k < installedLists.size(); k++) { + gdi.addStringUT(0, installedLists[k].first).setColor(colorDarkGreen); + gdi.setCX(xx); + gdi.addString("RemoveInstalled", 0, "Ta bort", ListsCB).setExtra(installedLists[k].second); + gdi.addString("EditInstalled", 0, "Redigera", ListsCB).setExtra(installedLists[k].second); + gdi.dropLine(); + if (k+1 < installedLists.size()) { + RECT rc = {bx, gdi.getCY(),gdi.getCX(),gdi.getCY()+1}; + gdi.addRectangle(rc, colorDarkBlue); + gdi.dropLine(0.1); + } + gdi.popX(); + } + gdi.fillDown(); + gdi.popX(); + } + + if (!lists.empty()) { + gdi.dropLine(2); + gdi.addString("", 1, "Installerbara listor"); + gdi.fillRight(); + gdi.pushX(); + + for (size_t k = 0; k < lists.size(); k++) { + gdi.addStringUT(0, lists[k].first, 0); + if (!installedId.count(lists[k].second.first)) { + gdi.setCX(xx); + gdi.addString("CustomList", 0, "Lägg till", ListsCB).setColor(colorDarkGreen).setExtra(k); + gdi.addString("RemoveList", 0, "Radera permanent", ListsCB).setColor(colorDarkRed).setExtra(k); + } + gdi.dropLine(); + + if (k+1 < lists.size() && !installedId.count(lists[k].second.first)) { + RECT rc = {bx, gdi.getCY(),gdi.getCX(),gdi.getCY()+1}; + gdi.addRectangle(rc, colorDarkBlue); + gdi.dropLine(0.1); + } + gdi.popX(); + + } + gdi.fillDown(); + gdi.popX(); + } + + gdi.dropLine(2); + gdi.fillRight(); + gdi.addButton("BrowseList", "Bläddra...", ListsCB); + gdi.addButton("Cancel", "Återgå", ListsCB).setCancel(); + gdi.refresh(); + } + else if (bi.id == "BrowseList") { + vector< pair > filter; + filter.push_back(make_pair("xml-data", "*.xml;*.meoslist")); + string file = gdi.browseForOpen(filter, "xml"); + if (!file.empty()) { + xmlparser xml(0); + xml.read(file); + xmlobject xlist = xml.getObject(0); + oe->synchronize(); + oe->getListContainer().load(MetaListContainer::ExternalList, xlist, false); + oe->synchronize(true); + + loadPage(gdi); + } + } + else if (bi.id == "ResultListFT_ONATT") { + vector< pair > ext; + ext.push_back(make_pair("Semikolonseparerad", "*.csv;*.txt")); + string file=gdi.browseForSave(ext, "txt", index); + if (!file.empty()) + oe->exportONattResults(gdi, file); + } + else if (bi.id == "EditInForest") { + TabRunner &rt = dynamic_cast(*gdi.getTabs().get(TRunnerTab)); + rt.showInForestList(gdi); + } + else if (bi.id == "SplitAnalysis") { + oe->setProperty("splitanalysis", gdi.isChecked(bi.id)); + } + else if (bi.id == "PageBreak") { + oe->setProperty("pagebreak", gdi.isChecked(bi.id)); + } + else if (bi.id == "ShowInterResults"){ + oe->setProperty("intertime", gdi.isChecked(bi.id)); + } + } + else if (type==GUI_LISTBOX) { + ListBoxInfo lbi=*(ListBoxInfo *)data; + + if (lbi.id == "NumPerPage") { + enableWideFormat(gdi, true); + } + else if (lbi.id == "SavedInstance") { + int ix = lbi.data; + bool split = oe->getListContainer().canSplit(ix); + gdi.setInputStatus("SplitSaved", split); + } + else if (lbi.id=="ListType"){ + EStdListType type = EStdListType(lbi.data); + selectGeneralList(gdi, type); + } + else if (lbi.id == "ListSelection") { + gdi.getSelection(lbi.id, lastClassSelection); + if (gdi.hasField("ResultType")) { + ListBoxInfo entry; + gdi.getSelectedItem("ResultType", entry); + gdi.setInputStatus("Generate", !lastClassSelection.empty() && int(entry.data) >= 0); + } + } + else if (lbi.id == "ClassLimit"){ + oe->setProperty("classlimit", lbi.data); + } + else if (lbi.id=="ResultType") { + setResultOptionsFromType(gdi, lbi.data); + } + else if (lbi.id=="ResultSpecialTo") { + oe->setProperty("ControlTo", lbi.data); + } + else if (lbi.id=="ResultSpecialFrom") { + oe->setProperty("ControlFrom", lbi.data); + } + } + else if (type==GUI_CLEAR) { + offsetY=gdi.GetOffsetY(); + offsetX=gdi.GetOffsetX(); + return true; + } + else if (type == GUI_LINK) { + TextInfo ti = *(TextInfo *)data; + if (ti.id == "CustomList") { + vector< pair > > lists; + oe->getListContainer().enumerateLists(lists); + size_t ix = ti.getExtraSize(); + if (ix < lists.size()) { + xmlparser xml(0); + xml.read(lists[ix].second.second); + xmlobject xlist = xml.getObject(0); + + oe->synchronize(false); + oe->getListContainer().load(MetaListContainer::ExternalList, xlist, false); + oe->synchronize(true); + oe->loadGeneralResults(true); + } + ButtonInfo bi; + bi.id = "ImportCustom"; + listCB(gdi, GUI_BUTTON, &bi); + + } + else if (ti.id == "RemoveList") { + vector< pair > > lists; + oe->getListContainer().enumerateLists(lists); + size_t ix = ti.getExtraSize(); + if (ix < lists.size()) { + if (gdi.ask("Vill du ta bort 'X'?#" + lists[ix].first)) { + DeleteFile(lists[ix].second.second.c_str()); + } + } + ButtonInfo bi; + bi.id = "ImportCustom"; + listCB(gdi, GUI_BUTTON, &bi); + } + else if (ti.id == "RemoveInstalled") { + int ix = ti.getExtraInt(); + if (gdi.ask("Vill du ta bort 'X'?#" + oe->getListContainer().getList(ix).getListName())) { + + oe->synchronize(false); + oe->getListContainer().removeList(ix); + oe->synchronize(true); + + ButtonInfo bi; + bi.id = "ImportCustom"; + listCB(gdi, GUI_BUTTON, &bi); + } + } + else if (ti.id == "EditInstalled") { + int ix = ti.getExtraInt(); + if (!listEditor) + listEditor = new ListEditor(oe); + gdi.clearPage(false); + listEditor->load(oe->getListContainer(), ix); + listEditor->show(gdi); + gdi.refresh(); + } + } + + return 0; +} + +void TabList::enableFromTo(oEvent &oe, gdioutput &gdi, bool from, bool to) { + vector< pair > d; + oe.fillControls(d, oEvent::CTCourseControl); + + if (from) { + gdi.enableInput("ResultSpecialFrom"); + vector< pair > ds; + ds.push_back(make_pair(lang.tl("Start"), 0)); + ds.insert(ds.end(), d.begin(), d.end()); + gdi.addItem("ResultSpecialFrom", ds); + if (!gdi.selectItemByData("ResultSpecialFrom", oe.getPropertyInt("ControlFrom", 0))) { + gdi.selectItemByData("ResultSpecialFrom", 0); // Fallback + } + } + else { + gdi.clearList("ResultSpecialFrom"); + gdi.disableInput("ResultSpecialFrom"); + } + + if (to) { + gdi.enableInput("ResultSpecialTo"); + gdi.addItem("ResultSpecialTo", d); + gdi.addItem("ResultSpecialTo", lang.tl("Mål"), 0); + if (!gdi.selectItemByData("ResultSpecialTo", oe.getPropertyInt("ControlTo", 0))) { + gdi.selectItemByData("ResultSpecialTo", 0); // Fallback + } + } + else { + gdi.clearList("ResultSpecialTo"); + gdi.disableInput("ResultSpecialTo"); + } +} + +void TabList::selectGeneralList(gdioutput &gdi, EStdListType type) +{ + oListInfo li; + oe->getListType(type, li); + oe->setProperty("ListType", type); + if (li.supportClasses) { + gdi.enableInput("ListSelection"); + oe->fillClasses(gdi, "ListSelection", oEvent::extraNone, oEvent::filterNone); + if (lastClassSelection.empty()) + lastClassSelection.insert(-1); + gdi.setSelection("ListSelection", lastClassSelection); + } + else { + gdi.clearList("ListSelection"); + gdi.disableInput("ListSelection"); + } + + gdi.setInputStatus("UseLargeSize", li.supportLarge); + gdi.setInputStatus("InputNumber", li.supportParameter); + + gdi.setInputStatus("SplitAnalysis", li.supportSplitAnalysis); + gdi.setInputStatus("ShowInterResults", li.supportInterResults); + gdi.setInputStatus("PageBreak", li.supportPageBreak); + gdi.setInputStatus("ClassLimit", li.supportClassLimit); + //gdi.setInputStatus("Title", li.supportCustomTitle); + + if (li.supportLegs) { + //gdi.enableInput("LegNumber"); + //oe->fillLegNumbers(gdi, "LegNumber", li.isTeamList(), true); + set clsUnused; + vector< pair > out; + oe->fillLegNumbers(clsUnused, li.isTeamList(), true, out); + gdi.addItem("LegNumber", out); + gdi.setInputStatus("LegNumber", !out.empty()); + } + else { + gdi.disableInput("LegNumber"); + gdi.clearList("LegNumber"); + } + + enableFromTo(*oe, gdi, li.supportFrom, li.supportTo); +} + +void TabList::makeClassSelection(gdioutput &gdi) { + gdi.fillDown(); + gdi.addListBox("ListSelection", 250, 300, ListsCB, "Urval:", "", true); + + gdi.pushX(); + gdi.fillRight(); + gdi.dropLine(0.5); + + gdi.addButton("SelectAll", "Välj allt", ListsCB); + gdi.addButton("SelectNone", "Välj inget", ListsCB); + gdi.popX(); +} + +void TabList::loadGeneralList(gdioutput &gdi) +{ + oe->sanityCheck(gdi, false); + gdi.fillDown(); + gdi.clearPage(false); + gdi.addString("", boldLarge, "Skapa generell lista"); + gdi.dropLine(0.8); + gdi.pushY(); + gdi.addSelection("ListType", 250, 300, ListsCB, "Lista:"); + oe->fillListTypes(gdi, "ListType", 0); + + makeClassSelection(gdi); + + gdi.setCX(gdi.scaleLength(290)+30); + gdi.pushX(); + gdi.popY(); + gdi.fillDown(); + gdi.addCheckbox("PageBreak", "Sidbrytning mellan klasser / klubbar", ListsCB, oe->getPropertyInt("pagebreak", 0)!=0); + + gdi.addCheckbox("ShowInterResults", "Visa mellantider", ListsCB, oe->getPropertyInt("intertime", 1)!=0, "Mellantider visas för namngivna kontroller."); + gdi.addCheckbox("SplitAnalysis", "Med sträcktidsanalys", ListsCB, oe->getPropertyInt("splitanalysis", 1)!=0); + gdi.addCheckbox("UseLargeSize", "Använd stor font", 0, lastLargeSize); + + if (lastLimitPer == -1) { + lastLimitPer = oe->getPropertyInt("classlimit", 0); + } + string lastClassLimit; + if (lastLimitPer > 0) + lastClassLimit = itos(lastLimitPer); + + gdi.addInput("ClassLimit", lastClassLimit, 5, 0, "Begränsa antal per klass:"); + gdi.dropLine(); + + makeFromTo(gdi); + /*gdi.fillRight(); + gdi.pushX(); + gdi.addSelection("ResultSpecialFrom", 140, 300, ListsCB, "Från kontroll:"); + gdi.disableInput("ResultSpecialFrom"); + + gdi.addSelection("ResultSpecialTo", 140, 300, ListsCB, "Till kontroll:"); + gdi.disableInput("ResultSpecialTo"); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + */ + gdi.addSelection("LegNumber", 140, 300, ListsCB, "Sträcka:"); + gdi.disableInput("LegNumber"); + + gdi.addInput("InputNumber", lastInputNumber, 5, 0, "Listparameter:", "Ett värde vars tolkning beror på listan."); + gdi.disableInput("InputNumber"); + gdi.popX(); + + if (oe->getPropertyInt("ListType", 0) > 0) { + gdi.selectItemByData("ListType", oe->getPropertyInt("ListType", 0)); + selectGeneralList(gdi, EStdListType(oe->getPropertyInt("ListType", 0))); + } + + + gdi.dropLine(3); + gdi.addInput("Title", "", 32, ListsCB, "Egen listrubrik:"); + + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("Generate", "Generera", ListsCB); + gdi.addButton("Cancel", "Avbryt", ListsCB); + + gdi.refresh(); +} + +static int getListIx(const map &tag2ListIx, + set &usedListIx, + const char *tag, int fallback) { + map::const_iterator res = tag2ListIx.find(tag); + if (res != tag2ListIx.end()) { + usedListIx.insert(res->second); + return res->second; + } + return fallback; +} + +void TabList::makeFromTo(gdioutput &gdi) { + gdi.fillRight(); + gdi.pushX(); + + gdi.addSelection("ResultSpecialFrom", 140, 300, ListsCB, "Från kontroll:"); + gdi.disableInput("ResultSpecialFrom"); + + gdi.addSelection("ResultSpecialTo", 140, 300, ListsCB, "Till kontroll:"); + gdi.disableInput("ResultSpecialTo"); + + gdi.popX(); + gdi.dropLine(3); +} + +void TabList::settingsResultList(gdioutput &gdi) +{ + lastFilledResultClassType = -1; + oe->sanityCheck(gdi, true); + gdi.fillDown(); + gdi.clearPage(false); + gdi.addString("", boldLarge, MakeDash("Resultatlista - inställningar")); + + //gdi.addSelection("ListType", 200, 300, ListsCB, "Lista"); + //oe->fillListTypes(gdi, "ListType", 0); + const int boxHeight = 380; + gdi.pushY(); + gdi.fillDown(); + gdi.addListBox("ListSelection", 200, boxHeight, ListsCB, "Urval:", "", true); + + gdi.dropLine(0.5); + gdi.fillRight(); + gdi.addButton("SelectAll", "Välj allt", ListsCB); + gdi.addButton("SelectNone", "Välj inget", ListsCB); + + gdi.popY(); + gdi.setCX(gdi.scaleLength(250)); + infoCX = gdi.getCX(); + infoCY = gdi.getCY() + gdi.scaleLength(boxHeight) + 2 *gdi.getLineHeight(); + + gdi.fillDown(); + gdi.addString("", 0, "Typ av lista:"); + gdi.pushX(); + gdi.fillRight(); + + gdi.addListBox("ResultType", 180, boxHeight, ListsCB); + + vector< pair > lists; + vector< pair > dlists; + const MetaListContainer &lc = oe->getListContainer(); + lc.getLists(dlists, false, true, !oe->hasTeam()); + set usedListIx; + map tag2ListIx; + for (size_t k = 0; k < dlists.size(); k++) { + int ix = dlists[k].second; + if (lc.isInternal(ix)) + tag2ListIx[lc.getTag(ix)] = dlists[k].second + CUSTOM_OFFSET; + } + lists.reserve(dlists.size() + 10); + + lists.push_back(make_pair(lang.tl("Individuell"), 1)); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol)) + lists.push_back(make_pair(lang.tl("Patrull"), 2)); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Relay)) { + lists.push_back(make_pair(lang.tl("Stafett - total"), 3)); + lists.push_back(make_pair(lang.tl("Stafett - sammanställning"), 4)); + + lists.push_back(make_pair(lang.tl("Stafett - sträcka"), + getListIx(tag2ListIx, usedListIx, "legresult", 5))); + } + + lists.push_back(make_pair(lang.tl("Allmänna resultat"), 6)); + + size_t startIx = lists.size(); + for (size_t k = 0; k < dlists.size(); k++) { + int ix = dlists[k].second + CUSTOM_OFFSET; + if (usedListIx.count(ix)) + continue; + lists.push_back(make_pair(dlists[k].first, ix)); + } + sort(lists.begin() + startIx, lists.end()); + + gdi.addItem("ResultType", lists); + gdi.autoGrow("ResultType"); + + int lastSelectedResultListOK = -1; + for (size_t k = 0; k < lists.size(); k++) { + if (lastSelectedResultList == lists[k].second) + lastSelectedResultListOK = lists[k].second; + } + + if (lastSelectedResultListOK >= 0) + gdi.selectItemByData("ResultType", lastSelectedResultListOK); + + gdi.fillDown(); + gdi.pushX(); + gdi.addCheckbox("PageBreak", "Sidbrytning mellan klasser", ListsCB, oe->getPropertyInt("pagebreak", 0)!=0); + gdi.addCheckbox("ShowInterResults", "Visa mellantider", 0, lastInterResult, + "Mellantider visas för namngivna kontroller."); + gdi.addCheckbox("ShowSplits", "Lista med sträcktider", 0, lastSplitState); + gdi.addCheckbox("UseLargeSize", "Använd stor font", 0, lastLargeSize); + + gdi.fillRight(); + gdi.popX(); + gdi.addString("", 0, "Topplista, N bästa:"); + gdi.dropLine(-0.2); + + if (lastLimitPer == -1) { + lastLimitPer = oe->getPropertyInt("classlimit", 0); + } + string lastClassLimit; + if (lastLimitPer > 0) + lastClassLimit = itos(lastLimitPer); + + gdi.addInput("ClassLimit", lastClassLimit, 5, 0); + gdi.popX(); + gdi.dropLine(2); + gdi.addString("", 0, "Listparameter:"); + gdi.dropLine(-0.2); + gdi.addInput("InputNumber", lastInputNumber, 5, 0, "", "Ett värde vars tolkning beror på listan."); + gdi.disableInput("InputNumber"); + gdi.popX(); + gdi.dropLine(2); + + makeFromTo(gdi); + + gdi.addSelection("LegNumber", 140, 300, ListsCB, "Sträcka:"); + gdi.disableInput("LegNumber"); + gdi.popX(); + + gdi.dropLine(3); + gdi.addInput("Title", "", 32, ListsCB, "Egen listrubrik:"); + gdi.popX(); + + gdi.dropLine(3.5); + createListButtons(gdi); + + gdi.setRestorePoint("ListInfo"); + infoCY = max(infoCY, gdi.getCY()); + gdi.setCX(infoCX); + gdi.setCY(infoCY); + + if (lastSelectedResultListOK >= 0) + setResultOptionsFromType(gdi, lastSelectedResultListOK); + gdi.refresh(); +} + +void TabList::createListButtons(gdioutput &gdi) { + gdi.fillRight(); + gdi.addButton("Generate", "Skapa listan", ListsCB).setDefault(); + gdi.disableInput("Generate"); + gdi.addButton("Cancel", "Avbryt", ListsCB).setCancel(); + gdi.popX(); +} + +void checkWidth(gdioutput &gdi) { + int h,w; + gdi.getTargetDimension(w, h); + w = max (w, gdi.scaleLength(300)); + if (gdi.getCX() + gdi.scaleLength(100) > w) { + gdi.popX(); + gdi.dropLine(2.5); + } +} + +bool TabList::loadPage(gdioutput &gdi, const string &command) { + SelectedList = command; + offsetX = 0; + offsetY = 0; + return loadPage(gdi); +} + +bool TabList::loadPage(gdioutput &gdi) +{ + oe->checkDB(); + oe->synchronize(); + gdi.selectTab(tabId); + noReEvaluate = false; + gdi.clearPage(false); + if (SelectedList!="") { + ButtonInfo bi; + bi.id=SelectedList; + ListsCB(&gdi, GUI_BUTTON, &bi); + //gdi.SendCtrlMessage(SelectedList); + gdi.setOffset(offsetX, offsetY, false); + return 0; + } + + // Make sure all lists are loaded + oListInfo li; + oe->getListType(EStdNone, li); + + gdi.addString("", boldLarge, "Listor och sammanställningar"); + + gdi.addString("", 10, "help:30750"); + + ClassConfigInfo cnf; + oe->getClassConfigurationInfo(cnf); + gdi.pushX(); + if (!cnf.empty()) { + gdi.dropLine(1); + gdi.addString("", 1, "Startlistor"); + gdi.fillRight(); + if (cnf.hasIndividual()) { + gdi.addButton("StartIndividual", "Individuell", ListsCB); + checkWidth(gdi); + gdi.addButton("StartClub", "Klubbstartlista", ListsCB); + } + + for (size_t k = 0; k 0) { + checkWidth(gdi); + gdi.addButton("RaceNStart", "Lopp X#" + itos(k+1), ListsCB, + "Startlista ett visst lopp.").setExtra(k); + } + } + if (cnf.hasRelay()) { + checkWidth(gdi); + gdi.addButton("TeamStartList", "Stafett (sammanställning)", ListsCB); + } + if (cnf.hasPatrol()) { + checkWidth(gdi); + gdi.addButton("PatrolStartList", "Patrull", ListsCB); + } + for (size_t k = 0; k 0) { + checkWidth(gdi); + gdi.addButton("LegNStart", "Sträcka X#" + itos(k+1), ListsCB).setExtra(k); + } + } + + checkWidth(gdi); + gdi.addButton("MinuteStartList", "Minutstartlista", ListsCB); + + if (cnf.isMultiStageEvent()) { + checkWidth(gdi); + gdi.addButton("StartL:inputresult", "Input Results", ListsCB); + } + + gdi.dropLine(3); + gdi.fillDown(); + gdi.popX(); + gdi.addString("", 1, "Resultatlistor"); + gdi.fillRight(); + + if (cnf.hasIndividual()) { + gdi.addButton("ResultIndividual", "Individuell", ListsCB); + checkWidth(gdi); + gdi.addButton("ResultClub", "Klubbresultat", ListsCB); + checkWidth(gdi); + gdi.addButton("ResultIndSplit", "Sträcktider", ListsCB); + + checkWidth(gdi); + gdi.addButton("Result:latestresult", "Latest Results", ListsCB).setExtra(1); + + if (cnf.isMultiStageEvent()) { + checkWidth(gdi); + gdi.addButton("Result:stageresult", "Etappresultat", ListsCB); + + checkWidth(gdi); + gdi.addButton("Result:finalresult", "Slutresultat", ListsCB); + } + } + bool hasMulti = false; + for (size_t k = 0; k 0) { + checkWidth(gdi); + gdi.addButton("RaceNRes", "Lopp X#" + itos(k+1), ListsCB, + "Resultat för ett visst lopp.").setExtra(k); + hasMulti = true; + } + } + + if (hasMulti) { + checkWidth(gdi); + gdi.addButton("MultiResults", "Alla lopp", ListsCB, "Individuell resultatlista, sammanställning av flera lopp."); + } + if (cnf.hasRelay()) { + checkWidth(gdi); + gdi.addButton("TeamResults", "Stafett (sammanställning)", ListsCB); + } + if (cnf.hasPatrol()) { + checkWidth(gdi); + gdi.addButton("PatrolResultList", "Patrull", ListsCB); + } + for (map >::const_iterator it = cnf.legResult.begin(); it != cnf.legResult.end(); ++it) { + checkWidth(gdi); + gdi.addButton("LegNResult", "Sträcka X#" + itos(it->first+1), ListsCB).setExtra(it->first); + } + + if (cnf.hasRogaining()) { + checkWidth(gdi); + //gdi.addButton("RogainingResultList", "Rogaining", ListsCB); + gdi.addButton("Result:rogainingind", "Rogaining", ListsCB).setExtra(2); + } + + checkWidth(gdi); + gdi.addButton("ResultList", "Avancerat...", ListsCB); + + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + } + + + MetaListContainer &lc = oe->getListContainer(); + if (lc.getNumLists(MetaListContainer::ExternalList) > 0) { + gdi.addString("", 1, "Egna listor"); + + gdi.fillRight(); + gdi.pushX(); + + for (int k = 0; k < lc.getNumLists(); k++) { + if (lc.isExternal(k)) { + MetaList &mc = lc.getList(k); + checkWidth(gdi); + gdi.addButton("CustomList", mc.getListName(), ListsCB).setExtra(k); + } + } + } + + gdi.popX(); + gdi.dropLine(3); + gdi.fillDown(); + + vector< pair > savedParams; + lc.getListParam(savedParams); + if (savedParams.size() > 0) { + gdi.addString("", 1, "Sparade listval"); + gdi.fillRight(); + gdi.pushX(); + + gdi.addSelection("SavedInstance", 250, 200, ListsCB); + gdi.addItem("SavedInstance", savedParams); + gdi.autoGrow("SavedInstance"); + gdi.selectFirstItem("SavedInstance"); + gdi.addButton("ShowSaved", "Visa", ListsCB); + gdi.addButton("RenameSaved", "Döp om", ListsCB); + gdi.addButton("MergeSaved", "Slå ihop...", ListsCB); + gdi.addButton("SplitSaved", "Dela upp...", ListsCB); + + bool split = oe->getListContainer().canSplit(savedParams[0].second); + gdi.setInputStatus("SplitSaved", split); + + gdi.addButton("RemoveSaved", "Ta bort", ListsCB); + gdi.popX(); + gdi.dropLine(3); + gdi.fillDown(); + } + + gdi.addString("", 1, "Rapporter"); + + gdi.fillRight(); + gdi.pushX(); + + gdi.addButton("InForestList", "Kvar-i-skogen", ListsCB, "tooltip:inforest"); + if (cnf.hasIndividual()) { + gdi.addButton("PriceList", "Prisutdelningslista", ListsCB); + } + gdi.addButton("PreReport", "Kör kontroll inför tävlingen...", ListsCB); + checkWidth(gdi); + + if (cnf.hasMultiCourse) { + gdi.addButton("CourseReport", "Bantilldelning", ListsCB); + checkWidth(gdi); + + if (cnf.hasTeamClass()) { + gdi.addButton("GenLst:courseteamtable", "Gafflingar i tabellformat", ListsCB, + "Från den här listan kan man skapa etiketter att klistra på kartor"); + checkWidth(gdi); + } + } + + bool hasVac = false; + { + vector rr; + oe->getRunners(0, 0, rr, false); + for (size_t k = 0; k < rr.size(); k++) { + if (rr[k]->isVacant()) { + hasVac = true; + break; + } + } + } + + if (hasVac) { + gdi.addButton("GenLst:vacnacy", "Vakanser", ListsCB); + checkWidth(gdi); + } + + gdi.addButton("GenLst:courseusage", "Bananvändning", ListsCB); + checkWidth(gdi); + + gdi.addButton("GenLst:controloverview", "Kontroller", ListsCB); + checkWidth(gdi); + + gdi.addButton("GenLst:controlstatistics", "Control Statistics", ListsCB); + checkWidth(gdi); + + if (cnf.hasRentedCard) + gdi.addButton("RentedCards", "Hyrbricksrapport", ListsCB); + + gdi.popX(); + + gdi.dropLine(3); + gdi.addCheckbox("PageBreak", "Sidbrytning mellan klasser / klubbar", ListsCB, oe->getPropertyInt("pagebreak", 0)!=0); + gdi.addCheckbox("SplitAnalysis", "Med sträcktidsanalys", ListsCB, oe->getPropertyInt("splitanalysis", 1)!=0); + + gdi.popX(); + gdi.fillRight(); + gdi.dropLine(2); + gdi.addString("", 0, "Begränsning, antal visade per klass: "); + gdi.dropLine(-0.2); + gdi.addSelection("ClassLimit", 70, 350, ListsCB); + gdi.addItem("ClassLimit", lang.tl("Ingen"), 0); + for (int k = 1; k<=12+9; k++) { + int v = k; + if (v>12) + v=(v-11)*10; + gdi.addItem("ClassLimit", itos(v), v); + } + gdi.selectItemByData("ClassLimit", oe->getPropertyInt("classlimit", 0)); + + gdi.popX(); + + gdi.dropLine(3); + + gdi.addButton("GeneralList", "Alla listor...", ListsCB); + gdi.addButton("EditList", "Redigera lista...", ListsCB); + + gdi.addButton("ImportCustom", "Hantera egna listor...", ListsCB); + checkWidth(gdi); + gdi.addButton("EditMethod", "Result Modules...", ListsCB); + + //gdi.registerEvent("DataUpdate", ListsEventCB); + gdi.refresh(); + + gdi.setOnClearCb(ListsCB); + + offsetY=0; + offsetX=0; + gdi.refresh(); + return true; +} + +void TabList::enableWideFormat(gdioutput &gdi, bool wide) { + if (gdi.hasField("NumPerPage")) { + gdi.setInputStatus("NumPerPage", wide); + + bool needTime = gdi.getSelectedItem("NumPerPage").first != 1; + gdi.setInputStatus("MaxWaitTime", wide & needTime); + } +} + +void TabList::splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter, + TabType returnMode, PrintSettingsSelection type) +{ + if (!gdi.canClear()) + return; + + gdi.clearPage(false); + gdi.fillDown(); + if (type == Splits) + gdi.addString("", boldLarge, "Inställningar sträcktidsutskrift"); + else + gdi.addString("", boldLarge, "Inställningar startbevis"); + + gdi.dropLine(); + + gdi.fillRight(); + gdi.pushX(); + if (setupPrinter) { + gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar"); + gdi.dropLine(0.3); + } + + + if (!oe.empty() && type == Splits) { + bool withSplitAnalysis = (oe.getDCI().getInt("Analysis") & 1) == 0; + bool withSpeed = (oe.getDCI().getInt("Analysis") & 2) == 0; + bool withResult = (oe.getDCI().getInt("Analysis") & 4) == 0; + + gdi.addCheckbox("SplitAnalysis", "Med sträcktidsanalys", 0, withSplitAnalysis); + gdi.addCheckbox("Speed", "Med km-tid", 0, withSpeed); + gdi.addCheckbox("Results", "Med resultat", 0, withResult); + + } + gdi.popX(); + gdi.fillDown(); + char *ctype = type == Splits ? "SPExtra" : "EntryExtra"; + customTextLines(oe, ctype, gdi); + + if (type == Splits) { + const bool wideFormat = oe.getPropertyInt("WideSplitFormat", 0) == 1; + gdi.addCheckbox("WideFormat", "Sträcktider i kolumner (för standardpapper)", ListsCB, wideFormat); + + if (returnMode == TSITab) { + int printLen = oe.getPropertyInt("NumSplitsOnePage", 3); + vector< pair > nsp; + for (size_t j = 1; j < 8; j++) + nsp.push_back(make_pair(itos(j), j)); + gdi.addSelection("NumPerPage", 90, 200, ListsCB, "Max antal brickor per sida"); + gdi.addItem("NumPerPage", nsp); + gdi.selectItemByData("NumPerPage", printLen); + + int maxWait = oe.getPropertyInt("SplitPrintMaxWait", 60); + gdi.addInput("MaxWaitTime", itos(maxWait), 8, 0, "Längsta tid i sekunder att vänta med utskrift"); + + enableWideFormat(gdi, wideFormat); + } + } + + + gdi.fillRight(); + gdi.setData("Type", ctype); + gdi.addButton("SavePS", "OK", ListsCB).setDefault().setExtra(returnMode); + gdi.addButton("CancelPS", "Avbryt", ListsCB).setCancel().setExtra(returnMode); + + gdi.refresh(); +} + +void TabList::saveExtraLines(oEvent &oe, const char *dataField, gdioutput &gdi) { + vector< pair > lines; + for (int k = 0; k < 5; k++) { + string row = "row"+itos(k); + string key = "font"+itos(k); + ListBoxInfo lbi; + gdi.getSelectedItem(key, lbi); + string r = gdi.getText(row); + lines.push_back(make_pair(r, lbi.data)); + } + oe.setExtraLines(dataField, lines); +} + +void TabList::customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi) { + gdi.dropLine(2.5); + gdi.addString("", boldText, "Egna textrader"); + + vector< pair > fonts; + vector< pair > lines; + + MetaListPost::getAllFonts(fonts); + oe.getExtraLines(dataField, lines); + + for (int k = 0; k < 5; k++) { + gdi.fillRight(); + gdi.pushX(); + string row = "row"+itos(k); + gdi.addInput(row, "", 24); + string key = "font"+itos(k); + gdi.addSelection(key, 100, 100); + gdi.addItem(key, fonts); + if (lines.size() > size_t(k)) { + gdi.selectItemByData(key.c_str(), lines[k].second); + gdi.setText(row, lines[k].first); + } + else + gdi.selectFirstItem(key); + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2); + } +} + +void TabList::liveResult(gdioutput &gdi, oListInfo &li) { + if (liveResults.empty() || !liveResults.back()) { + liveResults.push_back(0); + LiveResult *lr = new LiveResult(oe); + liveResults.back() = lr; + } + liveResults.back()->showTimer(gdi, li); +} + +EStdListType TabList::getTypeFromResultIndex(int ix) const { + switch(ix) { + case 1: + return EStdResultList; + case 2: + return EStdPatrolResultList; + case 3: + return EStdTeamResultListAll; + case 4: + return EStdTeamResultList; + //case 5: + // return EStdTeamResultListLeg; + case 6: + return EGeneralResultList; + default: + if (ix >= CUSTOM_OFFSET) { + int index = ix - CUSTOM_OFFSET; + const string &uid = oe->getListContainer().getList(index).getUniqueId(); + return oe->getListContainer().getCodeFromUnqiueId(uid); + } + } + return EStdNone; +} + +void TabList::setResultOptionsFromType(gdioutput &gdi, int data) { + bool builtIn = data < CUSTOM_OFFSET; + string info, title; + bool hasResMod = false; + oListInfo li; + EStdListType type = getTypeFromResultIndex(data); + oe->getListType(type, li); + ListBoxInfo lbi; + if (gdi.getSelectedItem("LegNumber", lbi) && int(lbi.data) >= 0) + lastLeg = lbi.data; + + if (builtIn) { + enableFromTo(*oe, gdi, data==1 || data==6, data==1 || data==6); + + if (data==6) { + gdi.enableInput("UseLargeSize"); + } + else { + gdi.disableInput("UseLargeSize"); + gdi.check("UseLargeSize", false); + } + + gdi.setInputStatus("ShowInterResults", builtIn); + gdi.setInputStatus("ShowSplits", builtIn); + + + set clsUnused; + vector< pair > out; + + oe->fillLegNumbers(clsUnused, li.isTeamList(), true, out); + gdi.addItem("LegNumber", out); + gdi.setInputStatus("LegNumber", !out.empty()); + + if (!out.empty() && lastLeg >= 0) + gdi.selectItemByData("LegNumber", lastLeg); + + //oe->fillLegNumbers(gdi, "LegNumber", li.isTeamList(), true); + gdi.setInputStatus("InputNumber", false); + } + else { + + gdi.setInputStatus("UseLargeSize", li.supportLarge); + gdi.setInputStatus("InputNumber", li.supportParameter); + + //gdi.setInputStatus("SplitAnalysis", li.supportSplitAnalysis); + //gdi.setInputStatus("ShowInterResults", li.supportInterResults); + //gdi.setInputStatus("PageBreak", li.supportPageBreak); + //gdi.setInputStatus("ClassLimit", li.supportClassLimit); + + if (li.supportLegs) { + gdi.enableInput("LegNumber"); + //oe->fillLegNumbers(gdi, "LegNumber", li.isTeamList(), true); + set clsUnused; + vector< pair > out; + oe->fillLegNumbers(clsUnused, li.isTeamList(), true, out); + gdi.addItem("LegNumber", out); + if (!out.empty() && lastLeg >= 0) + gdi.selectItemByData("LegNumber", lastLeg); + gdi.setInputStatus("LegNumber", !out.empty()); + } + else { + ListBoxInfo lbi; + if (gdi.getSelectedItem("LegNumber", lbi) && int(lbi.data) >= 0) + lastLeg = lbi.data; + gdi.disableInput("LegNumber"); + gdi.clearList("LegNumber"); + } + + enableFromTo(*oe, gdi, li.supportFrom, li.supportTo); + } + + if (!builtIn) { + int index = data - CUSTOM_OFFSET; + const MetaList &ml = oe->getListContainer().getList(index); + info = ml.getListInfo(*oe); + title = ml.getListName(); + hasResMod = !ml.getResultModule().empty(); + } + + if (info.empty() && gdi.getText("ListInfo", true).empty()) { + // Do nothing + } + else { + gdi.restore("ListInfo", false); + gdi.setCX(infoCX); + gdi.setCY(infoCY); + + if (!info.empty()) { + gdi.setRestorePoint("ListInfo"); + gdi.fillDown(); + gdi.addString("", fontMediumPlus, title); + gdi.dropLine(0.3); + gdi.addString("ListInfo", 10, info); + gdi.dropLine(0.7); + } + //createListButtons(gdi); + gdi.refresh(); + } + oEvent::ClassFilter ct = li.isTeamList() ? oEvent::filterOnlyMulti : oEvent::filterNone; + set curSel; + gdi.getSelection("ListSelection", curSel); + + if (lastFilledResultClassType != ct) { + lastFilledResultClassType = ct; + lastResultClassSelection.insert(curSel.begin(), curSel.end()); + oe->fillClasses(gdi, "ListSelection", oEvent::extraNone, ct); + gdi.setSelection("ListSelection", lastResultClassSelection); + } + + gdi.setInputStatus("Generate", data >= 0 && !lastResultClassSelection.empty()); +} + +void TabList::clearCompetitionData() { + SelectedList = ""; + lastResultClassSelection.clear(); + + ownWindow = false; + hideButtons = false; + currentListType=EStdNone; + noReEvaluate = false; + + infoCX = 0; + infoCY = 0; + + lastLimitPer = -1; + lastInterResult = false; + lastSplitState = false; + lastLargeSize = false; + + lastSelectedResultList = -1; + lastLeg = 0; + lastFilledResultClassType = -1; + + delete listEditor; + delete methodEditor; + listEditor = 0; + methodEditor = 0; +} diff --git a/code/TabList.h b/code/TabList.h new file mode 100644 index 0000000..a17795c --- /dev/null +++ b/code/TabList.h @@ -0,0 +1,115 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "tabbase.h" +#include "oListInfo.h" + +class LiveResult; +class ListEditor; +class MethodEditor; + +class TabList : + public TabBase +{ +protected: + EStdListType currentListType; + oListInfo currentList; + string SelectedList; + string lastInputNumber; + int lastLimitPer; + bool lastInterResult; + bool lastSplitState; + bool lastLargeSize; + + + EStdListType getTypeFromResultIndex(int ix) const; + + int infoCX; + int infoCY; + + static void createListButtons(gdioutput &gdi); + + void generateList(gdioutput &gdi); + void selectGeneralList(gdioutput &gdi, EStdListType type); + + int offsetY; + int offsetX; + set lastClassSelection; + vector liveResults; + + int lastSelectedResultList; + set lastResultClassSelection; + int lastLeg; + int lastFilledResultClassType; + + void setResultOptionsFromType(gdioutput &gdi, int data); + + + bool hideButtons; + bool ownWindow; + ListEditor *listEditor; + MethodEditor *methodEditor; + + bool noReEvaluate; + + int baseButtons(gdioutput &gdi, int extraButtons); + +private: + // Not supported, copy works not. + TabList(const TabList &); + const TabList &operator = (const TabList &); + +public: + bool loadPage(gdioutput &gdi); + bool loadPage(gdioutput &gdi, const string &command); + + // Clear up competition specific settings + void clearCompetitionData(); + static void makeClassSelection(gdioutput &gdi); + static void makeFromTo(gdioutput &gdi); + static void enableFromTo(oEvent &oe, gdioutput &gdi, bool from, bool to); + void liveResult(gdioutput &gdi, oListInfo ¤tList); + + int listCB(gdioutput &gdi, int type, void *data); + void loadGeneralList(gdioutput &gdi); + void rebuildList(gdioutput &gdi); + void settingsResultList(gdioutput &gdi); + + enum PrintSettingsSelection { + Splits = 0, + StartInfo = 1, + }; + + static void splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter, TabType returnMode, PrintSettingsSelection type); + static void customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi); + static void saveExtraLines(oEvent &oe, const char *dataField, gdioutput &gdi); + static void enableWideFormat(gdioutput &gdi, bool wide); + + ListEditor *getListeditor() const {return listEditor;} + + const char * getTypeStr() const {return "TListTab";} + TabType getType() const {return TListTab;} + + TabList(oEvent *oe); + ~TabList(void); + friend int ListsEventCB(gdioutput *gdi, int type, void *data); +}; diff --git a/code/TabMulti.cpp b/code/TabMulti.cpp new file mode 100644 index 0000000..ba117b1 --- /dev/null +++ b/code/TabMulti.cpp @@ -0,0 +1,50 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "csvparser.h" +#include "SportIdent.h" + +#include "TabMulti.h" + +TabMulti::TabMulti(oEvent *poe):TabBase(poe) +{ +} + +TabMulti::~TabMulti(void) +{ +} + +bool TabMulti::loadPage(gdioutput &gdi) +{ + return true; +} + diff --git a/code/TabMulti.h b/code/TabMulti.h new file mode 100644 index 0000000..5041fd8 --- /dev/null +++ b/code/TabMulti.h @@ -0,0 +1,32 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "tabbase.h" + +class TabMulti : + public TabBase +{ +public: + bool loadPage(gdioutput &gdi); + TabMulti(oEvent *oe); + ~TabMulti(void); +}; diff --git a/code/TabRunner.cpp b/code/TabRunner.cpp new file mode 100644 index 0000000..d7f83ac --- /dev/null +++ b/code/TabRunner.cpp @@ -0,0 +1,2744 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "gdiconstants.h" + +#include "csvparser.h" +#include "SportIdent.h" +#include "meos_util.h" +#include "TabRunner.h" +#include "TabTeam.h" +#include "TabList.h" +#include "Table.h" +#include +#include "oListInfo.h" +#include "TabSI.h" +#include "intkeymapimpl.hpp" +#include "meosexception.h" +#include "MeOSFeatures.h" + +int SportIdentCB(gdioutput *gdi, int type, void *data); + +TabRunner::TabRunner(oEvent *poe):TabBase(poe) +{ + clearCompetitionData(); +} + +TabRunner::~TabRunner(void) +{ +} + +void disablePunchCourse(gdioutput &gdi); + +bool TabRunner::loadPage(gdioutput &gdi, int runnerId) +{ + oe->checkDB(); + assert(this); + + if (currentMode == 5) { + this->runnerId = runnerId; + loadPage(gdi); + } + else { + currentMode = 0; + loadPage(gdi); + pRunner r=oe->getRunner(runnerId, 0); + if (r){ + selectRunner(gdi, r); + return true; + } + } + return false; +} + +void TabRunner::enableControlButtons(gdioutput &gdi, bool enable, bool vacant) +{ + if (enable) { + gdi.enableInput("Remove"); + gdi.enableInput("Save"); + gdi.enableInput("Undo"); + if (vacant) { + gdi.disableInput("Move", true); + gdi.disableInput("NoStart", true); + } + else { + gdi.enableInput("Move", true); + gdi.enableInput("NoStart", true); + } + } + else { + gdi.disableInput("Remove"); + gdi.disableInput("Save"); + gdi.disableInput("Undo"); + gdi.disableInput("Move", true); + gdi.disableInput("NoStart", true); + } +} + +void TabRunner::selectRunner(gdioutput &gdi, pRunner r) { + if (!r) { + runnerId=0; + gdi.setText("Name", ""); + gdi.setText("Bib", ""); + gdi.selectItemByData("RCourse", 0); + updateNumShort(gdi, 0, 0); + //Don't clear club and class + + + gdi.setText("CardNo", ""); + gdi.enableInput("Start"); + gdi.setText("Start", "-"); + gdi.enableInput("Finish"); + gdi.setText("Finish", "-"); + + gdi.setText("Time", "-"); + gdi.setText("Points", ""); + gdi.selectItemByData("Status", 0); + + gdi.clearList("Punches"); + gdi.clearList("Course"); + + gdi.selectItemByData("Runners", -1); + gdi.setInputFocus("Name", true); + if (gdi.hasField("MultiR")) { + gdi.clearList("MultiR"); + gdi.disableInput("MultiR"); + } + gdi.enableEditControls(false); + enableControlButtons(gdi, false, false); + disablePunchCourse(gdi); + + if (gdi.hasField("EditTeam")) + gdi.disableInput("EditTeam"); + gdi.setText("RunnerInfo", "", true); + + gdi.setText("TimeAdjust", "-"); + gdi.setText("PointAdjust", ""); + + if (gdi.hasField("StatusIn")) { + gdi.selectFirstItem("StatusIn"); + gdi.setText("PlaceIn", ""); + gdi.setText("TimeIn", "-"); + if (gdi.hasField("PointIn")) + gdi.setText("PointIn", ""); + } + + return; + } + + gdi.enableEditControls(true); + disablePunchCourse(gdi); + + pRunner parent=r->getMultiRunner(0); + + r->synchronizeAll(); + //r->apply(false); + vector mp; + r->evaluateCard(true, mp, 0, false); + /* + if (parent!=r) { + parent->synchronize(); + parent->apply(false); + }*/ + + gdi.selectItemByData("Runners", parent->getId()); + + runnerId=r->getId(); + + gdi.setText("Name", r->getNameRaw()); + string bib = r->getBib(); + + if (gdi.hasField("Bib")) { + gdi.setText("Bib", bib); + bool controlBib = r->getTeam() == 0 || (r->getClassRef() && r->getClassRef()->getBibMode() == BibFree); + gdi.setInputStatus("Bib", controlBib); + } + + gdi.setText("Club", r->getClub()); + + oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); + gdi.addItem("RClass", lang.tl("Ingen klass"), 0); + gdi.selectItemByData("RClass", r->getClassId()); + + if (gdi.hasField("EditTeam")) { + gdi.setInputStatus("EditTeam", r->getTeam()!=0); + + if (r->getTeam()) { + gdi.setText("Team", r->getTeam()->getName()); + } + else + gdi.setText("Team", ""); + } + + gdi.setText("TimeAdjust", getTimeMS(r->getTimeAdjustment())); + gdi.setText("PointAdjust", -r->getPointAdjustment()); + +#ifdef _DEBUG + vector delta; + vector place; + vector after; + vector placeAcc; + vector afterAcc; + + r->getSplitAnalysis(delta); + r->getLegTimeAfter(after); + r->getLegPlaces(place); + + r->getLegTimeAfterAcc(afterAcc); + r->getLegPlacesAcc(placeAcc); + + string out; + for (size_t k = 0; k0) + out+= " +" + getTimeMS(after[k]); + + if (k0) + out+= " (+" + getTimeMS(afterAcc[k]) + ")"; + + if (delta[k]>0) + out+= " B: " + getTimeMS(delta[k]); + + out += " | "; + + } + gdi.restore("fantom", false); + gdi.setRestorePoint("fantom"); + gdi.addStringUT(0, out); + gdi.refresh(); +#endif + + if (gdi.hasField("MultiR")) { + int numMulti=parent->getNumMulti(); + if (numMulti==0) { + gdi.clearList("MultiR"); + gdi.disableInput("MultiR"); + lastRace=0; + } + else { + char bf[32]; + gdi.clearList("MultiR"); + gdi.enableInput("MultiR"); + + for (int k=0;kgetRaceNo()); + } + } + oe->fillCourses(gdi, "RCourse", true); + string crsName = r->getCourse(false) ? r->getCourse(false)->getName() + " " : ""; + gdi.addItem("RCourse", crsName + lang.tl("[Klassens bana]"), 0); + gdi.selectItemByData("RCourse", r->getCourseId()); + updateNumShort(gdi, r->getCourse(false), r); + + int cno = parent->getCardNo(); + gdi.setText("CardNo", cno>0 ? itos(cno) : ""); + + warnDuplicateCard(gdi, cno, r); + + gdi.check("RentCard", parent->getDI().getInt("CardFee") != 0); + bool hasFee = gdi.hasField("Fee"); + + if (hasFee) + gdi.setText("Fee", oe->formatCurrency(parent->getDI().getInt("Fee"))); + + if (parent != r) { + gdi.disableInput("CardNo"); + gdi.disableInput("RentCard"); + if (hasFee) + gdi.disableInput("Fee"); + gdi.disableInput("RClass"); + } + else { + gdi.enableInput("CardNo"); + gdi.enableInput("RentCard"); + if (hasFee) + gdi.enableInput("Fee"); + gdi.enableInput("RClass"); + } + + enableControlButtons(gdi, true, r->isVacant()); + + gdi.setText("Start", r->getStartTimeS()); + gdi.setInputStatus("Start", canSetStart(r)); + + gdi.setText("Finish", r->getFinishTimeS()); + gdi.setInputStatus("Finish", canSetFinish(r)); + + gdi.setText("Time", r->getRunningTimeS()); + gdi.setText("Points", itos(r->getRogainingPoints(false))); + + gdi.selectItemByData("Status", r->getStatus()); + gdi.setText("RunnerInfo", lang.tl(r->getProblemDescription()), true); + + if (gdi.hasField("StatusIn")) { + gdi.selectItemByData("StatusIn", r->getInputStatus()); + int ip = r->getInputPlace(); + if (ip > 0) + gdi.setText("PlaceIn", ip); + else + gdi.setText("PlaceIn", MakeDash("-")); + + gdi.setText("TimeIn", r->getInputTimeS()); + if (gdi.hasField("PointIn")) + gdi.setText("PointIn", r->getInputPoints()); + } + + pCard pc=r->getCard(); + + pCourse pcourse=r->getCourse(true); + + if (pc) { + gdi.setTabStops("Punches", 70); + pc->fillPunches(gdi, "Punches", pcourse); + } + else gdi.clearList("Punches"); + + if (pcourse) { + pcourse->synchronize(); + gdi.setTabStops("Course", 50); + pcourse->fillCourse(gdi, "Course"); + autoGrowCourse(gdi); + gdi.enableInput("AddAllC"); + } + else { + gdi.clearList("Course"); + gdi.disableInput("AddAllC"); + } +} + +int RunnerCB(gdioutput *gdi, int type, void *data) +{ + TabRunner &tc = dynamic_cast(*gdi->getTabs().get(TRunnerTab)); + + return tc.runnerCB(*gdi, type, data); +} + +int PunchesCB(gdioutput *gdi, int type, void *data) +{ + TabRunner &tc = dynamic_cast(*gdi->getTabs().get(TRunnerTab)); + return tc.punchesCB(*gdi, type, data); +} + +int VacancyCB(gdioutput *gdi, int type, void *data) +{ + TabRunner &tc = dynamic_cast(*gdi->getTabs().get(TRunnerTab)); + + return tc.vacancyCB(*gdi, type, data); +} + +int runnerSearchCB(gdioutput *gdi, int type, void *data) +{ + TabRunner &tc = dynamic_cast(*gdi->getTabs().get(TRunnerTab)); + + return tc.searchCB(*gdi, type, data); +} + +int TabRunner::searchCB(gdioutput &gdi, int type, void *data) { + static DWORD editTick = 0; + string expr; + bool showNow = false; + bool filterMore = false; + + if (type == GUI_INPUTCHANGE) { + inputId++; + InputInfo &ii = *(InputInfo *)(data); + expr = trim(ii.text); + filterMore = expr.length() > lastSearchExpr.length() && + expr.substr(0, lastSearchExpr.length()) == lastSearchExpr; + editTick = GetTickCount(); + if (expr != lastSearchExpr) { + int nr = oe->getNumRunners(); + if (timeToFill < 50 || (filterMore && (timeToFill * lastFilter.size())/nr < 50)) + showNow = true; + else {// Delay filter + gdi.addTimeoutMilli(500, "Search: " + expr, runnerSearchCB).setExtra((void *)inputId); + } + } + } + else if (type == GUI_TIMER) { + + TimerInfo &ti = *(TimerInfo *)(data); + + if (inputId != int(ti.getExtra())) + return 0; + + expr = ti.id.substr(8); + filterMore = expr.length() > lastSearchExpr.length() && + expr.substr(0, lastSearchExpr.length()) == lastSearchExpr; + showNow = true; + } + else if (type == GUI_EVENT) { + EventInfo &ev = *(EventInfo *)(data); + if (ev.getKeyCommand() == KC_FIND) { + gdi.setInputFocus("SearchText", true); + } + else if (ev.getKeyCommand() == KC_FINDBACK) { + gdi.setInputFocus("SearchText", false); + } + } + else if (type == GUI_FOCUS) { + InputInfo &ii = *(InputInfo *)(data); + + if (ii.text == getSearchString()) { + ((InputInfo *)gdi.setText("SearchText", ""))->setFgColor(colorDefault); + } + } + + if (showNow) { + stdext::hash_set filter; + + if (type == GUI_TIMER) + gdi.setWaitCursor(true); + + if (filterMore) { + + oe->findRunner(expr, 0, lastFilter, filter); + lastSearchExpr = expr; + // Filter more + if (filter.empty()) { + vector< pair > runners; + runners.push_back(make_pair(lang.tl("Ingen matchar 'X'#" + expr), -1)); + gdi.addItem("Runners", runners); + } + else + gdi.filterOnData("Runners", filter); + + filter.swap(lastFilter); + } + else { + lastFilter.clear(); + oe->findRunner(expr, 0, lastFilter, filter); + lastSearchExpr = expr; + + bool formMode = currentMode == 0; + + vector< pair > runners; + oe->fillRunners(runners, !formMode, formMode ? 0 : oEvent::RunnerFilterShowAll, filter); + + if (filter.size() == runners.size()){ + } + else if (filter.empty()) { + runners.clear(); + runners.push_back(make_pair(lang.tl("Ingen matchar 'X'#" + expr), -1)); + } + + filter.swap(lastFilter); + gdi.addItem("Runners", runners); + } + + if (lastFilter.size() == 1) { + pRunner r = oe->getRunner(*lastFilter.begin(), 0); + selectRunner(gdi, r); + } + if (type == GUI_TIMER) + gdi.setWaitCursor(false); + } + + return 0; +} + +pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) { + oe->synchronizeList(oLCardId, true, true); + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.storedInfo.clear(); + + bool create=(runnerId==0); + + if (create) + return 0; + + string name=gdi.getText("Name"); + + if (name.empty()) + throw std::exception("Alla deltagare måste ha ett namn."); + + int cardNo = gdi.getTextNo("CardNo"); + + ListBoxInfo lbi; + gdi.getSelectedItem("Club", lbi); + + int clubId = 0; + if (!lbi.text.empty()) { + pClub pc = oe->getClub(lbi.text); + if (!pc) + pc=oe->addClub(lbi.text); + pc->synchronize(); + + clubId = pc->getId(); + } + + gdi.getSelectedItem("RClass", lbi); + + int classId = 0; + if (signed(lbi.data)<=0 && oe->getNumClasses() == 0) { + if (gdi.ask("Vill du skapa en ny klass?")) { + pClass pc=oe->addClass(oe->getAutoClassName()); + pc->synchronize(); + classId = pc->getId(); + } + } + else + classId = lbi.data; + + int year = 0; + pRunner r; + bool cardNoChanged = false; + if (runnerId==0) { + cardNoChanged = true; + r = oe->addRunner(name, clubId, classId, cardNo, year, true); + r->setCardNo(0, false, false); // Reset to get auto card match + } + else { + r = oe->getRunner(runnerId, 0); + if (r==0) + throw meosException("Internal error runner index"); + + cardNoChanged = r->getCardNo() != cardNo; + if (r->getName() != name || (r->getClubId() != clubId && clubId != 0)) + r->updateFromDB(name, clubId, classId, cardNo, r->getBirthYear()); + } + + if (cardNoChanged && cardNo>0) { + pRunner warnCardDupl = warnDuplicateCard(cardNo, r); + if (warnCardDupl) { + gdi.alert("Varning: Brickan X används redan av Y.#" + itos(cardNo) + "#" + warnCardDupl->getCompleteIdentification()); + } + } + + if (r) { + runnerId=r->getId(); + RunnerStatus originalStatus = r->getStatus(); + r->setName(name, true); + + if (gdi.hasField("Bib")) { + const string &bib = gdi.getText("Bib"); + char pat[32]; + int num = oClass::extractBibPattern(bib, pat); + r->setBib(bib, num, num>0, false); + } + + bool noSetStatus = false; + if (cardNo > 0 && r->getCard() && + r->getCard()->getCardNo() != cardNo && r->getCardNo() != cardNo) { + if (gdi.ask("Vill du koppla isär X från inläst bricka Y?#" + r->getName() + + "#" + r->getCard()->getCardNoString())) { + r->setStatus(StatusUnknown, true, false, false); + r->setCard(0); + r->setFinishTime(0); + r->synchronize(true); + gdi.setText("Finish", ""); + noSetStatus = true; + } + } + + if (cardNo > 0 && cardNo != r->getCardNo() && oe->hasNextStage()) { + if (gdi.ask("Vill du använda den nya brickan till alla etapper?")) { + r->setTransferCardNoNextStage(true); + } + } + + r->setCardNo(cardNo, true); + if (gdi.isChecked("RentCard")) + r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee")); + else + r->getDI().setInt("CardFee", 0); + + if (gdi.hasField("Fee")) + r->getDI().setInt("Fee", oe->interpretCurrency(gdi.getText("Fee"))); + + r->setStartTimeS(gdi.getText("Start")); + r->setFinishTimeS(gdi.getText("Finish")); + + if (gdi.hasField("NumShort")) { + r->setNumShortening(gdi.getSelectedItem("NumShort").first); + } + + if (gdi.hasField("TimeAdjust")) { + int t = convertAbsoluteTimeMS(gdi.getText("TimeAdjust")); + if (t != NOTIME) + r->setTimeAdjustment(t); + } + if (gdi.hasField("PointAdjust")) { + r->setPointAdjustment(-gdi.getTextNo("PointAdjust")); + } + + r->setClubId(clubId); + + if (!willExit) { + oe->fillClubs(gdi, "Club"); + gdi.setText("Club", r->getClub()); + } + + pClass pNewCls = oe->getClass(classId); + if (pNewCls && pNewCls->getClassType() == oClassRelay) { + if (!r->getTeam()) { + gdi.alert("För att delta i en lagklass måste deltagaren ingå i ett lag."); + classId = 0; + } + else if (r->getTeam()->getClassId() != classId && r->getClassId() != classId) { + gdi.alert("Deltagarens klass styrs av laget."); + classId = r->getTeam()->getClassId(); + } + } + + bool readStatusIn = true; + if (r->getClassId() != classId && r->getInputStatus() != StatusNotCompetiting && r->hasInputData()) { + if (gdi.ask("Vill du sätta resultatet från tidigare etapper till ?")) { + r->resetInputData(); + readStatusIn = false; + } + } + + r->setClassId(classId, true); + + r->setCourseId(gdi.getSelectedItem("RCourse").first); + + RunnerStatus sIn = (RunnerStatus)gdi.getSelectedItem("Status").first; + bool checkStatus = sIn != originalStatus; + if (r->getStatus() != sIn && !noSetStatus) { + r->setStatus(sIn, true, false); + } + r->addClassDefaultFee(false); + vector mp; + r->evaluateCard(true, mp, 0, true); + + if (r->getClassId() != classId) { + gdi.alert("Deltagarens klass styrs av laget."); + } + + if (checkStatus && sIn != r->getStatus()) + gdi.alert("Status matchar inte data i löparbrickan."); + + if (gdi.hasField("StatusIn") && readStatusIn) { + r->setInputStatus(RunnerStatus(gdi.getSelectedItem("StatusIn").first)); + r->setInputPlace(gdi.getTextNo("PlaceIn")); + r->setInputTime(gdi.getText("TimeIn")); + if (gdi.hasField("PointIn")) + r->setInputPoints(gdi.getTextNo("PointIn")); + } + + r->synchronizeAll(); + + if (r->getClassRef() && r->getClassRef()->hasClassGlobalDependance()) { + set cls; + cls.insert(r->getClassId()); + oe->reEvaluateAll(cls, false); + } + } + else + runnerId=0; + + if (!willExit) { + fillRunnerList(gdi); + + if (create) + selectRunner(gdi, 0); + else + selectRunner(gdi, r); + } + return r; +} + +int TabRunner::runnerCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON){ + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="Search") { + ListBoxInfo lbi; + gdi.getSelectedItem("Runners", lbi); + string searchText = gdi.getText("SearchText"); + bool formMode = currentMode == 0; + stdext::hash_set foo; + fillRunnerList(gdi); + //oe->fillRunners(gdi, "Runners", !formMode, formMode ? 0 : oEvent::RunnerFilterShowAll); + pRunner r=oe->findRunner(searchText, lbi.data, foo, foo); + + if (r) { + if (formMode) + selectRunner(gdi, r); + gdi.selectItemByData("Runners", r->getId()); + } + else + gdi.alert("Löparen hittades inte"); + } + else if (bi.id == "ShowAll") { + fillRunnerList(gdi); + } + else if (bi.id=="Pair") { + ListBoxInfo lbi; + pRunner r=0; + if (gdi.getSelectedItem("Runners", lbi) && + (r=oe->getRunner(lbi.data, 0))!=0) { + int cid = bi.getExtraInt(); + pCard card = oe->getCard(cid); + if (!card) + throw meosException("Internal error"); + card->synchronize(); + if (card->isRemoved()) + throw meosException("Card was removed"); + + int newCardId=card->getId(); + + int oldCardId=r->setCard(newCardId); + gdi.restore("CardTable"); + Table &t=gdi.getTable(); + t.reloadRow(newCardId); + if (oldCardId) + t.reloadRow(oldCardId); + gdi.enableTables(); + gdi.refresh(); + } + } + else if (bi.id == "Window") { + gdioutput *gdi_new = createExtraWindow(uniqueTag("kiosk"), MakeDash("MeOS - " + oe->getName()), gdi.getWidth() + 64 + gdi.scaleLength(120)); + if (gdi_new) { + TabRunner &tr = dynamic_cast(*gdi_new->getTabs().get(TRunnerTab)); + tr.currentMode = currentMode; + tr.runnerId = runnerId; + tr.ownWindow = true; + tr.loadPage(*gdi_new); + } + } + else if (bi.id == "Kiosk") { + if (gdi.ask("ask:kiosk")) { + oe->setReadOnly(); + oe->updateTabs(); + loadPage(gdi); + } + } + else if (bi.id == "ListenReadout") { + listenToPunches = gdi.isChecked(bi.id); + } + else if (bi.id=="Unpair") { + ListBoxInfo lbi; + int cid = bi.getExtraInt(); + pCard c = oe->getCard(cid); + + if (c->getOwner()) + c->getOwner()->setCard(0); + + gdi.restore("CardTable"); + Table &t=gdi.getTable(); + t.reloadRow(c->getId()); + gdi.enableTables(); + gdi.refresh(); + } + else if (bi.id=="TableMode") { + gdi.canClear(); + currentMode = 1; + loadPage(gdi); + } + else if (bi.id=="FormMode") { + if (currentMode != 0) { + currentMode = 0; + gdi.canClear(); + gdi.enableTables(); + loadPage(gdi); + } + } + else if (bi.id=="Vacancy") { + if (currentMode != 4) { + gdi.canClear(); + showVacancyList(gdi, "add"); + } + } + else if (bi.id == "ReportMode") { + if (currentMode != 5) { + gdi.canClear(); + showRunnerReport(gdi); + } + } + else if (bi.id=="Cards") { + if (currentMode != 3) { + gdi.canClear(); + showCardsList(gdi); + } + } + else if (bi.id=="InForest") { + if (currentMode != 2) { + gdi.canClear(); + showInForestList(gdi); + } + } + else if (bi.id=="CancelInForest") { + clearInForestData(); + loadPage(gdi); + } + else if (bi.id=="CancelReturn") { + loadPage(gdi); + } + else if (bi.id=="SetDNS") { + for (size_t k=0; kgetStatus()==StatusUnknown) + unknown[k]->setStatus(StatusDNS, true, false); + + //Reevaluate and synchronize all + oe->reEvaluateAll(set(), true); + clearInForestData(); + showInForestList(gdi); + } + else if (bi.id=="SetUnknown") { + for (size_t k=0; kgetStatus()==StatusDNS) + known_dns[k]->setStatus(StatusUnknown, true, false); + + //Reevaluate and synchronize all + oe->reEvaluateAll(set(), true); + clearInForestData(); + showInForestList(gdi); + } + else if (bi.id == "RemoveVacant") { + if (gdi.ask("Vill du radera alla vakanser från tävlingen?")) { + oe->removeVacanies(0); + gdi.disableInput(bi.id.c_str()); + } + } + else if (bi.id=="Cancel") { + gdi.restore("CardTable"); + gdi.enableTables(); + gdi.refresh(); + } + else if (bi.id=="SplitPrint") { + if (!runnerId) + return 0; + pRunner r=oe->getRunner(runnerId, 0); + if (!r) return 0; + + gdioutput gdiprint(2.0, gdi.getEncoding(), gdi.getHWND(), splitPrinter); + if (bi.getExtraInt() == 0) + r->printSplits(gdiprint); + else + r->printStartInfo(gdiprint); + gdiprint.print(oe, 0, false, true); + gdiprint.fetchPrinterSettings(splitPrinter); + } + else if (bi.id == "PrintSettings") { + if (runnerId) + save(gdi, runnerId, true); + TabList::splitPrintSettings(*oe, gdi, false, TRunnerTab, (TabList::PrintSettingsSelection)bi.getExtraInt()); + } + else if (bi.id == "EditTeam") { + pRunner r = oe->getRunner(runnerId, 0); + if (r && r->getTeam()) { + save(gdi, runnerId, true); + + TabTeam *tt = (TabTeam *)gdi.getTabs().get(TTeamTab); + tt->loadPage(gdi, r->getTeam()->getId()); + } + } + else if (bi.id=="Save") { + save(gdi, runnerId, false); + return true; + } + else if (bi.id=="Undo") { + selectRunner(gdi, oe->getRunner(runnerId, 0)); + return true; + } + else if (bi.id=="Add") { + if (runnerId>0) { + string name = gdi.getText("Name"); + pRunner r = oe->getRunner(runnerId, 0); + if (!name.empty() && r && r->getName() != name && r->getNameRaw() != name) { + if (gdi.ask("Vill du lägga till deltagaren 'X'?#" + name)) { + r = oe->addRunner(name, 0, 0, 0,0, false); + runnerId = r->getId(); + } + save(gdi, runnerId, false); + return true; + } + + save(gdi, runnerId, true); + } + ListBoxInfo lbi; + gdi.getSelectedItem("RClass", lbi); + + pRunner r = oe->addRunner(oe->getAutoRunnerName(), 0,0,0,0, false); + if (signed(lbi.data)>0) + r->setClassId(lbi.data, true); + else + r->setClassId(oe->getFirstClassId(false), true); + + fillRunnerList(gdi); + oe->fillClubs(gdi, "Club"); + selectRunner(gdi, r); + gdi.setInputFocus("Name", true); + } + else if (bi.id=="Remove") { + if (!runnerId) + return 0; + + if (gdi.ask("Vill du verkligen ta bort löparen?")) { + if (oe->isRunnerUsed(runnerId)) + gdi.alert("Löparen ingår i ett lag och kan inte tas bort."); + else { + pRunner r = oe->getRunner(runnerId, 0); + if (r) + r->remove(); + fillRunnerList(gdi); + //oe->fillRunners(gdi, "Runners"); + selectRunner(gdi, 0); + } + } + } + else if (bi.id=="NoStart") { + if (!runnerId) + return 0; + pRunner r = oe->getRunner(runnerId, 0); + r = r->getMultiRunner(0); + + if (r && gdi.ask("Bekräfta att deltagaren har lämnat återbud.")) { + if (r->getStartTime()>0) { + pRunner newRunner = oe->addRunnerVacant(r->getClassId()); + newRunner->cloneStartTime(r); + newRunner->setStartNo(r->getStartNo(), false); + if (r->getCourseId()) + newRunner->setCourseId(r->getCourseId()); + newRunner->synchronizeAll(); + } + + for (int k=0;kgetNumMulti()+1; k++) { + pRunner rr = r->getMultiRunner(k); + if (rr) { + rr->setStartTime(0, true, false); + rr->setStartNo(0, false); + rr->setStatus(StatusDNS, true, false); + rr->setCardNo(0, false); + } + } + r->synchronizeAll(); + selectRunner(gdi, r); + } + } + else if (bi.id == "Move") { + pRunner r = oe->getRunner(runnerId, 0); + + if (!runnerId || !r) + return 0; + gdi.clearPage(true); + + gdi.pushX(); + gdi.fillRight(); + gdi.addString("", boldLarge, "Klassbyte"); + gdi.addStringUT(boldLarge, r->getName()).setColor(colorDarkRed); + + //gdi.fillRight(); + //gdi.addString("", 0, "Deltagare:"); + gdi.fillDown(); + gdi.dropLine(2); + gdi.popX(); + gdi.addString("", 0, "Välj en vakant plats nedan."); + + oe->generateVacancyList(gdi, RunnerCB); + + gdi.dropLine(); + gdi.addButton("CancelReturn", "Avbryt", RunnerCB); + } + else if (bi.id == "RemoveC") { + ListBoxInfo lbi; + gdi.getSelectedItem("Punches", lbi); + + DWORD rid=runnerId; + if (!rid) + return 0; + + pRunner r=oe->getRunner(rid, 0); + + if (!r) return 0; + + pCard card=r->getCard(); + + if (!card) return 0; + + card->deletePunch(card->getPunchByIndex(lbi.data)); + card->synchronize(); + //Update runner + vector mp; + r->evaluateCard(true, mp, 0, true); + + card->fillPunches(gdi, "Punches", r->getCourse(true)); + + gdi.setText("Time", r->getRunningTimeS()); + gdi.selectItemByData("Status", r->getStatus()); + } + else if (bi.id=="Check") { + } + } + else if (type==GUI_INPUT) { + InputInfo ii=*(InputInfo *)data; + + if (ii.id=="CardNo") { + int cardNo = gdi.getTextNo("CardNo"); + if (runnerId) { + pRunner r = oe->getRunner(runnerId, 0); + if (r) { + warnDuplicateCard(gdi, cardNo, r); + } + } + } + } + else if (type==GUI_LISTBOX) { + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Runners") { + if (gdi.isInputChanged("")) { + pRunner r = oe->getRunner(runnerId, 0); + bool newName = r && r->getName() != gdi.getText("Name"); + + save(gdi, runnerId, true); + + if (newName) + fillRunnerList(gdi); + } + + if (bi.data == -1) { + fillRunnerList(gdi); + return 0; + } + + pRunner r=oe->getRunner(bi.data, 0); + + if (r==0) + throw meosException("Internal error runner index"); + + if (lastRace<=r->getNumMulti()) + r=r->getMultiRunner(lastRace); + + oe->fillClubs(gdi, "Club"); + selectRunner(gdi, r); + } + else if (bi.id=="ReportRunner") { + if (bi.data == -1) { + fillRunnerList(gdi); + return 0; + } + runnerId = bi.data; + //loadPage(gdi); + PostMessage(gdi.getTarget(), WM_USER + 2, TRunnerTab, 0); + } + else if (bi.id=="RClass") { + gdi.selectItemByData("RCourse", 0); + pCourse crsToUse = 0; + + if (bi.data==0) { + gdi.clearList("Course"); + } + else { + pClass Class=oe->getClass(bi.data); + + if (Class) { + crsToUse = Class->getCourse(); + + pRunner rTmp; + if (crsToUse == 0 && (rTmp = oe->getRunner(runnerId, 0)) != 0) { + crsToUse = Class->getCourse(rTmp->getLegNumber(), rTmp->getStartNo()); + } + } + + string crsName; + if (crsToUse) { + crsToUse->fillCourse(gdi, "Course"); + autoGrowCourse(gdi); + crsName = crsToUse->getName() + " "; + } + else { + gdi.clearList("Course"); + } + + ListBoxInfo rcrs; + gdi.getSelectedItem("RCourse", rcrs); + oe->fillCourses(gdi, "RCourse", true); + gdi.addItem("RCourse", crsName + lang.tl("[Klassens bana]"), 0); + gdi.selectItemByData("RCourse", rcrs.data); + } + + updateNumShort(gdi, crsToUse, oe->getRunner(runnerId, 0)); + } + else if (bi.id=="RCourse") { + pCourse crsToUse = 0; + pRunner r=oe->getRunner(runnerId, 0); + + if (bi.data==0) { + gdi.clearList("Course"); + if (r) { //Fix for multi classes, course depends on runner. + ListBoxInfo lbi; + gdi.getSelectedItem("RClass", lbi); + if (signed(lbi.data)>0) { + r->setClassId(lbi.data, true); + r = oe->getRunner(runnerId, 0); + if (r) { + r->synchronize(true); + crsToUse = r->getCourse(true); + } + } + } + if (!r) { + pClass Class=oe->getClass(gdi.getSelectedItem("RClass").first); + if (Class) + crsToUse = Class->getCourse(); + } + } + else { + crsToUse=oe->getCourse(bi.data); + } + if (crsToUse) { + crsToUse->fillCourse(gdi, "Course"); + autoGrowCourse(gdi); + updateNumShort(gdi, crsToUse, r); + } + } + else if (bi.id=="MultiR") { + pRunner r=oe->getRunner(runnerId, 0); + lastRace=bi.data; + if (r) + selectRunner(gdi, r->getMultiRunner(bi.data)); + } + } + else if (type==GUI_EVENT) { + EventInfo ei=*(EventInfo *)data; + + if (ei.id=="LoadRunner") { + pRunner r=oe->getRunner(ei.getData(), 0); + if (r) { + selectRunner(gdi, r); + gdi.selectItemByData("Runners", r->getId()); + } + } + else if (ei.id=="CellAction") { + //oBase *b=static_cast(ei.getExtra()); + oBase *b = oe->getCard(ei.getExtraInt()); + + cellAction(gdi, ei.getData(), b); + } + else if ((ei.id == "DataUpdate") && listenToPunches && currentMode == 5) { + if (ei.getData() > 0) { + runnerId = ei.getData(); + } + loadPage(gdi); + } + else if ((ei.id == "ReadCard") && + (listenToPunches || oe->isReadOnly()) && currentMode == 5) { + if (ei.getData() > 0) { + vector rs; + oe->getRunnersByCard(ei.getData(), rs); + if (!rs.empty()) { + runnersToReport.resize(rs.size()); + for (size_t k = 0; kgetId(), false); + } + runnerId = 0; + } + loadPage(gdi); + } + } + else if (type==GUI_CLEAR) { + if (runnerId>0 && currentMode == 0) + save(gdi, runnerId, true); + + return true; + } + else if (type == GUI_LINK) { + int id = static_cast(data)->getExtraInt(); + oRunner *vacancy = oe->getRunner(id, 0); + + if (vacancy==0 || vacancy->getClassId()==0) + return -1; + + pRunner r = oe->getRunner(runnerId, 0); + + vacancy->synchronize(); + r->synchronize(); + + if (r==0) + return -1; + + char bf[1024]; + sprintf_s(bf, lang.tl("Bekräfta att %s byter klass till %s.").c_str(), + r->getName().c_str(), vacancy->getClass().c_str()); + if (gdi.ask(string("#") + bf)) { + + vacancy->synchronize(); + if (!vacancy->isVacant()) + throw std::exception("Starttiden är upptagen."); + + oRunner temp(oe, 0); + temp.setTemporary(); + temp.setBib(r->getBib(), 0, false, false); + temp.setStartNo(r->getStartNo(), false); + temp.setClassId(r->getClassId(), true); + temp.apply(false, 0, false); + temp.cloneStartTime(r); + + r->setClassId(vacancy->getClassId(), true); + // Remove or create multi runners + r->createMultiRunner(true, true); + r->apply(false, 0, false); + r->cloneStartTime(vacancy); + r->setBib(vacancy->getBib(), 0, false, false); + r->setStartNo(vacancy->getStartNo(), false); + + if (oe->hasPrevStage()) { + if (gdi.ask("Vill du sätta resultatet från tidigare etapper till ?")) + r->resetInputData(); + } + + vacancy->setClassId(temp.getClassId(), true); + // Remove or create multi runners + vacancy->createMultiRunner(true, true); + vacancy->apply(false, 0, false); + vacancy->cloneStartTime(&temp); + vacancy->setBib(temp.getBib(), 0, false, false); + vacancy->setStartNo(temp.getStartNo(), false); + + r->synchronizeAll(); + vacancy->synchronizeAll(); + + loadPage(gdi); + selectRunner(gdi, r); + } + } + return 0; +} + +void TabRunner::showCardsList(gdioutput &gdi) +{ + currentMode = 3; + gdi.clearPage(false); + gdi.dropLine(0.5); + gdi.addString("", boldLarge, "Hantera löparbrickor"); + gdi.addString("", 10, "help:14343"); + addToolbar(gdi); + gdi.dropLine(); + cardModeStartY=gdi.getCY(); + Table *t=oe->getCardsTB(); + gdi.addTable(t,gdi.getCX(),gdi.getCY()+15); + gdi.registerEvent("CellAction", RunnerCB); + gdi.refresh(); +} + +int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data) +{ + if (type == GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + + + if (bi.id == "VacancyAdd") { + showVacancyList(gdi, "add"); + } + else if (bi.id == "PrinterSetup") { + tsi.setPrintStartInfo(true); + TabList::splitPrintSettings(*oe, gdi, true, TRunnerTab, TabList::StartInfo); + } + else if (bi.id == "CancelVacant") { + tsi.storedInfo.clear(); + loadPage(gdi); + } + } + else if (type == GUI_LINK) { + int id = static_cast(data)->getExtraInt(); + oRunner *r = oe->getRunner(id, 0); + + if (r==0) + return -1; + + r->synchronize(); + if (!r->isVacant()) + throw std::exception("Starttiden är upptagen."); + + string name = gdi.getText("Name"); + + if (name.empty()) + throw std::exception("Alla deltagare måste ha ett namn."); + + int cardNo = gdi.getTextNo("CardNo"); + + if (cardNo!=r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo)) + return 0; + + string club = gdi.getText("Club"); + int birthYear = 0; + pClub pc = oe->getClubCreate(0, club); + + r->updateFromDB(name, pc->getId(), r->getClassId(), cardNo, birthYear); + + r->setName(name, true); + r->setCardNo(cardNo, true); + + r->setClub(club); + int fee = 0; + if (gdi.hasField("Fee")) { + ListBoxInfo lbi; + if (gdi.getSelectedItem("Fee", lbi) && lbi.data == -1) { + lastFee = "@"; + // Use class default fee + } + else { + r->setFlag(oRunner::FlagFeeSpecified, true); + fee = oe->interpretCurrency(gdi.getText("Fee")); + lastFee = oe->formatCurrency(fee); + r->getDI().setInt("Fee", fee); + } + } + + r->getDI().setDate("EntryDate", getLocalDate()); + r->addClassDefaultFee(false); + int cardFee = 0; + + if (gdi.isChecked("RentCard")) { + cardFee = oe->getDI().getInt("CardFee"); + r->getDI().setInt("CardFee", cardFee); + } + else + r->getDI().setInt("CardFee", 0); + + + + if (cardFee < 0) + cardFee = 0; + fee = r->getDCI().getInt("Fee"); + + TabSI::writePayMode(gdi, fee + cardFee, *r); + + if (gdi.hasField("AllStages")) { + r->setFlag(oRunner::FlagTransferSpecified, true); + r->setFlag(oRunner::FlagTransferNew, gdi.isChecked("AllStages")); + } + + if (oe->hasPrevStage()) { + if (gdi.ask("Vill du sätta resultatet från tidigare etapper till ?")) + r->resetInputData(); + } + + r->synchronizeAll(); + + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + + // Print start certificate + tsi.generateStartInfo(gdi, *r); + + showVacancyList(gdi, "", r->getClassId()); + } + else if (type==GUI_INPUT) { + InputInfo ii=*(InputInfo *)data; + + if (ii.id=="CardNo") { + int cardNo = gdi.getTextNo("CardNo"); + if (gdi.getText("Name").empty()) + setCardNo(gdi, cardNo); + } + } + else if (type==GUI_POSTCLEAR) { + // Clear out SI-link + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.setCardNumberField(""); + + return true; + } + else if (type == GUI_CLEAR) { + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.storedInfo.clear(); + tsi.storedInfo.storedName = gdi.getText("Name"); + tsi.storedInfo.storedCardNo = gdi.getText("CardNo"); + tsi.storedInfo.storedClub = gdi.getText("Club"); + ListBoxInfo lbi; + if (gdi.getSelectedItem("Fee", lbi) && lbi.data == -1) { + tsi.storedInfo.storedFee = "@"; + // Use class default fee + } + else + tsi.storedInfo.storedFee = gdi.getText("Fee", true); + + tsi.storedInfo.allStages = gdi.isChecked("AllStages"); + tsi.storedInfo.rentState = gdi.isChecked("RentCard"); + tsi.storedInfo.hasPaid = gdi.isChecked("Paid"); + tsi.storedInfo.payMode = gdi.hasField("PayMode") ? gdi.getSelectedItem("PayMode").first : 0; + return 1; + } + return 0; +} + +void TabRunner::setCardNo(gdioutput &gdi, int cardNo) +{ + pRunner db_r=oe->dbLookUpByCard(cardNo); + + if (db_r) { + gdi.setText("Name", db_r->getName()); + gdi.setText("Club", db_r->getClub()); + } +} + +void TabRunner::showRunnerReport(gdioutput &gdi) +{ + gdi.clearPage(true); + currentMode = 5; + + if (!ownWindow && !oe->isReadOnly()) + addToolbar(gdi); + else if (oe->isReadOnly()) + gdi.addString("", fontLarge, MakeDash("MeOS - Resultatkiosk")).setColor(colorDarkBlue); + + gdi.dropLine(); + + gdi.pushX(); + gdi.fillRight(); + + gdi.addSelection("ReportRunner", 300, 300, RunnerCB); + oe->fillRunners(gdi, "ReportRunner", true, oEvent::RunnerFilterShowAll|oEvent::RunnerCompactMode); + gdi.selectItemByData("ReportRunner", runnerId); + + if (!oe->isReadOnly()) { + if (!ownWindow) { + gdi.addButton("Kiosk", "Resultatkiosk", RunnerCB); + gdi.addButton("Window", "Eget fönster", RunnerCB, "Öppna i ett nytt fönster."); + } + gdi.dropLine(0.2); + gdi.addCheckbox("ListenReadout", "Visa senast inlästa deltagare", RunnerCB, listenToPunches); + } + + gdi.dropLine(3); + gdi.popX(); + gdi.registerEvent("DataUpdate", RunnerCB); + gdi.registerEvent("ReadCard", RunnerCB); + + gdi.fillDown(); + oe->calculateResults(oEvent::RTClassResult); + + if (runnerId > 0) { + runnersToReport.resize(1); + runnersToReport[0] = make_pair(runnerId, false); + } + + cTeam t = 0; + for (size_t k = 0; k < runnersToReport.size(); k++) { + pRunner r = oe->getRunner(runnersToReport[k].first, 0); + if (r && r->getTeam()) { + pClass cls = oe->getClass(r->getClassId()); + if (cls && cls->getClassType() == oClassPatrol) + continue; + + if (t == 0) + t = r->getTeam(); + } + } + + if (runnersToReport.size() == 1) + runnerId = runnersToReport[0].first; + + if (t == 0) { + for (size_t k = 0; k < runnersToReport.size(); k++) + runnerReport(gdi, runnersToReport[k].first, runnersToReport[k].second); + } + else { + oe->calculateTeamResults(false); + + set selectedRunners; + bool selHasRes = false; + for (size_t k = 0; k < runnersToReport.size(); k++) { + selectedRunners.insert(runnersToReport[k].first); + pRunner r = oe->getRunner(runnersToReport[k].first, 0); + if (r->getStatus() != StatusUnknown) + selHasRes = true; + } + + string tInfo = t->getName(); + if (t->statusOK()) { + tInfo += ", " + t->getRunningTimeS() + lang.tl(".S Placering: ") + t->getPlaceS(); + if (t->getTimeAfter(-1) > 0) + tInfo += ", +" + formatTime(t->getTimeAfter(-1)); + } + else if (t->getStatus() != StatusUnknown) { + tInfo += " " + t->getStatusS(); + } + + gdi.addStringUT(fontMediumPlus, t->getClass()); + gdi.addStringUT(boldLarge, tInfo); + gdi.dropLine(); + + bool visitedSelected = false; + for (int leg = 0; leg < t->getNumRunners(); leg++) { + if (selHasRes && visitedSelected) + break; + + pRunner r = t->getRunner(leg); + pRunner nextR = t->getRunner(leg + 1); + bool nextSelected = nextR && selectedRunners.count(nextR->getId()); + + if (r) { + bool selected = selectedRunners.count(r->getId()) > 0; + + if (selHasRes) { + runnerReport(gdi, r->getId(), !selected); + } + else { + runnerReport(gdi, r->getId(), !nextSelected); + } + + visitedSelected |= selected; + } + } + } +} + +void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) { + pRunner r = oe->getRunner(id, 0); + if (!r || ! r->getClassRef()) + return; + + gdi.pushX(); + gdi.fillDown(); + if (r->getTeam() == 0) { + gdi.addStringUT(fontMediumPlus, r->getClass()); + gdi.addStringUT(boldLarge, r->getCompleteIdentification()); + } + else { + string s; + if (r->getTeam()) + s += r->getClassRef()->getLegNumber(r->getLegNumber()); + + s += ": " + r->getName(); + gdi.addStringUT(boldText, s); + } + + string str; + if (r->getTeam() == 0) { + str = oe->formatListString(lRunnerTimeStatus, r); + } + else { + str = oe->formatListString(lTeamLegTimeStatus, r); + str += " (" + oe->formatListString(lRunnerTimeStatus, r) + ")"; + } + + gdi.dropLine(0.3); + + if (r->statusOK()) { + int total, finished, dns; + oe->getNumClassRunners(r->getClassId(), r->getLegNumber(), total, finished, dns); + + if (r->getTeam() == 0) { + gdi.addString("", fontMediumPlus, "Tid: X, nuvarande placering Y/Z.#" + str + "#" + r->getPlaceS() + "#" + itos(finished)); + } + else { + int place = r->getTeam()->getLegPlace(r->getLegNumber(), false); + if (place > 0 && place < 10000) { + gdi.addString("", fontMediumPlus, "Tid: X, nuvarande placering Y/Z.#" + str + "#" + itos(place) + "#" + itos(finished)); + } + else { + gdi.addStringUT(fontMediumPlus, str).setColor(colorRed); + } + } + } + else if (r->getStatus() != StatusUnknown) { + gdi.addStringUT(fontMediumPlus, str).setColor(colorRed); + } + + gdi.popX(); + gdi.fillRight(); + + if (r->getStartTime() > 0) + gdi.addString("", fontMedium, "Starttid: X #" + r->getStartTimeCompact()); + + if (r->getFinishTime() > 0) + gdi.addString("", fontMedium, "Måltid: X #" + r->getFinishTimeS()); + + const string &after = oe->formatListString(lRunnerTimeAfter, r); + if (!after.empty()) { + gdi.addString("", fontMedium, "Tid efter: X #" + after); + } + + const string &lost = oe->formatListString(lRunnerMissedTime, r); + if (!lost.empty()) { + gdi.addString("", fontMedium, "Bomtid: X #" + lost).setColor(colorDarkRed); + } + + gdi.popX(); + gdi.dropLine(2.5); + gdi.fillDown(); + + if (compact) + return; + + pCourse crs = r->getCourse(true); + + int xp = gdi.getCX(); + int yp = gdi.getCY(); + int xw = gdi.scaleLength(130); + int cx = xp; + int limit = (9*xw)/10; + int lh = gdi.getLineHeight(); + + if (crs && r->getStatus() != StatusUnknown) { + int nc = crs->getNumControls(); + vector delta; + vector place; + vector after; + vector placeAcc; + vector afterAcc; + + r->getSplitAnalysis(delta); + r->getLegTimeAfter(after); + r->getLegPlaces(place); + + r->getLegTimeAfterAcc(afterAcc); + r->getLegPlacesAcc(placeAcc); + int end = crs->useLastAsFinish() ? nc - 1 : nc; + int start = crs->useFirstAsStart() ? 1 : 0; + for (int k = start; k<=end; k++) { + string name = crs->getControlOrdinal(k); + if ( k < end) { + pControl ctrl = crs->getControl(k); + if (ctrl && ctrl->getFirstNumber() > 0) + name += " (" + itos(ctrl->getFirstNumber()) + ")"; + gdi.addString("", yp, cx, boldText, "Kontroll X#" + name, limit); + } + else + gdi.addStringUT(yp, cx, boldText, name, limit); + + string split = r->getSplitTimeS(k, false); + + int bestTime = 0; + if ( k < int(after.size()) && after[k] >= 0) + bestTime = r->getSplitTime(k, false) - after[k]; + + GDICOLOR color = colorDefault; + if (k < int(after.size()) ) { + if (after[k] > 0) + split += " (" + itos(place[k]) + ", +" + getTimeMS(after[k]) + ")"; + else if (place[k] == 1) + split += lang.tl(" (sträckseger)"); + else if (place[k] > 0) + split += " " + itos(place[k]); + + if (after[k] >= 0 && after[k]<=int(bestTime * 0.03)) + color = colorLightGreen; + } + gdi.addStringUT(yp + lh, cx, fontMedium, split, limit); + + if (k>0 && k < int(placeAcc.size())) { + split = r->getPunchTimeS(k, false); + string pl = placeAcc[k] > 0 ? itos(placeAcc[k]) : "-"; + if (k < int(afterAcc.size()) ) { + if (afterAcc[k] > 0) + split += " (" + pl + ", +" + getTimeMS(afterAcc[k]) + ")"; + else if (placeAcc[k] == 1) + split += lang.tl(" (ledare)"); + else if (placeAcc[k] > 0) + split += " " + pl; + } + gdi.addStringUT(yp + 2*lh, cx, fontMedium, split, limit).setColor(colorDarkBlue); + } + + if (k < int(delta.size()) && delta[k] > 0 ) { + gdi.addString("", yp + 3*lh, cx, fontMedium, "Bomtid: X#" + getTimeMS(delta[k])); + + color = (delta[k] > bestTime * 0.5 && delta[k]>60 ) ? + colorMediumDarkRed : colorMediumRed; + } + + RECT rc; + rc.top = yp - 2; + rc.bottom = yp + lh*5 - 4; + rc.left = cx - 4; + rc.right = cx + xw - 8; + + gdi.addRectangle(rc, color); + + cx += xw; + + if (k % 6 == 5) { + cx = xp; + yp += lh * 5; + } + } + } + else { + vector punches; + oe->getPunchesForRunner(r->getId(), punches); + + int lastT = r->getStartTime(); + for (size_t k = 0; k < punches.size(); k++) { + + string name = punches[k]->getType(); + string realName; + if (atoi(name.c_str()) > 0) { + const pCourse rCrs = r->getCourse(false); + if (rCrs) { + vector crsCtrl; + rCrs->getControls(crsCtrl); + for(size_t j = 0; j < crsCtrl.size(); j++) { + if (crsCtrl[j]->hasNumber(atoi(name.c_str()))) { + if (crsCtrl[j]->hasName()) + realName = crsCtrl[j]->getName(); + + break; + } + } + } + if (realName.empty()) + gdi.addString("", yp, cx, boldText, "Kontroll X#" + name, limit); + else + gdi.addStringUT(yp, cx, boldText, realName, limit); + } + else + gdi.addStringUT(yp, cx, boldText, name, limit); + + int t = punches[k]->getAdjustedTime(); + if (t>0) { + int st = r->getStartTime(); + gdi.addString("", yp + lh, cx, normalText, "Klocktid: X#" + oe->getAbsTime(t), limit); + if (st > 0 && t > st) { + string split = formatTimeHMS(t-st); + if (lastT>0 && st != lastT && lastT < t) + split += " (" + getTimeMS(t-lastT) + ")"; + gdi.addStringUT(yp + 2*lh, cx, normalText, split, limit); + } + } + + if (punches[k]->isStart() || punches[k]->getControlNumber() >= 30) { + lastT = t; + } + + GDICOLOR color = colorDefault; + + RECT rc; + rc.top = yp - 2; + rc.bottom = yp + lh*5 - 4; + rc.left = cx - 4; + rc.right = cx + xw - 8; + + gdi.addRectangle(rc, color); + cx += xw; + if (k % 6 == 5) { + cx = xp; + yp += lh * 5; + } + } + } + + gdi.dropLine(3); + gdi.popX(); +} + + +void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classId) +{ + gdi.clearPage(true); + currentMode = 4; + + if (method == "") { + gdi.dropLine(0.5); + gdi.addString("", boldLarge, "Tillsatte vakans"); + addToolbar(gdi); + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.storedInfo.clear(); + + gdi.dropLine(); + + gdi.fillRight(); + gdi.pushX(); + gdi.addButton("VacancyAdd", "Tillsätt ytterligare vakans", VacancyCB); + //gdi.addButton("Cancel", "Återgå", VacancyCB); + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2); + + if (classId==0) + oe->generateVacancyList(gdi, 0); + else { + oListParam par; + par.selection.insert(classId); + oListInfo info; + par.listCode = EStdStartList; + oe->generateListInfo(par, gdi.getLineHeight(), info); + oe->generateList(gdi, false, info, true); + } + } + else if (method == "add") { + gdi.dropLine(0.5); + gdi.addString("", boldLarge, "Tillsätt vakans"); + addToolbar(gdi); + + gdi.dropLine(); + + gdi.fillRight(); + + int bx = gdi.getCX(); + int by = gdi.getCY(); + + gdi.setCX(bx + gdi.scaleLength(10)); + gdi.setCY(by + gdi.scaleLength(10)); + gdi.pushX(); + + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.storedInfo.checkAge(); + + gdi.addInput("CardNo", tsi.storedInfo.storedCardNo, 8, VacancyCB, "Bricka:"); + tsi.setCardNumberField("CardNo"); + + //Remember to clear SI-link when page is cleared. + gdi.setPostClearCb(VacancyCB); + gdi.setOnClearCb(VacancyCB); + + gdi.dropLine(1.2); + gdi.addCheckbox("RentCard", "Hyrd", 0, tsi.storedInfo.rentState); + gdi.dropLine(-1.2); + + gdi.addInput("Name", tsi.storedInfo.storedName, 16, 0, "Namn:"); + + gdi.addCombo("Club", 220, 300, 0, "Klubb:"); + oe->fillClubs(gdi, "Club"); + gdi.setText("Club", tsi.storedInfo.storedClub); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) { + if (!tsi.storedInfo.storedFee.empty()) + lastFee = tsi.storedInfo.storedFee; + + gdi.addCombo("Fee", 60, 150, SportIdentCB, "Avgift:"); + oe->fillFees(gdi, "Fee", true); + gdi.autoGrow("Fee"); + + if (!lastFee.empty() && lastFee != "@") { + gdi.setText("Fee", lastFee); + } + else { + gdi.selectFirstItem("Fee"); + } + gdi.dropLine(1.2); + + //gdi.addCheckbox("Paid", "Kontant betalning", 0, tsi.storedInfo.hasPaid); + tsi.generatePayModeWidget(gdi); + gdi.dropLine(-0.2); + } + else { + gdi.dropLine(); + } + + gdi.dropLine(2.8); + gdi.popX(); + gdi.addCheckbox("StartInfo", "Skriv ut startbevis", SportIdentCB, tsi.hasPrintStartInfo(), "Skriv ut startbevis för deltagaren"); + + if (oe->hasNextStage()) + gdi.addCheckbox("AllStages", "Anmäl till efterföljande etapper", 0, tsi.storedInfo.allStages); + + gdi.dropLine(-0.2); + gdi.addButton("PrinterSetup", "Skrivarinställningar...", VacancyCB, "Skrivarinställningar för sträcktider och startbevis"); + gdi.setCX(gdi.getCX() + gdi.scaleLength(40)); + gdi.addButton("CancelVacant", "Avbryt", VacancyCB); + + gdi.fillDown(); + gdi.dropLine(2.5); + RECT rc = {bx, by, gdi.getWidth(), gdi.getCY() + gdi.scaleLength(20)}; + gdi.addRectangle(rc, colorLightCyan); + + gdi.setCX(bx); + gdi.pushX(); + gdi.dropLine(); + + gdi.addString("", fontMediumPlus, "Välj klass och starttid nedan"); + oe->generateVacancyList(gdi, VacancyCB); + gdi.setInputFocus("CardNo"); + } + else if (method == "move") { + + } +} + + +void TabRunner::clearInForestData() +{ + unknown_dns.clear(); + known_dns.clear(); + known.clear(); + unknown.clear(); +} + +void TabRunner::showInForestList(gdioutput &gdi) +{ + gdi.clearPage(false); + currentMode = 2; + gdi.dropLine(0.5); + gdi.addString("", boldLarge, "Hantera kvar-i-skogen"); + addToolbar(gdi); + gdi.dropLine(); + gdi.setRestorePoint("Help"); + gdi.addString("", 10, "help:425188"); + gdi.dropLine(); + gdi.pushX(); + gdi.fillRight(); + gdi.addButton("Import", "Importera stämplingar...", SportIdentCB).setExtra(1); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) { + vector rr; + oe->getRunners(0, 0, rr, false); + bool hasVac = false; + for (size_t k = 0; k < rr.size(); k++) { + if (rr[k]->isVacant()) { + hasVac = true; + break; + } + } + if (hasVac) { + gdi.addButton("RemoveVacant", "Radera vakanser", RunnerCB); + } + } + gdi.addButton("SetDNS", "Sätt okända löpare utan registrering till ", RunnerCB); + gdi.fillDown(); + gdi.addButton("SetUnknown", "Återställ löpare med registrering till ", RunnerCB); + gdi.dropLine(); + gdi.popX(); + + clearInForestData(); + oe->analyseDNS(unknown_dns, known_dns, known, unknown); + oe->setupCardHash(false); + if (!unknown.empty()) { + gdi.dropLine(); + gdi.dropLine(0.5); + gdi.addString("", 1, "Löpare, Status Okänd, som saknar registrering"); + listRunners(gdi, unknown, true); + } + else { + gdi.disableInput("SetDNS"); + } + + if (!known.empty()) { + gdi.dropLine(); + gdi.addString("", 1, "Löpare, Status Okänd, med registrering (kvar-i-skogen)"); + gdi.dropLine(0.5); + listRunners(gdi, known, false); + } + + if (!known_dns.empty()) { + gdi.dropLine(); + gdi.addString("", 1, "Löpare, Ej Start, med registrering (kvar-i-skogen!?)"); + gdi.dropLine(0.5); + listRunners(gdi, known_dns, false); + } + else + gdi.disableInput("SetUnknown"); + + oe->setupCardHash(true); + + if (known.empty() && unknown.empty() && known_dns.empty()) { + gdi.addString("", 10, "inforestwarning"); + } + + gdi.refresh(); +} + +void TabRunner::listRunners(gdioutput &gdi, const vector &r, bool filterVacant) const +{ + char bf[64]; + int yp = gdi.getCY(); + int xp = gdi.getCX(); + vector out; + for (size_t k=0; kisVacant()) + continue; + sprintf_s(bf, "%d.", k+1); + gdi.addStringUT(yp, xp, 0, bf); + gdi.addStringUT(yp, xp+40, 0, r[k]->getNameAndRace(true), 190); + gdi.addStringUT(yp, xp+200, 0, r[k]->getClass(), 140); + gdi.addStringUT(yp, xp+350, 0, r[k]->getClub(), 190); + int c = r[k]->getCardNo(); + if (c>0) { + oe->getRunnersByCardNo(c, true, true, out); + if (out.size() <= 1) { + gdi.addStringUT(yp, xp+550, 0, "(" + itos(c) + ")", 190); + } + else { + TextInfo &ti = gdi.addStringUT(yp, xp+550, 0, "(" + itos(c) + ", " + lang.tl("reused card") + ")", 100); + string tt; + for (size_t j = 0; j < out.size(); j++) { + if (out[j] == r[k]->getMultiRunner(0)) + continue; + if (!tt.empty()) + tt += ", "; + tt += out[j]->getName(); + } + gdi.addToolTip(ti.id, tt, 0, &ti.textRect); + } + } + yp += gdi.getLineHeight(); + } +} + +void TabRunner::cellAction(gdioutput &gdi, DWORD id, oBase *obj) +{ + if (id==TID_RUNNER || id==TID_CARD) { + gdi.disableTables(); + pCard c=dynamic_cast(obj); + if (c) { + gdi.setRestorePoint("CardTable"); + int orgx=gdi.getCX(); + gdi.dropLine(1); + gdi.setCY(cardModeStartY); + gdi.scrollTo(orgx, cardModeStartY); + gdi.addString("", fontMediumPlus, "Para ihop bricka X med en deltagare#" + itos(c->getCardNo())).setColor(colorDarkGreen); + gdi.dropLine(0.5); + + string name = c->getOwner() ? c->getOwner()->getName() : MakeDash("-"); + gdi.addString("", 0, "Nuvarande innehavare: X.#" + name); + + gdi.dropLine(1); + gdi.pushX(); + gdi.fillRight(); + gdi.addListBox("Card", 150, 300, 0, "Vald bricka:"); + c->fillPunches(gdi, "Card", 0); + gdi.disableInput("Card"); + + gdi.pushX(); + gdi.fillRight(); + gdi.popX(); + + gdi.fillDown(); + gdi.addListBox("Runners", 350, 300, 0, "Deltagare:"); + gdi.setTabStops("Runners", 200, 300); + oe->fillRunners(gdi, "Runners", true, oEvent::RunnerFilterShowAll); + if (c->getOwner()) + gdi.selectItemByData("Runners", c->getOwner()->getId()); + + gdi.popX(); + gdi.fillRight(); + gdi.addInput("SearchText", "", 15).setBgColor(colorLightCyan); + gdi.addButton("Search", "Sök deltagare", RunnerCB, "Sök på namn, bricka eller startnummer."); + + gdi.popX(); + gdi.dropLine(3); + gdi.addButton("Pair", "Para ihop", RunnerCB).setExtra(c->getId()); + gdi.addButton("Unpair", "Sätt som oparad", RunnerCB).setExtra(c->getId()); + gdi.addButton("Cancel", "Avbryt", RunnerCB); + gdi.fillDown(); + gdi.popX(); + gdi.refresh(); + } + } +} + +void disablePunchCourseAdd(gdioutput &gdi) +{ + gdi.disableInput("AddC"); + gdi.disableInput("AddAllC"); + gdi.selectItemByData("Course", -1); +} + +const string &TabRunner::getSearchString() const { + return lang.tl("Sök (X)#Ctrl+F"); +} + +void disablePunchCourseChange(gdioutput &gdi) +{ + gdi.disableInput("SaveC"); + gdi.disableInput("RemoveC"); + gdi.disableInput("PTime"); + gdi.setText("PTime", ""); + gdi.selectItemByData("Punches", -1); + +} + +void disablePunchCourse(gdioutput &gdi) +{ + disablePunchCourseAdd(gdi); + disablePunchCourseChange(gdi); +} + +void UpdateStatus(gdioutput &gdi, pRunner r) +{ + if (!r) return; + + gdi.setText("Start", r->getStartTimeS()); + gdi.setText("Finish", r->getFinishTimeS()); + gdi.setText("Time", r->getRunningTimeS()); + gdi.selectItemByData("Status", r->getStatus()); + gdi.setText("RunnerInfo", lang.tl(r->getProblemDescription()), true); +} + +int TabRunner::punchesCB(gdioutput &gdi, int type, void *data) +{ + DWORD rid=runnerId; + if (!rid) + return 0; + + pRunner r=oe->getRunner(rid, 0); + + if (!r){ + gdi.alert("Deltagaren måste sparas innan stämplingar kan hanteras."); + return 0; + } + + + if (type==GUI_LISTBOX){ + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Punches") { + if (bi.data != -1) { + pCard card=r->getCard(); + if (!card) return 0; + pPunch punch = card->getPunchByIndex(bi.data); + if (!punch) + throw meosException("Punch not found."); + + string ptime=punch->getTime();//;card->getPunchTime(punch); + + if (ptime!="") { + gdi.enableInput("SaveC"); + gdi.setText("PTime", ptime); + } + gdi.enableInput("RemoveC"); + gdi.enableInput("PTime"); + } + else { + gdi.disableInput("SaveC"); + gdi.disableInput("RemoveC"); + gdi.setText("PTime", ""); + } + disablePunchCourseAdd(gdi); + } + else if (bi.id=="Course") { + if (signed(bi.data)>=0) { + pCourse pc=r->getCourse(true); + + if (!pc) return 0; + + gdi.enableInput("AddC"); + gdi.enableInput("AddAllC"); + } + else{ + gdi.disableInput("AddC"); + gdi.disableInput("AddAllC"); + } + disablePunchCourseChange(gdi); + } + } + else if (type==GUI_BUTTON){ + ButtonInfo bi=*(ButtonInfo *)data; + pCard card=r->getCard(); + + if (!card){ + if (!gdi.ask("ask:addpunches")) + return 0; + + card=oe->allocateCard(r); + + card->setCardNo(r->getCardNo()); + vector mp; + r->addPunches(card, mp); + + } + + if (bi.id=="AddC"){ + vector mp; + r->evaluateCard(true, mp); + + pCourse pc=r->getCourse(true); + + if (!pc) return 0; + + ListBoxInfo lbi; + + if (!gdi.getSelectedItem("Course", lbi)) + return 0; + + oControl *oc=pc->getControl(lbi.data); + + if (!oc) return 0; + vector nmp; + + if (oc->getStatus() == oControl::StatusRogaining) { + r->evaluateCard(true, nmp, oc->getFirstNumber()); //Add this punch + } + else { + for (size_t k = 0; khasNumber(mp[k])) + r->evaluateCard(true, nmp, mp[k]); //Add this punch + } + } + //synchronize SQL + card->synchronize(); + r->synchronize(true); + r->evaluateCard(true, mp); + card->fillPunches(gdi, "Punches", pc); + UpdateStatus(gdi, r); + } + else if (bi.id=="AddAllC"){ + vector mp; + r->evaluateCard(true, mp); + vector::iterator it=mp.begin(); + + + while(it!=mp.end()){ + vector nmp; + r->evaluateCard(true, nmp, *it); //Add this punch + ++it; + if (nmp.empty()) + break; + } + + //synchronize SQL + card->synchronize(); + r->synchronize(true); + r->evaluateCard(true, mp); + card->fillPunches(gdi, "Punches", r->getCourse(true)); + UpdateStatus(gdi, r); + } + else if (bi.id=="SaveC"){ + //int time=oe->GetRelTime(); + + ListBoxInfo lbi; + + if (!gdi.getSelectedItem("Punches", lbi)) + return 0; + + pCard pc=r->getCard(); + + if (!pc) return 0; + + pPunch pp = pc->getPunchByIndex(lbi.data); + + if (!pp) + throw meosException("Punch not found."); + + pc->setPunchTime(pp, gdi.getText("PTime")); + + vector mp; + r->evaluateCard(true, mp); + + //synchronize SQL + card->synchronize(); + r->synchronize(); + r->evaluateCard(true, mp); + card->fillPunches(gdi, "Punches", r->getCourse(true)); + UpdateStatus(gdi, r); + gdi.selectItemByData("Punches", lbi.data); + } + } + return 0; +} + +bool TabRunner::loadPage(gdioutput &gdi) +{ + oe->reEvaluateAll(set(), true); + + if (oe->isReadOnly()) + currentMode = 5; // Evaluate result + else { + clearInForestData(); + gdi.selectTab(tabId); + } + gdi.clearPage(false); + int basex=gdi.getCX(); + + if (currentMode == 1) { + Table *tbl=oe->getRunnersTB(); + addToolbar(gdi); + gdi.dropLine(1); + gdi.addTable(tbl, basex, gdi.getCY()); + return true; + } + else if (currentMode == 2) { + showInForestList(gdi); + return true; + } + else if (currentMode == 3) { + showCardsList(gdi); + return true; + } + else if (currentMode == 4) { + showVacancyList(gdi, "add"); + return true; + } + else if (currentMode == 5) { + showRunnerReport(gdi); + return true; + } + + currentMode = 0; + + gdi.pushX(); + gdi.dropLine(0.5); + gdi.addString("", boldLarge, "Deltagare"); + gdi.fillRight(); + gdi.registerEvent("SearchRunner", runnerSearchCB).setKeyCommand(KC_FIND); + gdi.registerEvent("SearchRunnerBack", runnerSearchCB).setKeyCommand(KC_FINDBACK); + + gdi.addInput("SearchText", getSearchString(), 13, runnerSearchCB, "", + "Sök på namn, bricka eller startnummer.").isEdit(false) + .setBgColor(colorLightCyan).ignore(true); + gdi.dropLine(-0.2); + //gdi.addButton("Search", "Sök", RunnerCB, "Sök på namn, bricka eller startnummer."); + gdi.addButton("ShowAll", "Visa alla", RunnerCB).isEdit(false); + gdi.dropLine(2); + gdi.popX(); + + gdi.fillDown(); + gdi.addListBox("Runners", 206, 420, RunnerCB).isEdit(false).ignore(true); + gdi.setInputFocus("Runners"); + fillRunnerList(gdi); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) { + gdi.fillRight(); + gdi.addButton("Move", "Klassbyte", RunnerCB); + gdi.addButton("NoStart", "Återbud", RunnerCB); + } + + gdi.newColumn(); + gdi.fillDown(); + + gdi.dropLine(1); + gdi.fillRight(); + gdi.pushX(); + gdi.addInput("Name", "", 16, 0, "Namn:"); + + if (oe->hasBib(true, false)) { + gdi.addInput("Bib", "", 4, 0, "Nr", "Nummerlapp"); + } + gdi.popX(); + gdi.dropLine(3); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + gdi.fillDown(); + gdi.addCombo("Club", 220, 300, 0, "Klubb:"); + oe->fillClubs(gdi, "Club"); + gdi.pushX(); + } + + if (oe->hasTeam()) { + gdi.fillRight(); + gdi.addInput("Team", "", 16, 0, "Lag:").isEdit(false); + gdi.disableInput("Team"); + gdi.fillDown(); + gdi.dropLine(0.9); + gdi.addButton("EditTeam", "...", RunnerCB, "Hantera laget"); + gdi.popX(); + } + + gdi.fillRight(); + gdi.addSelection("RClass", 150, 300, RunnerCB, "Klass:"); + oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); + gdi.addItem("RClass", lang.tl("Ingen klass"), 0); + + gdi.fillDown(); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) + gdi.addInput("Fee", "", 6, 0, "Avgift:"); + else + gdi.dropLine(3); + + gdi.dropLine(0.4); + + if (oe->hasMultiRunner()) { + gdi.fillRight(); + gdi.popX(); + gdi.addString("", 0, "Välj lopp:"); + gdi.fillDown(); + gdi.dropLine(-0.2); + gdi.addSelection("MultiR", 160, 100, RunnerCB); + } + + gdi.popX(); + + int numSL = numShorteningLevels(); + if (numSL > 0) + gdi.fillRight(); + + gdi.addSelection("RCourse", numSL == 0 ? 220 : 180, 300, RunnerCB, "Bana:"); + oe->fillCourses(gdi, "RCourse", true); + gdi.addItem("RCourse", lang.tl("[Klassens bana]"), 0); + + if (numSL > 0) { + gdi.fillDown(); + gdi.addSelection("NumShort", 60, 300, RunnerCB, "Avkortning:"); + vector< pair > data; + if (numSL == 1) { + data.push_back(make_pair(lang.tl("Nej"), 0)); + data.push_back(make_pair(lang.tl("Ja"), 1)); + } + else { + data.push_back(make_pair(lang.tl("Nej"), 0)); + for (int i = 1; i <= numSL; i++) { + data.push_back(make_pair(itos(i), i)); + } + } + gdi.addItem("NumShort", data); + gdi.popX(); + } + + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("CardNo", "", 8, RunnerCB, "Bricka:"); + gdi.dropLine(1); + gdi.addCheckbox("RentCard", "Hyrd", 0, false); + + gdi.dropLine(2); + gdi.popX(); + + gdi.addInput("Start", "", 8, 0, "Starttid:"); + gdi.addInput("Finish", "", 8, 0, "Måltid:"); + + const bool timeAdjust = oe->getMeOSFeatures().hasFeature(MeOSFeatures::TimeAdjust); + const bool pointAdjust = oe->getMeOSFeatures().hasFeature(MeOSFeatures::PointAdjust); + + if (timeAdjust || pointAdjust) { + gdi.dropLine(3); + gdi.popX(); + if (timeAdjust) { + gdi.addInput("TimeAdjust", "", 8, 0, "Tidstillägg:"); + } + if (pointAdjust) { + gdi.addInput("PointAdjust", "", 8, 0, "Poängavdrag:"); + } + } + gdi.dropLine(3); + gdi.popX(); + + gdi.addInput("Time", "", 8, 0, "Tid:").isEdit(false).ignore(true); + gdi.disableInput("Time"); + + if (oe->hasRogaining()) { + gdi.addInput("Points", "", 5, 0, "Poäng:").isEdit(false).ignore(true); + gdi.disableInput("Points"); + } + + gdi.fillDown(); + gdi.addSelection("Status", 100, 80, 0, "Status:", "tooltip_explain_status"); + oe->fillStatus(gdi, "Status"); + gdi.autoGrow("Status"); + gdi.popX(); + gdi.selectItemByData("Status", 0); + + gdi.addString("RunnerInfo", 1, "").setColor(colorRed); + + const bool multiDay = oe->hasPrevStage(); + + if (multiDay) { + gdi.dropLine(1.2); + + int xx = gdi.getCX(); + int yy = gdi.getCY(); + gdi.dropLine(0.5); + gdi.fillDown(); + int dx = int(gdi.getLineHeight()*0.7); + int ccx = xx + dx; + gdi.setCX(ccx); + gdi.addString("", 1, "Resultat från tidigare etapper"); + gdi.dropLine(0.3); + gdi.fillRight(); + + gdi.addSelection("StatusIn", 100, 160, 0, "Status:", "tooltip_explain_status"); + oe->fillStatus(gdi, "StatusIn"); + gdi.selectItemByData("Status", 0); + gdi.addInput("PlaceIn", "", 5, 0, "Placering:"); + int xmax = gdi.getCX() + dx; + gdi.setCX(ccx); + gdi.dropLine(3); + gdi.addInput("TimeIn", "", 5, 0, "Tid:"); + if (oe->hasRogaining()) { + gdi.addInput("PointIn", "", 5, 0, "Poäng:"); + } + gdi.dropLine(3); + RECT rc; + rc.right = xx; + rc.top = yy; + rc.left = max(xmax, gdi.getWidth()-dx); + rc.bottom = gdi.getCY(); + + gdi.addRectangle(rc, colorLightGreen, true, false); + gdi.dropLine(); + gdi.popX(); + } + else + gdi.dropLine(1.0); + + gdi.fillRight(); + gdi.addButton("Save", "Spara", RunnerCB, "help:save").setDefault(); + gdi.addButton("Undo", "Ångra", RunnerCB); + gdi.dropLine(2.2); + gdi.popX(); + gdi.addButton("Remove", "Radera", RunnerCB); + gdi.addButton("Add", "Ny deltagare", RunnerCB); + enableControlButtons(gdi, false, false); + gdi.fillDown(); + + gdi.newColumn(); + int hx = gdi.getCX(); + int hy = gdi.getCY(); + gdi.setCX(hx + gdi.scaleLength(5)); + + gdi.dropLine(2.5); + gdi.addListBox("Punches", 150, 300, PunchesCB, "Stämplingar:").ignore(true); + gdi.addButton("RemoveC", "Ta bort stämpling >>", RunnerCB); + + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("PTime", "", 8, 0, "", "Stämplingstid"); + gdi.fillDown(); + gdi.addButton("SaveC", "Spara tid", PunchesCB); + gdi.popX(); + gdi.dropLine(); + int contX = gdi.getCX(); + int contY = gdi.getCY(); + + gdi.newColumn(); + gdi.dropLine(2.5); + gdi.fillDown(); + gdi.addListBox("Course", 140, 300, PunchesCB, "Banmall:").ignore(true); + gdi.addButton("AddC", "<< Lägg till stämpling", PunchesCB); + gdi.addButton("AddAllC", "<< Lägg till alla", PunchesCB); + + gdi.synchronizeListScroll("Punches", "Course"); + disablePunchCourse(gdi); + + gdi.setCX(contX); + gdi.setCY(contY); + gdi.addString("", fontMediumPlus, "Utskrift"); + + gdi.dropLine(0.2); + gdi.fillRight(); + gdi.addButton(gdi.getCX(), gdi.getCY(), gdi.scaleLength(120), "SplitPrint", + "Skriv ut sträcktider", RunnerCB, "", false, false).isEdit(true).setExtra(0); + gdi.addButton("PrintSettings", "...", RunnerCB, "Inställningar").isEdit(true).setExtra(0); + + gdi.dropLine(2.5); + gdi.setCX(contX); + gdi.addButton(gdi.getCX(), gdi.getCY(), gdi.scaleLength(120), "SplitPrint", + "Skriv ut startbevis", RunnerCB, "", false, false).isEdit(true).setExtra(1); + gdi.addButton("PrintSettings", "...", RunnerCB, "Inställningar").isEdit(true).setExtra(1); + gdi.pushY(); + + int by = gdi.getHeight(); + int bx = gdi.getWidth(); + RECT box = {hx-gdi.scaleLength(5), hy, bx + gdi.scaleLength(5), by}; + gdi.addString("", hy + gdi.scaleLength(5), hx + gdi.scaleLength(5), fontMediumPlus, "Brickhantering"); + gdi.addRectangle(box, colorLightBlue, true, false).set3D(true).id = "CardRect"; + + gdi.fillDown(); + gdi.setCY(gdi.getHeight()); + gdi.setCX(gdi.scaleLength(100)); + + //gdi.addString("", 10, "help:41072"); + + gdi.registerEvent("LoadRunner", RunnerCB); + + gdi.setOnClearCb(RunnerCB); + + addToolbar(gdi); + + selectRunner(gdi, oe->getRunner(runnerId, 0)); + gdi.refresh(); + return true; +} + +void TabRunner::addToolbar(gdioutput &gdi) { + + const int button_w=gdi.scaleLength(130); + int dx = 2; + + gdi.addButton(dx, 2, button_w, "FormMode", + "Formulärläge", RunnerCB, "", false, true).fixedCorner(); + gdi.check("FormMode", currentMode==0); + dx += button_w; + + gdi.addButton(dx, 2, button_w, "TableMode", + "Tabelläge", RunnerCB, "", false, true).fixedCorner(); + gdi.check("TableMode", currentMode==1); + dx += button_w; + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::InForest)) { + gdi.addButton(dx, 2, button_w, "InForest", + "Kvar-i-skogen", RunnerCB, "", false, true).fixedCorner(); + gdi.check("InForest", currentMode==2); + dx += button_w; + } + + gdi.addButton(dx, 2 ,button_w, "Cards", + "Hantera brickor", RunnerCB, "", false, true).fixedCorner(); + gdi.check("Cards", currentMode==3); + dx += button_w; + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) { + gdi.addButton(dx, 2 ,button_w, "Vacancy", + "Vakanser", RunnerCB, "", false, true).fixedCorner(); + gdi.check("Vacancy", currentMode==4); + dx += button_w; + } + + gdi.addButton(dx, 2 ,button_w, "ReportMode", + "Rapportläge", RunnerCB, "", false, true).fixedCorner(); + gdi.check("ReportMode", currentMode==5); + dx += button_w; + +} + +void TabRunner::fillRunnerList(gdioutput &gdi) { + bool formMode = currentMode == 0; + timeToFill = GetTickCount(); + oe->fillRunners(gdi, "Runners", !formMode, formMode ? 0 : oEvent::RunnerFilterShowAll); + timeToFill = GetTickCount() - timeToFill; + if (formMode) { + lastSearchExpr = ""; + ((InputInfo *)gdi.setText("SearchText", getSearchString()))->setFgColor(colorGreyBlue); + lastFilter.clear(); + } +} + +bool TabRunner::canSetStart(pRunner r) const { + pClass pc = r->getTeam() ? r->getTeam()->getClassRef() : r->getClassRef(); + + if (pc && pc->getNumStages() > 0) { + StartTypes st = pc->getStartType(r->getLegNumber()); + if (st != STDrawn) + return false; + } + if (pc && !pc->ignoreStartPunch()) { + int startType = oPunch::PunchStart; + if (r->getCourse(false)) + startType = r->getCourse(false)->getStartPunchType(); + + pCard c = r->getCard(); + if (c && c->getPunchByType(startType)) + return false; + } + return true; +} + +bool TabRunner::canSetFinish(pRunner r) const { + pCard c = r->getCard(); + int finishPunch = oPunch::PunchFinish; + if (r->getCourse(false)) + finishPunch = r->getCourse(false)->getFinishPunchType(); + if (c && c->getPunchByType(finishPunch)) + return false; + + return true; +} + +pRunner TabRunner::warnDuplicateCard(int cno, pRunner r) { + pRunner warnCardDupl = 0; + + if (!r->getCard()) { + vector allR; + oe->getRunners(0, 0, allR, false); + for (size_t k = 0; k < allR.size(); k++) { + if (!r->canShareCard(allR[k], cno)) { + warnCardDupl = allR[k]; + break; + } + } + } + return warnCardDupl; +} + +void TabRunner::warnDuplicateCard(gdioutput &gdi, int cno, pRunner r) { + pRunner warnCardDupl = warnDuplicateCard(cno, r); + + InputInfo &cardNo = dynamic_cast(gdi.getBaseInfo("CardNo")); + if (warnCardDupl) { + cardNo.setBgColor(colorLightRed); + gdi.updateToolTip("CardNo", "Brickan används av X.#" + warnCardDupl->getCompleteIdentification()); + cardNo.refresh(); + } + else { + if (cardNo.getBgColor() != colorDefault) { + cardNo.setBgColor(colorDefault); + gdi.updateToolTip("CardNo", ""); + cardNo.refresh(); + } + } +} + +int TabRunner::numShorteningLevels() const { + vector allCrs; + oe->getCourses(allCrs); + set touch; + map known; + int res = 0; + for (size_t k = 0; k < allCrs.size(); k++) { + pCourse sh = allCrs[k]->getShorterVersion(); + touch.clear(); + int count = 0; + while (sh && !touch.count(sh->getId())) { + count++; + map::iterator r = known.find(sh->getId()); + if (r != known.end()) { + count += r->second; + break; + } + touch.insert(sh->getId()); + sh = sh->getShorterVersion(); + } + known[allCrs[k]->getId()] = count; + res = max(res, count); + } + return res; +} + +void TabRunner::updateNumShort(gdioutput &gdi, pCourse crs, pRunner r) { + if (gdi.hasField("NumShort")) { + if (crs && crs->getShorterVersion()) { + gdi.enableInput("NumShort"); + if (r) + gdi.selectItemByData("NumShort", r->getNumShortening()); + else + gdi.selectFirstItem("NumShort"); + } + else { + gdi.disableInput("NumShort"); + gdi.selectFirstItem("NumShort"); + } + } +} + +void TabRunner::clearCompetitionData() { + inputId = 0; + lastRace=0; + currentMode = 0; + runnerId=0; + timeToFill = 0; + ownWindow = false; + listenToPunches = false; +} + +void TabRunner::autoGrowCourse(gdioutput &gdi) { + ListBoxInfo &crsCtrl = dynamic_cast(gdi.getBaseInfo("Course")); + int wInit = crsCtrl.getWidth(); + if (gdi.autoGrow("Course")) { + RectangleInfo &rc = gdi.getRectangle("CardRect"); + int wAfter = crsCtrl.getWidth(); + rc.changeDimension(gdi, wAfter - wInit, 0); + gdi.refresh(); + } +} diff --git a/code/TabRunner.h b/code/TabRunner.h new file mode 100644 index 0000000..0df591d --- /dev/null +++ b/code/TabRunner.h @@ -0,0 +1,114 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "tabbase.h" +#include "Printer.h" + +class Table; + +class TabRunner : + public TabBase +{ +private: + void addToolbar(gdioutput &gdi); + + const string &getSearchString() const; + + void setCardNo(gdioutput &gdi, int cardNo); + + void enableControlButtons(gdioutput &gdi, bool enable, bool vacant); + + void cellAction(gdioutput &gdi, DWORD id, oBase *obj); + + void selectRunner(gdioutput &gdi, pRunner r); + + string lastSearchExpr; + stdext::hash_set lastFilter; + DWORD timeToFill; + int inputId; + int searchCB(gdioutput &gdi, int type, void *data); + + int runnerCB(gdioutput &gdi, int type, void *data); + int punchesCB(gdioutput &gdi, int type, void *data); + int vacancyCB(gdioutput &gdi, int type, void *data); + + int currentMode; + pRunner save(gdioutput &gdi, int runnerId, bool dontReloadRunners); + void listRunners(gdioutput &gdi, const vector &r, bool filterVacant) const; + + void fillRunnerList(gdioutput &gdi); + + int cardModeStartY; + int lastRace; + string lastFee; + int runnerId; + bool ownWindow; + bool listenToPunches; + vector< pair > runnersToReport; + + vector unknown_dns; + vector known_dns; + vector known; + vector unknown; + void clearInForestData(); + + PrinterObject splitPrinter; + + void showRunnerReport(gdioutput &gdi); + void runnerReport(gdioutput &gdi, int id, bool compactReport); + + void showVacancyList(gdioutput &gdi, const string &method="", int classId=0); + void showCardsList(gdioutput &gdi); + + bool canSetStart(pRunner r) const; + bool canSetFinish(pRunner r) const; + + void warnDuplicateCard(gdioutput &gdi, int cno, pRunner r); + pRunner warnDuplicateCard(int cno, pRunner r); + + int numShorteningLevels() const; + + void updateNumShort(gdioutput &gdi, pCourse crs, pRunner r); + + static void autoGrowCourse(gdioutput &gdi); + +protected: + void clearCompetitionData(); + +public: + + const char * getTypeStr() const {return "TRunnerTab";} + TabType getType() const {return TRunnerTab;} + + void showInForestList(gdioutput &gdi); + + bool loadPage(gdioutput &gdi); + bool loadPage(gdioutput &gdi, int runnerId); + + TabRunner(oEvent *oe); + ~TabRunner(void); + + friend int runnerSearchCB(gdioutput *gdi, int type, void *data); + friend int RunnerCB(gdioutput *gdi, int type, void *data); + friend int PunchesCB(gdioutput *gdi, int type, void *data); + friend int VacancyCB(gdioutput *gdi, int type, void *data); +}; diff --git a/code/TabSI.cpp b/code/TabSI.cpp new file mode 100644 index 0000000..024ea54 --- /dev/null +++ b/code/TabSI.cpp @@ -0,0 +1,3584 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "gdiconstants.h" + +#include "csvparser.h" + +#include "TabSI.h" +#include "TabAuto.h" +#include "TabList.h" +#include "meos_util.h" +#include +#include "TabRunner.h" +#include "meosexception.h" +#include "MeOSFeatures.h" +#include "RunnerDB.h" +#include "recorder.h" + +TabSI::TabSI(oEvent *poe):TabBase(poe) { + editCardData.tabSI = this; + interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0; + useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0; + printSplits = false; + printStartInfo = false; + savedCardUniqueId = 1; + + manualInput = poe->getPropertyInt("ManualInput", 0) == 1; + + mode=ModeReadOut; + currentAssignIndex=0; + + lastClubId=0; + lastClassId=0; + logger = 0; + + minRunnerId = 0; + inputId = 0; + printErrorShown = false; + NC = 8; +} + +TabSI::~TabSI(void) +{ + if (logger!=0) + delete logger; + logger = 0; +} + + +static void entryTips(gdioutput &gdi) { + gdi.fillDown(); + gdi.addString("", 10, "help:21576"); + gdi.dropLine(1); + gdi.setRestorePoint("EntryLine"); +} + + +void TabSI::logCard(const SICard &card) +{ + if (logger == 0) { + logger = new csvparser; + string readlog = "sireadlog_" + getLocalTimeFileName() + ".csv"; + char file[260]; + string subfolder = makeValidFileName(oe->getName(), true); + const char *sf = subfolder.empty() ? 0 : subfolder.c_str(); + getDesktopFile(file, readlog.c_str(), sf); + logger->openOutput(file); + vector head = SICard::logHeader(); + logger->OutputRow(head); + logcounter = 0; + } + + vector log = card.codeLogData(++logcounter); + logger->OutputRow(log); +} + +extern SportIdent *gSI; +extern pEvent gEvent; + +void LoadRunnerPage(gdioutput &gdi); + + +int SportIdentCB(gdioutput *gdi, int type, void *data) +{ + TabSI &tsi = dynamic_cast(*gdi->getTabs().get(TSITab)); + + return tsi.siCB(*gdi, type, data); +} + +int TabSI::siCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id == "ClearMemory") { + if (gdi.ask("Do you want to clear the card memory?")) { + savedCards.clear(); + loadPage(gdi); + } + } + else if (bi.id == "SaveMemory") { + vector< pair > ext; + ext.push_back(make_pair("Semikolonseparerad (csv)", "*.csv")); + + int filterIx = 0; + string file = gdi.browseForSave(ext, "csv", filterIx); + if (!file.empty()) { + csvparser saver; + saver.openOutput(file.c_str()); + vector head = SICard::logHeader(); + saver.OutputRow(head); + int count = 0; + for (list< pair >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) { + vector log = it->second.codeLogData(++count); + saver.OutputRow(log); + } + } + } + else if (bi.id == "CreateCompetition") { + createCompetitionFromCards(gdi); + } + else if (bi.id=="SIPassive") { + string port=gdi.getText("ComPortName"); + if (gSI->OpenComListen(port.c_str(), gdi.getTextNo("BaudRate"))) { + gSI->StartMonitorThread(port.c_str()); + loadPage(gdi); + gdi.addString("", 1, "Lyssnar på X.#"+port).setColor(colorDarkGreen); + } + else + gdi.addString("", 1, "FEL: Porten kunde inte öppnas").setColor(colorRed); + gdi.dropLine(); + gdi.refresh(); + } + else if (bi.id=="CancelTCP") + gdi.restore("TCP"); + else if (bi.id=="StartTCP") { + gSI->tcpAddPort(gdi.getTextNo("tcpPortNo"), 0); + gdi.restore("TCP"); + gSI->StartMonitorThread("TCP"); + + printSIInfo(gdi, "TCP"); + + gdi.dropLine(0.5); + refillComPorts(gdi); + gdi.refresh(); + } + else if (bi.id=="StartSI") { + char bf[64]; + ListBoxInfo lbi; + if (gdi.getSelectedItem("ComPort", lbi)) { + + sprintf_s(bf, 64, "COM%d", lbi.data); + string port=bf; + + if (lbi.text.substr(0, 3)=="TCP") + port="TCP"; + + if (gSI->IsPortOpen(port)) { + gSI->CloseCom(port.c_str()); + gdi.addStringUT(0, lang.tl("Kopplar ifrån SportIdent på ") + port + lang.tl("... OK")); + gdi.popX(); + gdi.dropLine(); + refillComPorts(gdi); + } + else { + gdi.fillDown(); + if (port=="TCP") { + gdi.setRestorePoint("TCP"); + gdi.dropLine(); + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("tcpPortNo", "10000", 8,0, "Port för TCP:"); + gdi.dropLine(); + gdi.addButton("StartTCP", "Starta", SportIdentCB); + gdi.addButton("CancelTCP", "Avbryt", SportIdentCB); + gdi.dropLine(2); + gdi.popX(); + gdi.fillDown(); + gdi.addString("", 10, "help:14070"); + gdi.scrollToBottom(); + gdi.refresh(); + return 0; + } + + gdi.addStringUT(0, lang.tl("Startar SI på")+" "+ port + "..."); + gdi.refresh(); + if (gSI->OpenCom(port.c_str())){ + gSI->StartMonitorThread(port.c_str()); + gdi.addStringUT(0, lang.tl("SI på")+" "+ port + ": "+lang.tl("OK")); + printSIInfo(gdi, port); + + SI_StationInfo *si = gSI->findStation(port); + if (si && !si->extended()) + gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed); + } + else{ + //Retry... + Sleep(300); + if (gSI->OpenCom(port.c_str())) { + gSI->StartMonitorThread(port.c_str()); + gdi.addStringUT(0, lang.tl("SI på") + " " + port + ": " + lang.tl("OK")); + printSIInfo(gdi, port); + + SI_StationInfo *si = gSI->findStation(port); + if (si && !si->extended()) + gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed); + } + else { + gdi.setRestorePoint(); + gdi.addStringUT(1, lang.tl("SI på") +" "+ port + ": " + lang.tl("FEL, inget svar.")).setColor(colorRed); + gdi.dropLine(); + gdi.refresh(); + + if (gdi.ask("help:9615")) { + + gdi.pushX(); + gdi.fillRight(); + gdi.addInput("ComPortName", port, 10, 0, "COM-Port:"); + //gdi.addInput("BaudRate", "4800", 10, 0, "help:baudrate"); + gdi.fillDown(); + gdi.addCombo("BaudRate", 130, 100, 0, "help:baudrate"); + gdi.popX(); + gdi.addItem("BaudRate", "4800", 4800); + gdi.addItem("BaudRate", "38400", 38400); + gdi.selectItemByData("BaudRate", 38400); + + + gdi.fillRight(); + gdi.addButton("SIPassive", "Lyssna...", SportIdentCB).setDefault(); + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel(); + gdi.popX(); + } + } + } + gdi.popX(); + gdi.dropLine(); + refillComPorts(gdi); + } + gdi.refresh(); + } + } + else if (bi.id=="SIInfo") { + char bf[64]; + ListBoxInfo lbi; + if (gdi.getSelectedItem("ComPort", lbi)) + { + if (lbi.text.substr(0,3)=="TCP") + sprintf_s(bf, 64, "TCP"); + else + sprintf_s(bf, 64, "COM%d", lbi.data); + gdi.fillDown(); + gdi.addStringUT(0, lang.tl("Hämtar information om")+" "+string(bf)+"."); + printSIInfo(gdi, bf); + gdi.refresh(); + } + } + else if (bi.id=="AutoDetect") + { + gdi.fillDown(); + gdi.addString("", 0, "Söker efter SI-enheter... "); + gdi.refresh(); + list ports; + if (!gSI->AutoDetect(ports)) { + gdi.addString("SIInfo", 0, "help:5422"); + gdi.refresh(); + return 0; + } + char bf[128]; + gSI->CloseCom(0); + + while(!ports.empty()) { + int p=ports.front(); + sprintf_s(bf, 128, "COM%d", p); + + gdi.addString((string("SIInfo")+bf).c_str(), 0, "#" + lang.tl("Startar SI på") + " " + string(bf) + "..."); + gdi.refresh(); + if (gSI->OpenCom(bf)) { + gSI->StartMonitorThread(bf); + gdi.addStringUT(0, lang.tl("SI på") + " " + string(bf) + ": " + lang.tl("OK")); + printSIInfo(gdi, bf); + + SI_StationInfo *si = gSI->findStation(bf); + if (si && !si->extended()) + gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed); + } + else if (gSI->OpenCom(bf)) { + gSI->StartMonitorThread(bf); + gdi.addStringUT(0, lang.tl("SI på") + " " + string(bf) + ": " + lang.tl("OK")); + printSIInfo(gdi, bf); + + SI_StationInfo *si = gSI->findStation(bf); + if (si && !si->extended()) + gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed); + } + else gdi.addStringUT(0, lang.tl("SI på") + " " + string(bf) + ": " +lang.tl("FEL, inget svar")); + + gdi.refresh(); + gdi.popX(); + gdi.dropLine(); + ports.pop_front(); + } + } + else if (bi.id == "PrinterSetup") { + if (mode == ModeEntry) { + printStartInfo = true; + TabList::splitPrintSettings(*oe, gdi, true, TSITab, TabList::StartInfo); + } + else { + printSplits = true; + TabList::splitPrintSettings(*oe, gdi, true, TSITab, TabList::Splits); + } + } + else if (bi.id == "AutoTie") { + gEvent->setProperty("AutoTie", gdi.isChecked("AutoTie")); + } + else if (bi.id == "RentCardTie") { + gEvent->setProperty("RentCard", gdi.isChecked(bi.id)); + } + else if (bi.id == "TieOK") { + tieCard(gdi); + } + else if (bi.id=="Interactive") { + interactiveReadout=gdi.isChecked(bi.id); + gEvent->setProperty("Interactive", interactiveReadout); + + if (mode == ModeAssignCards) { + gdi.restore("ManualTie", false); + showAssignCard(gdi, false); + } + } + else if (bi.id=="Database") { + useDatabase=gdi.isChecked(bi.id); + gEvent->setProperty("Database", useDatabase); + } + else if (bi.id=="PrintSplits") { + printSplits=gdi.isChecked(bi.id); + } + else if (bi.id=="StartInfo") { + printStartInfo = gdi.isChecked(bi.id); + } + else if (bi.id == "UseManualInput") { + manualInput = gdi.isChecked("UseManualInput"); + oe->setProperty("ManualInput", manualInput ? 1 : 0); + gdi.restore("ManualInput"); + if (manualInput) + showManualInput(gdi); + } + else if (bi.id=="Import") { + int origin = bi.getExtraInt(); + + vector< pair > ext; + ext.push_back(make_pair("Semikolonseparerad (csv)", "*.csv")); + + string file = gdi.browseForOpen(ext, "csv"); + if (!file.empty()) { + gdi.restore("Help"); + csvparser csv; + csv.importCards(*oe, file.c_str(), cards); + if (cards.empty()) { + csv.importPunches(*oe, file.c_str(), punches); + if (!punches.empty()) { + gdi.dropLine(2); + gdi.addString("", 1, "Inlästa stämplar"); + set dates; + showReadPunches(gdi, punches, dates); + + filterDate.clear(); + filterDate.push_back(lang.tl("Inget filter")); + for (set::iterator it = dates.begin(); it!=dates.end(); ++it) + filterDate.push_back(*it); + + gdi.dropLine(2); + gdi.scrollToBottom(); + gdi.fillRight(); + gdi.pushX(); + gdi.addSelection("ControlType", 150, 300, 0, "Enhetstyp:"); + + vector< pair > d; + oe->fillControlTypes(d); + gdi.addItem("ControlType", d); + // oe->fillControlTypes(gdi, "ControlType"); + gdi.selectItemByData("ControlType", oPunch::PunchCheck); + + gdi.addSelection("Filter", 150, 300, 0, "Datumfilter:"); + for (size_t k = 0; k0; + string filter = lbi.data < filterDate.size() ? filterDate[lbi.data] : ""; + + gdi.restore("Help"); + for (size_t k=0;kaddFreePunch(punches[k].time, type, punches[k].card, true); + } + punches.clear(); + if (origin==1) { + TabRunner &tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab)); + tc.showInForestList(gdi); + } + } + else if (bi.id=="SaveCards") { + int origin = bi.getExtraInt(); + gdi.restore("Help"); + oe->synchronizeList(oLCardId, true, false); + oe->synchronizeList(oLRunnerId, false, true); + for (size_t k=0;kreEvaluateAll(set(), true); + cards.clear(); + if (origin==1) { + TabRunner &tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab)); + tc.showInForestList(gdi); + } + } + else if (bi.id=="Save") { + SICard sic; + sic.clear(0); + sic.CheckPunch.Code = -1; + sic.CardNumber=gdi.getTextNo("SI"); + int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum()); + int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum()); + sic.FinishPunch.Time= f % (24*3600); + sic.StartPunch.Time = f % (24*3600); + if (!gdi.isChecked("HasFinish")) { + sic.FinishPunch.Code = -1; + sic.FinishPunch.Time = 0; + } + + if (!gdi.isChecked("HasStart")) { + sic.StartPunch.Code = -1; + sic.StartPunch.Time = 0; + } + + double t = 0.1; + for (sic.nPunch = 0; sic.nPunchaddCard(sic); + } + else if (bi.id=="SaveP") { + SICard sic; + sic.clear(0); + sic.FinishPunch.Code = -1; + sic.CheckPunch.Code = -1; + sic.StartPunch.Code = -1; + + sic.CardNumber=gdi.getTextNo("SI"); + int f=convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum()); + if (f > 0) { + sic.FinishPunch.Time = f; + sic.FinishPunch.Code = 1; + sic.PunchOnly = true; + gSI->addCard(sic); + return 0; + } + + int s=convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum()); + if (s > 0) { + sic.StartPunch.Time = s; + sic.StartPunch.Code = 1; + sic.PunchOnly = true; + gSI->addCard(sic); + return 0; + } + + sic.Punch[sic.nPunch].Code=gdi.getTextNo("C1"); + sic.Punch[sic.nPunch].Time=convertAbsoluteTimeHMS(gdi.getText("C2"), oe->getZeroTimeNum()); + sic.nPunch = 1; + sic.PunchOnly = true; + gSI->addCard(sic); + } + else if (bi.id=="Cancel") { + int origin = bi.getExtraInt(); + activeSIC.clear(0); + punches.clear(); + if (origin==1) { + TabRunner &tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab)); + tc.showInForestList(gdi); + return 0; + } + loadPage(gdi); + + checkMoreCardsInQueue(gdi); + return 0; + } + else if (bi.id=="OK1") { + string name=gdi.getText("Runners"); + string club=gdi.getText("Club", true); + + if (name.length()==0){ + gdi.alert("Alla deltagare måste ha ett namn."); + return 0; + } + + pRunner r=0; + DWORD rid; + bool lookup = true; + + if (gdi.getData("RunnerId", rid) && rid>0) { + r = gEvent->getRunner(rid, 0); + + if (r && r->getCard()) { + if (!askOverwriteCard(gdi, r)) { + r = 0; + lookup = false; + } + } + + if (r && stringMatch(r->getName(), name)) { + gdi.restore(); + //We have a match! + SICard copy = activeSIC; + activeSIC.clear(&activeSIC); + processCard(gdi, r, copy); + return 0; + } + } + + if (lookup) { + r = gEvent->getRunnerByName(name, club); + if (r && r->getCard()) { + if (!askOverwriteCard(gdi, r)) + r = 0; + } + } + + if (r) { + //We have a match! + gdi.setData("RunnerId", r->getId()); + + gdi.restore(); + SICard copy = activeSIC; + activeSIC.clear(&activeSIC); + processCard(gdi, r, copy); + return 0; + } + + //We have a new runner in our system + gdi.fillRight(); + gdi.pushX(); + + SICard si_copy=activeSIC; + gEvent->convertTimes(si_copy); + + //Find matching class... + vector classes; + int dist = gEvent->findBestClass(activeSIC, classes); + + if (classes.size()==1 && dist == 0 && si_copy.StartPunch.Time>0 && classes[0]->getType()!="tmp") { + //We have a match! + string club = gdi.getText("Club", true); + + if (club.length()==0 && oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) + club=lang.tl("Klubblös"); + int year = 0; + pRunner r=gEvent->addRunner(gdi.getText("Runners"), club, + classes[0]->getId(), activeSIC.CardNumber, year, true); + + gdi.setData("RunnerId", r->getId()); + + gdi.restore(); + SICard copy = activeSIC; + activeSIC.clear(&activeSIC); + processCard(gdi, r, copy); + r->synchronize(); + return 0; + } + + + gdi.restore("restOK1", false); + gdi.popX(); + gdi.dropLine(2); + + gdi.addInput("StartTime", gEvent->getAbsTime(si_copy.StartPunch.Time), 8, 0, "Starttid:"); + + gdi.addSelection("Classes", 200, 300, 0, "Klass:"); + gEvent->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterNone); + gdi.setInputFocus("Classes"); + + if (classes.size()>0) + gdi.selectItemByData("Classes", classes[0]->getId()); + + gdi.dropLine(); + + gdi.setRestorePoint("restOK2"); + + gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel(); + if (oe->getNumClasses() > 0) + gdi.addButton("OK2", "OK", SportIdentCB).setDefault(); + gdi.fillDown(); + + gdi.addButton("NewClass", "Skapa ny klass", SportIdentCB); + + gdi.popX(); + if (classes.size()>0) + gdi.addString("FindMatch", 0, "Press Enter to continue").setColor(colorGreen); + gdi.dropLine(); + + gdi.refresh(); + return 0; + } + else if (bi.id=="OK2") + { + //New runner in existing class... + + ListBoxInfo lbi; + gdi.getSelectedItem("Classes", lbi); + + if (lbi.data==0 || lbi.data==-1) { + gdi.alert("Du måste välja en klass"); + return 0; + } + pClass pc = oe->getClass(lbi.data); + if (pc && pc->getType()== "tmp") + pc->setType(""); + + string club = gdi.getText("Club", true); + + if (club.empty() && oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) + club = lang.tl("Klubblös"); + + int year = 0; + pRunner r=gEvent->addRunner(gdi.getText("Runners"), club, + lbi.data, activeSIC.CardNumber, year, true); + + r->setStartTimeS(gdi.getText("StartTime")); + r->setCardNo(activeSIC.CardNumber, false); + + gdi.restore(); + SICard copy = activeSIC; + activeSIC.clear(&activeSIC); + processCard(gdi, r, copy); + } + else if (bi.id=="NewClass") { + gdi.restore("restOK2", false); + gdi.popX(); + gdi.dropLine(2); + gdi.fillRight(); + gdi.pushX(); + + gdi.addInput("ClassName", gEvent->getAutoClassName(), 10,0, "Klassnamn:"); + + gdi.dropLine(); + gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel(); + gdi.fillDown(); + gdi.addButton("OK3", "OK", SportIdentCB).setDefault(); + gdi.setInputFocus("ClassName", true); + gdi.refresh(); + gdi.popX(); + } + else if (bi.id=="OK3") { + pCourse pc = 0; + pClass pclass = 0; + + if (oe->getNumClasses() == 1 && oe->getClass(1) != 0 && + oe->getClass(1)->getType() == "tmp" && + oe->getClass(1)->getNumRunners(false, false, false) == 0) { + pclass = oe->getClass(1); + pclass->setType(""); + pclass->setName(gdi.getText("ClassName")); + pc = pclass->getCourse(); + if (pc) + pc->setName(gdi.getText("ClassName")); + } + + if (pc == 0) { + pc=gEvent->addCourse(gdi.getText("ClassName")); + for(unsigned i=0;iaddControl(activeSIC.Punch[i].Code); + } + if (pclass == 0) { + pclass=gEvent->addClass(gdi.getText("ClassName"), pc->getId()); + } + else + pclass->setCourse(pc); + int year = 0; + pRunner r=gEvent->addRunner(gdi.getText("Runners"), gdi.getText("Club", true), + pclass->getId(), activeSIC.CardNumber, year, true); + + r->setStartTimeS(gdi.getText("StartTime")); + r->setCardNo(activeSIC.CardNumber, false); + gdi.restore(); + SICard copy_sic = activeSIC; + activeSIC.clear(&activeSIC); + processCard(gdi, r, copy_sic); + } + else if (bi.id=="OK4") { + //Existing runner in existing class... + + ListBoxInfo lbi; + gdi.getSelectedItem("Classes", lbi); + + if (lbi.data==0 || lbi.data==-1) + { + gdi.alert("Du måste välja en klass"); + return 0; + } + + DWORD rid; + pRunner r; + + if (gdi.getData("RunnerId", rid) && rid>0) + r = gEvent->getRunner(rid, 0); + else r = gEvent->addRunner(lang.tl("Oparad bricka"), lang.tl("Okänd"), 0, 0, 0, false); + + r->setClassId(lbi.data, true); + + gdi.restore(); + SICard copy = activeSIC; + activeSIC.clear(&activeSIC); + processCard(gdi, r, copy); + } + else if (bi.id=="EntryOK") { + storedInfo.clear(); + oe->synchronizeList(oLRunnerId, true, false); + oe->synchronizeList(oLCardId, false, true); + + string name=gdi.getText("Name"); + if (name.empty()) { + gdi.alert("Alla deltagare måste ha ett namn."); + return 0; + } + int rid = bi.getExtraInt(); + pRunner r = oe->getRunner(rid, 0); + int cardNo = gdi.getTextNo("CardNo"); + + pRunner cardRunner = oe->getRunnerByCardNo(cardNo, 0, true); + if (cardNo>0 && cardRunner!=0 && cardRunner!=r) { + gdi.alert("Bricknummret är upptaget (X).#" + cardRunner->getName() + ", " + cardRunner->getClass()); + return 0; + } + + ListBoxInfo lbi; + gdi.getSelectedItem("Class", lbi); + + if (signed(lbi.data)<=0) { + pClass pc = oe->getClassCreate(0, lang.tl("Öppen klass")); + lbi.data = pc->getId(); + pc->setAllowQuickEntry(true); + pc->synchronize(); + } + bool updated = false; + int year = 0; + + if (r==0) { + r = oe->addRunner(name, gdi.getText("Club", true), lbi.data, cardNo, year, true); + r->setCardNo(0, false, false); // Clear to match below + } + else { + int clubId = 0; + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + string cname = gdi.getText("Club", true); + + if (cname.empty()) { + pClub club = oe->getClubCreate(0, cname); + clubId = club->getId(); + } + } + int birthYear = 0; + r->updateFromDB(name, clubId, lbi.data, cardNo, birthYear); + r->setName(name, true); + r->setClubId(clubId); + r->setClassId(lbi.data, true); + updated = true; + } + + lastClubId=r->getClubId(); + lastClassId=r->getClassId(); + lastFee = gdi.getText("Fee", true); + int lastFeeNum = oe->interpretCurrency(lastFee); + + r->setCardNo(cardNo, true);//XXX + + oDataInterface di=r->getDI(); + + int cardFee = gdi.isChecked("RentCard") ? oe->getDI().getInt("CardFee") : 0; + di.setInt("CardFee", cardFee); + di.setInt("Fee", lastFeeNum); + r->setFlag(oRunner::FlagFeeSpecified, true); + + writePayMode(gdi, lastFeeNum + (cardFee > 0 ? cardFee : 0), *r); + + di.setString("Phone", gdi.getText("Phone")); + r->setFlag(oRunner::FlagTransferSpecified, gdi.hasField("AllStages")); + r->setFlag(oRunner::FlagTransferNew, gdi.isChecked("AllStages")); + + r->setStartTimeS(gdi.getText("StartTime")); + + string bib = ""; + if (r->autoAssignBib()) + bib = ", " + lang.tl("Nummerlapp: ") + r->getBib(); + + r->synchronize(); + + gdi.restore("EntryLine"); + + char bf[256]; + if (r->getClubId() != 0) { + sprintf_s(bf, "(%d), %s, %s", r->getCardNo(), r->getClub().c_str(), + r->getClass().c_str()); + } + else { + sprintf_s(bf, "(%d), %s", r->getCardNo(), r->getClass().c_str()); + } + + string info(bf); + if (r->getDI().getInt("CardFee") != 0) + info+=lang.tl(", Hyrbricka"); + + vector< pair > modes; + oe->getPayModes(modes); + string pm; + if (modes.size() > 1 && size_t(r->getPaymentMode()) < modes.size()) + pm = " (" + modes[r->getPaymentMode()].first + ")"; + if (r->getDI().getInt("Paid")>0) + info += lang.tl(", Betalat") + pm; + + if (bib.length()>0) + info+=bib; + + if (updated) + info += lang.tl(" [Uppdaterad anmälan]"); + + gdi.pushX(); + gdi.fillRight(); + gdi.addString("ChRunner", 0, "#" + r->getName(), SportIdentCB).setColor(colorGreen).setExtra(r->getId()); + gdi.fillDown(); + gdi.addStringUT(0, info, 0); + gdi.popX(); + + generateStartInfo(gdi, *r); + + gdi.setRestorePoint("EntryLine"); + generateEntryLine(gdi, 0); + } + else if (bi.id=="EntryCancel") { + gdi.restore("EntryLine"); + storedInfo.clear(); + generateEntryLine(gdi, 0); + } + else if (bi.id=="RentCard" || bi.id=="Paid" || bi.id == "AllStages") { + updateEntryInfo(gdi); + } + else if (bi.id == "ManualOK") { + if (runnerMatchedId == -1) + throw meosException("Löparen hittades inte"); + + bool useNow = gdi.getExtraInt("FinishTime") == 1; + string time = useNow ? getLocalTimeOnly() : gdi.getText("FinishTime"); + + int relTime = oe->getRelativeTime(time); + if (relTime <= 0) { + throw meosException("Ogiltig tid."); + } + bool ok = gdi.isChecked("StatusOK"); + bool dnf = gdi.isChecked("StatusDNF"); + + pRunner r = oe->getRunner(runnerMatchedId, 0); + if (r==0) + throw meosException("Löparen hittades inte"); + + if (r->getStatus() != StatusUnknown) { + if (!gdi.ask("X har redan ett resultat. Vi du fortsätta?#" + r->getCompleteIdentification())) + return 0; + } + + gdi.restore("ManualInput", false); + + SICard sic; + sic.runnerId = runnerMatchedId; + sic.relativeFinishTime = relTime; + sic.statusOK = ok; + sic.statusDNF = dnf; + + gSI->addCard(sic); + } + else if (bi.id == "StatusOK") { + bool ok = gdi.isChecked(bi.id); + if (ok) { + gdi.check("StatusDNF", false); + } + } + else if (bi.id == "StatusDNF") { + bool dnf = gdi.isChecked(bi.id); + gdi.setInputStatus("StatusOK", !dnf); + gdi.check("StatusOK", !dnf); + } + else if (bi.id == "CCSClear") { + if (gdi.ask("Vill du göra om avbockningen från början igen?")) { + checkedCardFlags.clear(); + gdi.restore("CCSInit", false); + showCheckCardStatus(gdi, "fillrunner"); + showCheckCardStatus(gdi, "stat"); + gdi.refresh(); + } + } + else if (bi.id == "CCSReport") { + gdi.restore("CCSInit", false); + showCheckCardStatus(gdi, "stat"); + showCheckCardStatus(gdi, "report"); + gdi.refresh(); + } + else if (bi.id == "CCSPrint") { + //gdi.print(oe); + gdioutput gdiPrint("print", gdi.getScale(), gdi.getEncoding()); + gdiPrint.clearPage(false); + + int tCardPosX = cardPosX; + int tCardPosY = cardPosY; + int tCardOffsetX = cardOffsetX; + int tCardCurrentCol = cardCurrentCol; + + showCheckCardStatus(gdiPrint, "stat"); + showCheckCardStatus(gdiPrint, "report"); + showCheckCardStatus(gdiPrint, "tickoff"); + + cardPosX = tCardPosX; + cardPosY = tCardPosY; + cardOffsetX = tCardOffsetX; + cardCurrentCol = tCardCurrentCol; + + gdiPrint.refresh(); + gdiPrint.print(oe); + } + } + else if (type==GUI_LISTBOX) { + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Runners") { + pRunner r = gEvent->getRunner(bi.data, 0); + if (r) { + gdi.setData("RunnerId", bi.data); + if (gdi.hasField("Club")) + gdi.setText("Club", r->getClub()); + gdi.setText("FindMatch", lang.tl("Press Enter to continue"), true); + } + } + else if (bi.id == "PayMode") { + updateEntryInfo(gdi); + } + else if (bi.id=="ComPort") { + char bf[64]; + + if (bi.text.substr(0,3)!="TCP") + sprintf_s(bf, 64, "COM%d", bi.data); + else + strcpy_s(bf, "TCP"); + + if (gSI->IsPortOpen(bf)) + gdi.setText("StartSI", lang.tl("Koppla ifrån")); + else + gdi.setText("StartSI", lang.tl("Aktivera")); + } + else if (bi.id=="ReadType") { + gdi.restore("SIPageLoaded"); + mode = SIMode(bi.data); + gdi.setInputStatus("StartInfo", mode == ModeEntry); + + if (mode==ModeAssignCards || mode==ModeEntry) { + if (mode==ModeAssignCards) { + gdi.dropLine(1); + showAssignCard(gdi, true); + } + else { + entryTips(gdi); + generateEntryLine(gdi, 0); + } + gdi.setInputStatus("Interactive", mode == ModeAssignCards); + gdi.setInputStatus("Database", mode != ModeAssignCards, true); + gdi.disableInput("PrintSplits"); + + gdi.disableInput("UseManualInput"); + } + else if (mode==ModeReadOut) { + gdi.enableInput("Interactive"); + gdi.enableInput("Database", true); + gdi.enableInput("PrintSplits"); + gdi.enableInput("UseManualInput"); + gdi.fillDown(); + gdi.addButton("Import", "Importera från fil...", SportIdentCB); + + if (gdi.isChecked("UseManualInput")) + showManualInput(gdi); + } + else if (mode == ModeCardData) { + showModeCardData(gdi); + } + else if (mode == ModeCheckCards) { + showCheckCardStatus(gdi, "init"); + } + gdi.refresh(); + } + else if (bi.id=="Fee") { + updateEntryInfo(gdi); + } + else if (bi.id == "NC") { + NC = bi.data; + PostMessage(gdi.getTarget(), WM_USER + 2, TSITab, 0); + } + } + else if (type == GUI_LINK) { + TextInfo ti = *(TextInfo *)data; + if (ti.id == "ChRunner") { + pRunner r = oe->getRunner(ti.getExtraInt(), 0); + generateEntryLine(gdi, r); + } + else if (ti.id == "EditAssign") { + int id = ti.getExtraInt(); + pRunner r = oe->getRunner(id, 0); + if (r) { + gdi.setText("CardNo", r->getCardNo()); + gdi.setText("RunnerId", r->getRaceIdentifier()); + gdi.setText("FindMatch", r->getCompleteIdentification(), true); + runnerMatchedId = r->getId(); + } + } + } + else if (type == GUI_COMBO) { + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Fee") { + updateEntryInfo(gdi); + } + else if (bi.id == "Runners") { + DWORD rid; + if ((gdi.getData("RunnerId", rid) && rid>0) || !gdi.getText("Club", true).empty()) + return 0; // Selected from list + + if (!bi.text.empty() && useDatabase) { + pRunner db_r = oe->dbLookUpByName(bi.text, 0, 0, 0); + if (!db_r && lastClubId) + db_r = oe->dbLookUpByName(bi.text, lastClubId, 0, 0); + + if (db_r && gdi.hasField("Club")) { + gdi.setText("Club", db_r->getClub()); + } + } + gdi.setText("FindMatch", lang.tl("Press Enter to continue"), true); + + } + } + else if (type == GUI_COMBOCHANGE) { + ListBoxInfo bi=*(ListBoxInfo *)data; + if (bi.id == "Runners") { + inputId++; + gdi.addTimeoutMilli(300, "AddRunnerInteractive", SportIdentCB).setExtra((void *)inputId); + } + } + else if (type == GUI_EVENT) { + EventInfo ev = *(EventInfo *)data; + if (ev.id == "AutoComplete") { + pRunner r = oe->getRunner(runnerMatchedId, 0); + if (r) { + gdi.setInputFocus("OK1"); + gdi.setText("Runners", r->getName()); + gdi.setData("RunnerId", runnerMatchedId); + if (gdi.hasField("Club")) + gdi.setText("Club", r->getClub()); + inputId = -1; + gdi.setText("FindMatch", lang.tl("Press Enter to continue"), true); + + } + } + } + else if (type == GUI_FOCUS) { + InputInfo &ii=*(InputInfo *)data; + + if (ii.id == "FinishTime") { + if (ii.getExtraInt() == 1) { + ii.setExtra(0); + ii.setFgColor(colorDefault); + //gdi.refreshFast(); + gdi.setText(ii.id, "", true); + } + } + } + else if (type == GUI_TIMER) { + TimerInfo &ti = *(TimerInfo *)(data); + + if (ti.id == "TieCard") { + runnerMatchedId = ti.getExtraInt(); + tieCard(gdi); + return 0; + } + + if (inputId != ti.getExtraInt()) + return 0; + + if (ti.id == "RunnerId") { + const string &text = gdi.getText(ti.id); + int nr = atoi(text.c_str()); + + pRunner r = 0; + if (nr > 0) { + r = getRunnerByIdentifier(nr); + if (r == 0) { + r = oe->getRunnerByBibOrStartNo(text, true); + if (r == 0) { + // Seek where a card is already defined + r = oe->getRunnerByBibOrStartNo(text, false); + } + } + } + + if (nr == 0 && text.size() > 2) { + stdext::hash_set f1, f2; + r = oe->findRunner(text, 0, f1, f2); + } + if (r != 0) { + gdi.setText("FindMatch", r->getCompleteIdentification(), true); + runnerMatchedId = r->getId(); + } + else { + gdi.setText("FindMatch", "", true); + runnerMatchedId = -1; + } + + gdi.setInputStatus("TieOK", runnerMatchedId != -1); + + if (runnerMatchedId != -1 && gdi.getTextNo("CardNo") > 0 && gdi.isChecked("AutoTie")) + tieCard(gdi); + } + else if (ti.id == "Manual") { + const string &text = gdi.getText(ti.id); + int nr = atoi(text.c_str()); + + pRunner r = 0; + if (nr > 0) { + r = oe->getRunnerByBibOrStartNo(text, false); + if (r == 0) + r = oe->getRunnerByCardNo(nr, 0, true, true); + } + + if (nr == 0 && text.size() > 2) { + stdext::hash_set f1, f2; + r = oe->findRunner(text, 0, f1, f2); + } + if (r != 0) { + gdi.setText("FindMatch", r->getCompleteIdentification(), true); + runnerMatchedId = r->getId(); + } + else { + gdi.setText("FindMatch", "", true); + runnerMatchedId = -1; + } + } + else if (ti.id == "AddRunnerInteractive") { + const string &text = gdi.getText("Runners"); + int nr = atoi(text.c_str()); + + pRunner r = 0; + if (nr > 0) { + r = oe->getRunnerByBibOrStartNo(text, true); + } + + if (nr == 0 && text.size() > 2) { + stdext::hash_set f1, f2; + r = oe->findRunner(text, 0, f1, f2); + } + if (r != 0) { + gdi.setText("FindMatch", lang.tl("X (press Ctrl+Space to confirm)#" + r->getCompleteIdentification()), true); + runnerMatchedId = r->getId(); + } + else { + gdi.setText("FindMatch", "", true); + runnerMatchedId = -1; + } + } + } + else if (type==GUI_INPUTCHANGE) { + + InputInfo ii=*(InputInfo *)data; + if (ii.id == "RunnerId") { + inputId++; + gdi.addTimeoutMilli(300, ii.id, SportIdentCB).setExtra((void *)inputId); + } + else if (ii.id == "Manual") { + inputId++; + gdi.addTimeoutMilli(300, ii.id, SportIdentCB).setExtra((void *)inputId); + } + else if (ii.id == "CardNo" && mode == ModeAssignCards) { + gdi.setInputStatus("TieOK", runnerMatchedId != -1); + } + else if (ii.id == "SI") { + pRunner r = oe->getRunnerByCardNo(atoi(ii.text.c_str()), 0, true, false); + if (r && r->getStartTime() > 0) { + gdi.setText("Start", r->getStartTimeS()); + gdi.check("HasStart", false); + int f = r->getStartTime() + 2800 + rand()%1200; + gdi.setText("Finish", oe->getAbsTime(f)); + pCourse pc = r->getCourse(false); + if (pc) { + for (int n = 0; n < pc->getNumControls(); n++) { + if (pc->getControl(n) && n < NC) { + gdi.setText("C" + itos(n+1), pc->getControl(n)->getFirstNumber()); + } + } + } + } + } + } + else if (type==GUI_INPUT) { + InputInfo &ii=*(InputInfo *)data; + if (ii.id == "FinishTime") { + if (ii.text.empty()) { + ii.setExtra(1); + ii.setFgColor(colorGreyBlue); + gdi.setText(ii.id, lang.tl("Aktuell tid"), true); + } + } + else if (ii.id=="CardNo") { + int cardNo = gdi.getTextNo("CardNo"); + + if (mode == ModeAssignCards) { + if (runnerMatchedId != -1 && gdi.isChecked("AutoTie") && cardNo>0) + gdi.addTimeoutMilli(50, "TieCard", SportIdentCB).setExtra((void *)runnerMatchedId); + } + else if (cardNo>0 && gdi.getText("Name").empty()) { + SICard sic; + sic.clear(0); + sic.CardNumber = cardNo; + + entryCard(gdi, sic); + } + } + else if (ii.id[0]=='*') { + int si=atoi(ii.text.c_str()); + + pRunner r=oe->getRunner(ii.getExtraInt(), 0); + r->synchronize(); + + if (r && r->getCardNo()!=si) { + if (si==0 || !oe->checkCardUsed(gdi,*r, si)) { + r->setCardNo(si, false); + r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee")); + r->synchronize(); + } + + if (r->getCardNo()) + gdi.setText(ii.id, r->getCardNo()); + else + gdi.setText(ii.id, ""); + } + } + } + else if (type==GUI_INFOBOX) { + DWORD loaded; + if (!gdi.getData("SIPageLoaded", loaded)) + loadPage(gdi); + } + else if (type == GUI_CLEAR) { + if (mode == ModeEntry) { + storedInfo.clear(); + storedInfo.storedName = gdi.getText("Name"); + storedInfo.storedCardNo = gdi.getText("CardNo"); + storedInfo.storedClub = gdi.hasField("Club") ? gdi.getText("Club") : ""; + storedInfo.storedFee = gdi.getText("Fee", true); + + ListBoxInfo lbi; + gdi.getSelectedItem("Class", lbi); + storedInfo.storedClassId = lbi.data; + storedInfo.storedPhone = gdi.getText("Phone"); + storedInfo.storedStartTime = gdi.getText("StartTime"); + + storedInfo.allStages = gdi.isChecked("AllStages"); + storedInfo.rentState = gdi.isChecked("RentCard"); + storedInfo.hasPaid = gdi.isChecked("Paid"); + storedInfo.payMode = gdi.hasField("PayMode") ? gdi.getSelectedItem("PayMode").first : 0; + } + return 1; + } + + return 0; +} + + +void TabSI::refillComPorts(gdioutput &gdi) +{ + if (!gSI) return; + + list ports; + gSI->EnumrateSerialPorts(ports); + + gdi.clearList("ComPort"); + ports.sort(); + char bf[256]; + int active=0; + int inactive=0; + while(!ports.empty()) + { + int p=ports.front(); + sprintf_s(bf, 256, "COM%d", p); + + if (gSI->IsPortOpen(bf)){ + gdi.addItem("ComPort", string(bf)+" [OK]", p); + active=p; + } + else{ + gdi.addItem("ComPort", bf, p); + inactive=p; + } + + ports.pop_front(); + } + + if (gSI->IsPortOpen("TCP")) + gdi.addItem("ComPort", "TCP [OK]"); + else + gdi.addItem("ComPort", "TCP"); + + if (active){ + gdi.selectItemByData("ComPort", active); + gdi.setText("StartSI", lang.tl("Koppla ifrån")); + } + else{ + gdi.selectItemByData("ComPort", inactive); + gdi.setText("StartSI", lang.tl("Aktivera")); + } +} + +void TabSI::showReadPunches(gdioutput &gdi, vector &punches, set &dates) +{ + char bf[64]; + int yp = gdi.getCY(); + int xp = gdi.getCX(); + dates.clear(); + for (size_t k=0;kgetRunnerByCardNo(punches[k].card, punches[k].time); + sprintf_s(bf, "%d", punches[k].card); + gdi.addStringUT(yp, xp+40, 0, bf, 240); + + if (r!=0) + gdi.addStringUT(yp, xp+100, 0, r->getName(), 170); + + if (punches[k].date[0] != 0) { + gdi.addStringUT(yp, xp+280, 0, punches[k].date, 75); + dates.insert(punches[k].date); + } + if (punches[k].time>0) + gdi.addStringUT(yp, xp+360, 0, oe->getAbsTime(punches[k].time)); + else + gdi.addStringUT(yp, xp+360, 0, MakeDash("-")); + + yp += gdi.getLineHeight(); + } +} + +void TabSI::showReadCards(gdioutput &gdi, vector &cards) +{ + char bf[64]; + int yp = gdi.getCY(); + int xp = gdi.getCX(); + for (size_t k=0;kgetRunnerByCardNo(cards[k].CardNumber, 0); + sprintf_s(bf, "%d", cards[k].CardNumber); + gdi.addStringUT(yp, xp+40, 0, bf, 240); + + if (r!=0) + gdi.addStringUT(yp, xp+100, 0, r->getName(), 240); + + gdi.addStringUT(yp, xp+300, 0, oe->getAbsTime(cards[k].FinishPunch.Time)); + yp += gdi.getLineHeight(); + } +} + +SportIdent &TabSI::getSI(const gdioutput &gdi) { + if (!gSI) { + HWND hWnd=gdi.getMain(); + gSI = new SportIdent(hWnd, 0); + gSI->SetZeroTime(gEvent->getZeroTimeNum()); + } + return *gSI; +} + +bool TabSI::loadPage(gdioutput &gdi) { + gdi.clearPage(true); + printErrorShown = false; + gdi.pushX(); + gdi.selectTab(tabId); + oe->checkDB(); + gdi.setData("SIPageLoaded", 1); + + if (!gSI) { + getSI(gdi); + if (oe->isClient()) + interactiveReadout = false; + } +#ifdef _DEBUG + gdi.fillRight(); + gdi.pushX(); + gdi.addInput("SI", "", 10, SportIdentCB, "SI"); + int s = 3600+(rand()%60)*60; + int f = s + 1800 + rand()%900; + + gdi.setCX(gdi.getCX()+gdi.getLineHeight()); + + gdi.dropLine(1.4); + gdi.addCheckbox("HasStart", ""); + gdi.dropLine(-1.4); + gdi.setCX(gdi.getCX()-gdi.getLineHeight()); + gdi.addInput("Start", oe->getAbsTime(s), 6, 0, "Start"); + + gdi.dropLine(1.4); + gdi.addCheckbox("HasFinish", ""); + gdi.dropLine(-1.4); + gdi.setCX(gdi.getCX()-gdi.getLineHeight()); + + gdi.addInput("Finish", oe->getAbsTime(f), 6, 0, "Mål"); + gdi.addSelection("NC", 45, 200, SportIdentCB, "NC"); + const int src[11] = {33, 34, 45, 50, 36, 38, 59, 61, 62, 67, 100}; + + for (int i = 0; i < 32; i++) + gdi.addItem("NC", itos(i), i); + + gdi.selectItemByData("NC", NC); + + for (int i = 0; i < NC; i++) { + int level = min(i, NC-i)/5; + int c; + if (i < NC /2) { + int ix = i%6; + c = src[ix] + level * 10; + if (c == 100) + c = 183; + } + else { + int ix = 10-(NC-i-1)%5; + c = src[ix] + level * 10; + } + + gdi.addInput("C" + itos(i+1), itos(c), 3, 0, "#C" + itos(i+1)); + } + /* + gdi.addInput("C1", "33", 5, 0, "#C1"); + gdi.addInput("C2", "34", 5, 0, "#C2"); + gdi.addInput("C3", "45", 5, 0, "#C3"); + gdi.addInput("C4", "50", 5, 0, "#C4"); + gdi.addInput("C5", "61", 5, 0, "#C5"); + gdi.addInput("C6", "62", 5, 0, "#C6"); + gdi.addInput("C7", "67", 5, 0, "#C7"); + + gdi.addInput("C8", "100", 5, 0, "#C8"); + */ + + gdi.dropLine(); + gdi.addButton("Save", "Bricka", SportIdentCB); + gdi.fillDown(); + + gdi.addButton("SaveP", "Stämpling", SportIdentCB); + gdi.popX(); +#endif + gdi.addString("", boldLarge, "SportIdent"); + gdi.dropLine(); + + gdi.pushX(); + gdi.fillRight(); + gdi.addSelection("ComPort", 120, 200, SportIdentCB); + gdi.addButton("StartSI", "#Aktivera+++", SportIdentCB); + gdi.addButton("SIInfo", "Info", SportIdentCB); + + refillComPorts(gdi); + + gdi.addButton("AutoDetect", "Sök och starta automatiskt...", SportIdentCB); + gdi.addButton("PrinterSetup", "Skrivarinställningar...", SportIdentCB, "Skrivarinställningar för sträcktider och startbevis"); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2.2); + + int xb = gdi.getCX(); + int yb = gdi.getCY(); + + gdi.fillRight(); + if (!oe->empty()) { + gdi.setCX(xb + gdi.scaleLength(10)); + gdi.setCY(yb + gdi.scaleLength(10)); + gdi.addString("", fontMediumPlus, "Funktion:"); + gdi.addSelection("ReadType", 200, 200, SportIdentCB); + gdi.addItem("ReadType", lang.tl("Avläsning/radiotider"), ModeReadOut); + gdi.addItem("ReadType", lang.tl("Tilldela hyrbrickor"), ModeAssignCards); + gdi.addItem("ReadType", lang.tl("Avstämning hyrbrickor"), ModeCheckCards); + gdi.addItem("ReadType", lang.tl("Anmälningsläge"), ModeEntry); + gdi.addItem("ReadType", lang.tl("Print card data"), ModeCardData); + + gdi.selectItemByData("ReadType", mode); + gdi.dropLine(2.5); + gdi.setCX(xb + gdi.scaleLength(10)); + } + else { + mode = ModeCardData; + } + + if (!oe->empty()) + gdi.addCheckbox("Interactive", "Interaktiv inläsning", SportIdentCB, interactiveReadout); + + if (oe->empty() || oe->useRunnerDb()) + gdi.addCheckbox("Database", "Använd löpardatabasen", SportIdentCB, useDatabase); + + gdi.addCheckbox("PrintSplits", "Sträcktidsutskrift[check]", SportIdentCB, printSplits); + + if (!oe->empty()) { + gdi.addCheckbox("StartInfo", "Startbevis", SportIdentCB, printStartInfo, "Skriv ut startbevis för deltagaren"); + if (mode != ModeEntry) + gdi.disableInput("StartInfo"); + } + if (!oe->empty()) + gdi.addCheckbox("UseManualInput", "Manuell inmatning", SportIdentCB, manualInput); + + gdi.fillDown(); + + if (!oe->empty()) { + RECT rc = {xb, yb, gdi.getWidth(), gdi.getHeight()}; + gdi.addRectangle(rc, colorLightBlue); + } + gdi.popX(); + gdi.dropLine(2); + gdi.setRestorePoint("SIPageLoaded"); + + if (mode==ModeReadOut) { + gdi.addButton("Import", "Importera från fil...", SportIdentCB); + + gdi.setRestorePoint("Help"); + gdi.addString("", 10, "help:471101"); + + if (gdi.isChecked("UseManualInput")) + showManualInput(gdi); + + gdi.dropLine(); + } + else if (mode==ModeAssignCards) { + gdi.dropLine(1); + showAssignCard(gdi, true); + } + else if (mode == ModeEntry) { + entryTips(gdi); + generateEntryLine(gdi, 0); + gdi.disableInput("Interactive"); + gdi.disableInput("PrintSplits"); + gdi.disableInput("UseManualInput"); + } + else if (mode == ModeCardData) { + showModeCardData(gdi); + } + else if (mode == ModeCheckCards) { + showCheckCardStatus(gdi, "init"); + } + + + // Unconditional clear + activeSIC.clear(0); + + checkMoreCardsInQueue(gdi); + gdi.refresh(); + return true; +} + +void InsertSICard(gdioutput &gdi, SICard &sic) +{ + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.insertSICard(gdi, sic); +} + +pRunner TabSI::autoMatch(const SICard &sic, pRunner db_r) +{ + assert(useDatabase); + //Look up in database. + if (!db_r) + db_r = gEvent->dbLookUpByCard(sic.CardNumber); + + pRunner r=0; + + if (db_r) { + r = gEvent->getRunnerByName(db_r->getName(), db_r->getClub()); + + if ( !r ) { + vector classes; + int dist = gEvent->findBestClass(sic, classes); + + if (classes.size()==1 && dist>=-1 && dist<=1) { //Almost perfect match found. Assume it is it! + r = gEvent->addRunnerFromDB(db_r, classes[0]->getId(), true); + r->setCardNo(sic.CardNumber, false); + } + else r=0; //Do not assume too much... + } + } + if (r && r->getCard()==0) + return r; + else return 0; +} + +void TabSI::insertSICard(gdioutput &gdi, SICard &sic) +{ + string msg; + try { + insertSICardAux(gdi, sic); + } + catch(std::exception &ex) { + msg = ex.what(); + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + + if (!msg.empty()) + gdi.alert(msg); +} + +void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic) +{ + if (oe->isReadOnly()) { + gdi.makeEvent("ReadCard", "insertSICard", sic.CardNumber, 0, true); + return; + } + + DWORD loaded; + bool pageLoaded=gdi.getData("SIPageLoaded", loaded); + + if (pageLoaded && manualInput) + gdi.restore("ManualInput"); + + if (!pageLoaded && !insertCardNumberField.empty()) { + if (gdi.insertText(insertCardNumberField, itos(sic.CardNumber))) + return; + } + + if (mode==ModeAssignCards) { + if (!pageLoaded) { + CardQueue.push_back(sic); + gdi.addInfoBox("SIREAD", "Inläst bricka ställd i kö"); + } + else assignCard(gdi, sic); + return; + } + else if (mode==ModeEntry) { + if (!pageLoaded) { + CardQueue.push_back(sic); + gdi.addInfoBox("SIREAD", "Inläst bricka ställd i kö"); + } + else entryCard(gdi, sic); + return; + } + if (mode==ModeCheckCards) { + if (!pageLoaded) { + CardQueue.push_back(sic); + gdi.addInfoBox("SIREAD", "Inläst bricka ställd i kö"); + } + else + checkCard(gdi, sic, true); + return; + } + else if (mode == ModeCardData) { + savedCards.push_back(make_pair(savedCardUniqueId++, sic)); + + if (printSplits) { + generateSplits(savedCards.back().first, gdi); + } + if (savedCards.size() > 1 && pageLoaded) { + RECT rc = {30, gdi.getCY(), gdi.scaleLength(250), gdi.getCY() + 3}; + gdi.addRectangle(rc); + } + + if (pageLoaded) { + gdi.enableInput("CreateCompetition", true); + printCard(gdi, savedCards.back().first, false); + gdi.dropLine(); + gdi.refreshFast(); + gdi.scrollToBottom(); + } + return; + } + gEvent->synchronizeList(oLCardId, true, false); + gEvent->synchronizeList(oLRunnerId, false, true); + + if (sic.PunchOnly) { + processPunchOnly(gdi, sic); + return; + } + pRunner r; + if (sic.runnerId == 0) + r = gEvent->getRunnerByCardNo(sic.CardNumber, 0, false); + else { + r = gEvent->getRunner(sic.runnerId, 0); + sic.CardNumber = r->getCardNo(); + } + + bool readBefore = sic.runnerId == 0 ? gEvent->isCardRead(sic) : false; + + bool sameCardNewRace = !readBefore && r && r->getCard(); + + if (!pageLoaded) { + if (sic.runnerId != 0) + throw meosException("Internal error"); + //SIPage not loaded... + + if (!r && useDatabase) + r=autoMatch(sic, 0); + + // Assign a class if not already done + autoAssignClass(r, sic); + + if (interactiveReadout) { + if (r && r->getClassId() && !readBefore && !sameCardNewRace) { + //We can do a silent read-out... + processCard(gdi, r, sic, true); + return; + } + else { + CardQueue.push_back(sic); + gdi.addInfoBox("SIREAD", "info:readout_action#" + gEvent->getCurrentTimeS()+"#"+itos(sic.CardNumber), 0, SportIdentCB); + return; + } + } + else { + if (!readBefore) { + if (r && r->getClassId() && !sameCardNewRace) + processCard(gdi, r, sic, true); + else + processUnmatched(gdi, sic, true); + } + else + gdi.addInfoBox("SIREAD", "Brickan redan inläst.", 0, SportIdentCB); + } + return; + } + else if (activeSIC.CardNumber) { + //We are already in interactive mode... + + // Assign a class if not already done + autoAssignClass(r, sic); + + if (r && r->getClassId() && !readBefore && !sameCardNewRace) { + //We can do a silent read-out... + processCard(gdi, r, sic, true); + return; + } + + string name; + if (r) + name = " ("+r->getName()+")"; + + //char bf[256]; + //sprintf_s(bf, 256, "SI-%d inläst%s.\nBrickan har ställts i kö.", sic.CardNumber, name.c_str()); + name = itos(sic.CardNumber) + name; + CardQueue.push_back(sic); + //gdi.addInfoBox("SIREAD", gEvent->getCurrentTimeS()+": "+bf); + gdi.addInfoBox("SIREAD", "info:readout_queue#" + gEvent->getCurrentTimeS()+ "#" + name); + return; + } + + if (readBefore) { + //We stop processing of new cards, while working... + // Thus cannot be in interactive mode + activeSIC=sic; + char bf[256]; + + if (interactiveReadout) { + sprintf_s(bf, 256, "SI X är redan inläst. Ska den läsas in igen?#%d", sic.CardNumber); + + if (!gdi.ask(bf)) { + if (printSplits) { + pRunner runner = oe->getRunnerByCardNo(sic.CardNumber, 0); + if (runner) + generateSplits(runner, gdi); + } + activeSIC.clear(0); + if (manualInput) + showManualInput(gdi); + checkMoreCardsInQueue(gdi); + return; + } + } + else { + if (printSplits) { + pRunner runner = oe->getRunnerByCardNo(sic.CardNumber, 0); + if (runner) + generateSplits(runner, gdi); + } + + gdi.dropLine(); + sprintf_s(bf, 256, "SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen.#%d", sic.CardNumber); + gdi.addString("", 0, bf).setColor(colorRed); + gdi.dropLine(); + gdi.scrollToBottom(); + gdi.refresh(); + activeSIC.clear(0); + checkMoreCardsInQueue(gdi); + return; + } + } + + pRunner db_r = 0; + if (sic.runnerId == 0) { + r = gEvent->getRunnerByCardNo(sic.CardNumber, 0, !readBefore); + + if (!r && useDatabase) { + //Look up in database. + db_r = gEvent->dbLookUpByCard(sic.CardNumber); + if (db_r) + r = autoMatch(sic, db_r); + } + } + + // If there is no class, auto create + if (interactiveReadout && oe->getNumClasses()==0) { + gdi.fillDown(); + gdi.dropLine(); + gdi.addString("", 1, "Skapar saknad klass").setColor(colorGreen); + gdi.dropLine(); + pCourse pc=gEvent->addCourse(lang.tl("Okänd klass")); + for(unsigned i=0;iaddControl(sic.Punch[i].Code); + gEvent->addClass(lang.tl("Okänd klass"), pc->getId())->setType("tmp"); + } + + // Assign a class if not already done + autoAssignClass(r, sic); + + if (r && r->getClassId() && !r->getCard()) { + SICard copy = sic; + activeSIC.clear(0); + processCard(gdi, r, copy); //Everyting is OK + if (gdi.isChecked("UseManualInput")) + showManualInput(gdi); + } + else { + if (interactiveReadout) { + startInteractive(gdi, sic, r, db_r); + } + else { + SICard copy = sic; + activeSIC.clear(0); + processUnmatched(gdi, sic, !pageLoaded); + } + } +} + +void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunner db_r) +{ + if (!r) { + gdi.setRestorePoint(); + gdi.fillDown(); + gdi.dropLine(); + char bf[256]; + sprintf_s(bf, 256, "SI X inläst. Brickan är inte knuten till någon löpare (i skogen).#%d", sic.CardNumber); + + gdi.dropLine(); + gdi.addString("", 1, bf); + gdi.dropLine(); + gdi.fillRight(); + gdi.pushX(); + + gdi.addCombo("Runners", 200, 300, SportIdentCB, "Namn:"); + gEvent->fillRunners(gdi, "Runners", false, oEvent::RunnerFilterOnlyNoResult); + + if (db_r){ + gdi.setText("Runners", db_r->getName()); //Data from DB + } + else if (sic.FirstName[0] || sic.LastName[0]){ //Data from SI-card + gdi.setText("Runners", string(sic.FirstName)+" "+sic.LastName); + } + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + gdi.addCombo("Club", 200, 300, 0, "Klubb:"); + gEvent->fillClubs(gdi, "Club"); + + if (db_r) + gdi.setText("Club", db_r->getClub()); //Data from DB + } + if (gdi.getText("Runners").empty() || !gdi.hasField("Club")) + gdi.setInputFocus("Runners"); + else + gdi.setInputFocus("Club"); + + //Process this card. + activeSIC=sic; + gdi.dropLine(); + gdi.setRestorePoint("restOK1"); + gdi.addButton("OK1", "OK", SportIdentCB).setDefault(); + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel(); + gdi.popX(); + gdi.addString("FindMatch", 0, "").setColor(colorGreen); + gdi.registerEvent("AutoComplete", SportIdentCB).setKeyCommand(KC_AUTOCOMPLETE); + gdi.dropLine(); + gdi.scrollToBottom(); + gdi.refresh(); + } + else { + //Process this card. + activeSIC=sic; + + //No class. Select... + gdi.setRestorePoint(); + + char bf[256]; + sprintf_s(bf, 256, "SI X inläst. Brickan tillhör Y som saknar klass.#%d#%s", + sic.CardNumber, r->getName().c_str()); + + gdi.dropLine(); + gdi.addString("", 1, bf); + + gdi.fillRight(); + gdi.pushX(); + + gdi.addSelection("Classes", 200, 300, 0, "Klass:"); + gEvent->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterNone); + gdi.setInputFocus("Classes"); + //Find matching class... + vector classes; + gEvent->findBestClass(sic, classes); + if (classes.size() > 0) + gdi.selectItemByData("Classes", classes[0]->getId()); + + gdi.dropLine(); + + gdi.addButton("OK4", "OK", SportIdentCB).setDefault(); + gdi.fillDown(); + + gdi.popX(); + gdi.setData("RunnerId", r->getId()); + gdi.scrollToBottom(); + gdi.refresh(); + } +} + +// Insert card without converting times and with/without runner +void TabSI::processInsertCard(const SICard &sic) +{ + if (oe->isCardRead(sic)) + return; + + pRunner runner = oe->getRunnerByCardNo(sic.CardNumber, 0, true); + pCard card = oe->allocateCard(runner); + card->setReadId(sic); + card->setCardNo(sic.CardNumber); + + if (sic.CheckPunch.Code!=-1) + card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0); + + if (sic.StartPunch.Code!=-1) + card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0); + + for(unsigned i=0;iaddPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0); + + if (sic.FinishPunch.Code!=-1) + card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time,0 ); + + //Update to SQL-source + card->synchronize(); + + if (runner) { + vector mp; + runner->addPunches(card, mp); + } +} + +bool TabSI::processUnmatched(gdioutput &gdi, const SICard &csic, bool silent) +{ + SICard sic(csic); + pCard card=gEvent->allocateCard(0); + + card->setReadId(csic); + card->setCardNo(csic.CardNumber); + + char bf[16]; + _itoa_s(sic.CardNumber, bf, 16, 10); + string cardno(bf); + + string info=lang.tl("Okänd bricka ") + cardno + "."; + string warnings; + + // Write read card to log + logCard(sic); + + // Convert punch times to relative times. + gEvent->convertTimes(sic); + + if (sic.CheckPunch.Code!=-1) + card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0); + + if (sic.StartPunch.Code!=-1) + card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0); + + for(unsigned i=0;iaddPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0); + + if (sic.FinishPunch.Code!=-1) + card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time, 0); + else + warnings+=lang.tl("Målstämpling saknas."); + + //Update to SQL-source + card->synchronize(); + + RECT rc; + rc.left=15; + rc.right=gdi.getWidth()-10; + rc.top=gdi.getCY()+gdi.getLineHeight()-5; + rc.bottom=rc.top+gdi.getLineHeight()*2+14; + + if (!silent) { + gdi.fillDown(); + //gdi.dropLine(); + gdi.addRectangle(rc, colorLightRed, true); + gdi.addStringUT(rc.top+6, rc.left+20, 1, info); + //gdi.dropLine(); + if (gdi.isChecked("UseManualInput")) + showManualInput(gdi); + + gdi.scrollToBottom(); + } + else { + gdi.addInfoBox("SIINFO", "#" + info, 10000); + } + gdi.makeEvent("DataUpdate", "sireadout", 0, 0, true); + + checkMoreCardsInQueue(gdi); + return true; +} + +void TabSI::rentCardInfo(gdioutput &gdi, int width) +{ + RECT rc; + rc.left=15; + rc.right=rc.left+width; + rc.top=gdi.getCY()-7; + rc.bottom=rc.top+gdi.getLineHeight()+5; + + gdi.addRectangle(rc, colorYellow, true); + gdi.addString("", rc.top+2, rc.left+width/2, 1|textCenter, "Vänligen återlämna hyrbrickan."); +} + +bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool silent) +{ + if (!runner) + return false; + if (runner->getClubId()) + lastClubId = runner->getClubId(); + + runner = runner->getMatchedRunner(csic); + + int lh=gdi.getLineHeight(); + //Update from SQL-source + runner->synchronize(); + + if (!runner->getClassId()) + runner->setClassId(gEvent->addClass(lang.tl("Okänd klass"))->getId(), true); + + // Choose course from pool + pClass cls=gEvent->getClass(runner->getClassId()); + if (cls && cls->hasCoursePool()) { + unsigned leg=runner->legToRun(); + + if (leggetNumStages()) { + pCourse c = cls->selectCourseFromPool(leg, csic); + if (c) + runner->setCourseId(c->getId()); + } + } + + if (cls && cls->hasUnorderedLegs()) { + pCourse crs = cls->selectParallelCourse(*runner, csic); + if (crs) { + runner->setCourseId(crs->getId()); + runner->synchronize(true); + } + } + + pClass pclass=gEvent->getClass(runner->getClassId()); + if (!runner->getCourse(false) && !csic.isManualInput()) { + + if (pclass && !pclass->hasMultiCourse() && !pclass->hasDirectResult()) { + pCourse pcourse=gEvent->addCourse(runner->getClass()); + pclass->setCourse(pcourse); + + for(unsigned i=0;iaddControl(csic.Punch[i].Code); + + char msg[256]; + + sprintf_s(msg, lang.tl("Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d)").c_str(), + pclass->getName().c_str(), csic.nPunch, csic.CardNumber); + + if (silent) + gdi.addInfoBox("SIINFO", string("#") + msg, 15000); + else + gdi.addStringUT(0, msg); + } + else { + if (!(pclass && pclass->hasDirectResult())) { + const char *msg="Löpare saknar klass eller bana"; + + if (silent) + gdi.addInfoBox("SIINFO", msg, 15000); + else + gdi.addString("", 0, msg); + } + } + } + + pCourse pcourse=runner->getCourse(false); + + if (pcourse) + pcourse->synchronize(); + else if (pclass && pclass->hasDirectResult()) + runner->setStatus(StatusOK, true, false, false); + //silent=true; + SICard sic(csic); + string info, warnings, cardno; + vector MP; + + if (!csic.isManualInput()) { + pCard card=gEvent->allocateCard(runner); + + card->setReadId(csic); + card->setCardNo(sic.CardNumber); + + char bf[16]; + _itoa_s(sic.CardNumber, bf, 16, 10); + cardno = bf; + + info=runner->getName() + " (" + cardno + "), " + runner->getClub() + ", " + runner->getClass(); + + // Write read card to log + logCard(sic); + + // Convert punch times to relative times. + oe->convertTimes(sic); + pCourse prelCourse = runner->getCourse(false); + const int finishPT = prelCourse ? prelCourse->getFinishPunchType() : oPunch::PunchFinish; + bool hasFinish = false; + + if (sic.CheckPunch.Code!=-1) + card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time,0); + + if (sic.StartPunch.Code!=-1) + card->addPunch(oPunch::PunchStart, sic.StartPunch.Time,0); + + for(unsigned i=0;iaddPunch(sic.Punch[i].Code, sic.Punch[i].Time,0); + } + if (sic.FinishPunch.Code!=-1) { + card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time,0); + if (finishPT == oPunch::PunchFinish) + hasFinish = true; + } + + if (!hasFinish) + warnings+=lang.tl("Målstämpling saknas."); + + card->synchronize(); + runner->addPunches(card, MP); + runner->hasManuallyUpdatedTimeStatus(); + } + else { + //Manual input + info = runner->getName() + ", " + runner->getClub() + ", " + runner->getClass(); + runner->setCard(0); + + if (csic.statusOK) { + runner->setStatus(StatusOK, true, false); + runner->setFinishTime(csic.relativeFinishTime); + } + else if (csic.statusDNF) { + runner->setStatus(StatusDNF, true, false); + runner->setFinishTime(0); + } + else { + runner->setStatus(StatusMP, true, false); + runner->setFinishTime(csic.relativeFinishTime); + } + + cardno = MakeDash("-"); + runner->evaluateCard(true, MP, false, false); + runner->hasManuallyUpdatedTimeStatus(); + } + + //Update to SQL-source + runner->synchronize(); + + RECT rc; + rc.left=15; + rc.right=gdi.getWidth()-10; + rc.top=gdi.getCY()+gdi.getLineHeight()-5; + rc.bottom=rc.top+gdi.getLineHeight()*2+14; + + if (!warnings.empty()) + rc.bottom+=gdi.getLineHeight(); + + if (runner->getStatus()==StatusOK) { + gEvent->calculateResults(oEvent::RTClassResult); + if (runner->getTeam()) + gEvent->calculateTeamResults(runner->getLegNumber(), false); + string placeS = runner->getTeam() ? runner->getTeam()->getLegPlaceS(runner->getLegNumber(), false) : runner->getPlaceS(); + + if (!silent) { + gdi.fillDown(); + //gdi.dropLine(); + gdi.addRectangle(rc, colorLightGreen, true); + + gdi.addStringUT(rc.top+6, rc.left+20, 1, info); + if (!warnings.empty()) + gdi.addStringUT(rc.top+6+2*lh, rc.left+20, 0, warnings); + + string statusline = lang.tl("Status OK, ") + + lang.tl("Tid: ") + runner->getRunningTimeS() + + lang.tl(", Prel. placering: ") + placeS; + + + statusline += lang.tl(", Prel. bomtid: ") + runner->getMissedTimeS(); + gdi.addStringUT(rc.top+6+lh, rc.left+20, 0, statusline); + + if (runner->getDI().getInt("CardFee") != 0) + rentCardInfo(gdi, rc.right-rc.left); + gdi.scrollToBottom(); + } + else { + string msg="#" + runner->getName() + " (" + cardno + ")\n"+ + runner->getClub()+". "+runner->getClass() + + "\n" + lang.tl("Tid: ") + runner->getRunningTimeS() + lang.tl(", Plats ") + placeS; + + gdi.addInfoBox("SIINFO", msg, 10000); + } + } + else { + string msg=lang.tl("Status")+": "+ lang.tl(runner->getStatusS()); + + if (!MP.empty()) { + msg=msg+", ("; + vector::iterator it; + char bf[32]; + + for(it=MP.begin(); it!=MP.end(); ++it){ + _itoa_s(*it, bf, 32, 10); + msg=msg+bf+" "; + } + msg+=" "+lang.tl("saknas")+".)"; + } + + if (!silent) { + gdi.fillDown(); + gdi.dropLine(); + gdi.addRectangle(rc, colorLightRed, true); + + gdi.addStringUT(rc.top+6, rc.left+20, 1, info); + if (!warnings.empty()) + gdi.addStringUT(rc.top+6+lh*2, rc.left+20, 1, warnings); + + gdi.addStringUT(rc.top+6+lh, rc.left+20, 0, msg); + + if (runner->getDI().getInt("CardFee") != 0) + rentCardInfo(gdi, rc.right-rc.left); + + gdi.scrollToBottom(); + } + else { + string statusmsg="#" + runner->getName() + " (" + cardno + ")\n"+ + runner->getClub()+". "+runner->getClass() + + "\n" + msg; + + gdi.addInfoBox("SIINFO", statusmsg, 10000); + } + } + + tabForceSync(gdi, gEvent); + gdi.makeEvent("DataUpdate", "sireadout", runner ? runner->getId() : 0, 0, true); + + // Print splits + if (printSplits) + generateSplits(runner, gdi); + + activeSIC.clear(&csic); + + checkMoreCardsInQueue(gdi); + return true; +} + +void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic) +{ + SICard sic=csic; + DWORD loaded; + gEvent->convertTimes(sic); + oFreePunch *ofp=0; + + if (sic.nPunch==1) + ofp=gEvent->addFreePunch(sic.Punch[0].Time, sic.Punch[0].Code, sic.CardNumber, true); + else if (sic.FinishPunch.Time > 0) + ofp=gEvent->addFreePunch(sic.FinishPunch.Time, oPunch::PunchFinish, sic.CardNumber, true); + else if (sic.StartPunch.Time > 0) + ofp=gEvent->addFreePunch(sic.StartPunch.Time, oPunch::PunchStart, sic.CardNumber, true); + else + ofp=gEvent->addFreePunch(sic.CheckPunch.Time, oPunch::PunchCheck, sic.CardNumber, true); + + if (ofp) { + pRunner r = ofp->getTiedRunner(); + if (gdi.getData("SIPageLoaded", loaded)){ + //gEvent->getRunnerByCard(sic.CardNumber); + + if (r) { + string str=r->getName() + lang.tl(" stämplade vid ") + ofp->getSimpleString(); + gdi.addStringUT(0, str); + gdi.dropLine(); + } + else { + string str="SI " + itos(sic.CardNumber) + lang.tl(" (okänd) stämplade vid ") + ofp->getSimpleString(); + gdi.addStringUT(0, str); + gdi.dropLine(0.3); + } + gdi.scrollToBottom(); + } + + tabForceSync(gdi, gEvent); + gdi.makeEvent("DataUpdate", "sireadout", r ? r->getId() : 0, 0, true); + + } + + checkMoreCardsInQueue(gdi); + return; +} + + +void TabSI::entryCard(gdioutput &gdi, const SICard &sic) +{ + gdi.setText("CardNo", sic.CardNumber); + + string name; + string club; + if (useDatabase) { + pRunner db_r=oe->dbLookUpByCard(sic.CardNumber); + + if (db_r) { + name=db_r->getNameRaw(); + club=db_r->getClub(); + } + } + + //Else get name from card + if (name.empty() && (sic.FirstName[0] || sic.LastName[0])) + name=string(sic.LastName) + ", " + string(sic.FirstName); + + gdi.setText("Name", name); + if (gdi.hasField("Club")) + gdi.setText("Club", club); + + if (name.empty()) + gdi.setInputFocus("Name"); + else if (club.empty() && gdi.hasField("Club")) + gdi.setInputFocus("Club"); + else + gdi.setInputFocus("Class"); +} + +void TabSI::assignCard(gdioutput &gdi, const SICard &sic) +{ + + if (interactiveReadout) { + pRunner rb = oe->getRunner(runnerMatchedId, 0); + + if (rb && oe->checkCardUsed(gdi, *rb, sic.CardNumber)) + return; + + gdi.setText("CardNo", sic.CardNumber); + if (runnerMatchedId != -1 && gdi.isChecked("AutoTie")) + tieCard(gdi); + return; + } + + int storedAssigneIndex = currentAssignIndex; + //Try first current focus + BaseInfo *ii=gdi.getInputFocus(); + char sicode[32]; + sprintf_s(sicode, "%d", sic.CardNumber); + + if (ii && ii->id[0]=='*') { + currentAssignIndex=atoi(ii->id.c_str()+1); + } + else { //If not correct focus, use internal counter + char id[32]; + sprintf_s(id, "*%d", currentAssignIndex++); + + ii=gdi.setInputFocus(id); + + if (!ii) { + currentAssignIndex=0; + sprintf_s(id, "*%d", currentAssignIndex++); + ii=gdi.setInputFocus(id); + } + } + + if (ii && ii->getExtraInt()) { + pRunner r=oe->getRunner(ii->getExtraInt(), 0); + if (r) { + if (oe->checkCardUsed(gdi, *r, sic.CardNumber)) { + currentAssignIndex = storedAssigneIndex; + return; + } + if (r->getCardNo()==0 || + gdi.ask("Skriv över existerande bricknummer?")) { + + r->setCardNo(sic.CardNumber, false); + r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee")); + r->synchronize(); + gdi.setText(ii->id, sicode); + } + } + gdi.TabFocus(); + } + + checkMoreCardsInQueue(gdi); +} + +void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) +{ + oe->synchronizeList(oLRunnerId, true, false); + oe->synchronizeList(oLCardId, false, true); + + gdi.restore("EntryLine", false); + gdi.setRestorePoint("EntryLine"); + gdi.dropLine(1); + int xb = gdi.getCX(); + int yb = gdi.getCY(); + gdi.dropLine(); + gdi.setCX(xb + gdi.scaleLength(10)); + + gdi.fillRight(); + + gdi.pushX(); + storedInfo.checkAge(); + gdi.addInput("CardNo", storedInfo.storedCardNo, 8, SportIdentCB, "Bricka:"); + + gdi.addInput("Name", storedInfo.storedName, 16, 0, "Namn:"); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + gdi.addCombo("Club", 180, 200, 0, "Klubb:", "Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben"); + oe->fillClubs(gdi, "Club"); + if (storedInfo.storedClub.empty()) + gdi.selectItemByData("Club", lastClubId); + else + gdi.setText("Club", storedInfo.storedClub); + } + + gdi.addSelection("Class", 150, 200, 0, "Klass:"); + oe->fillClasses(gdi, "Class", oEvent::extraNumMaps, oEvent::filterOnlyDirect); + if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) { + } + else if (!gdi.selectItemByData("Class", lastClassId)) { + gdi.selectFirstItem("Class"); + } + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) { + gdi.addCombo("Fee", 60, 150, SportIdentCB, "Anm. avgift:"); + oe->fillFees(gdi, "Fee", false); + + if (!storedInfo.storedFee.empty() && storedInfo.storedFee != "@") + gdi.setText("Fee", storedInfo.storedFee); + else + gdi.setText("Fee", lastFee); + + gdi.dropLine(1.2); + generatePayModeWidget(gdi); + gdi.dropLine(-1.2); + } + + gdi.popX(); + gdi.dropLine(3.1); + + gdi.addString("",0, "Starttid:"); + gdi.dropLine(-0.2); + gdi.addInput("StartTime", storedInfo.storedStartTime, 5, 0, ""); + + gdi.setCX(gdi.getCX()+gdi.scaleLength(50)); + gdi.dropLine(0.2); + gdi.setCX(gdi.getCX()+gdi.scaleLength(5)); + + gdi.addString("", 0, "Telefon:"); + gdi.dropLine(-0.2); + gdi.addInput("Phone", storedInfo.storedPhone, 12, 0, ""); + gdi.dropLine(0.2); + + gdi.setCX(gdi.getCX()+gdi.scaleLength(50)); + + gdi.addCheckbox("RentCard", "Hyrbricka", SportIdentCB, storedInfo.rentState); + if (oe->hasNextStage()) + gdi.addCheckbox("AllStages", "Anmäl till efterföljande etapper", SportIdentCB, storedInfo.allStages); + + if (r!=0) { + if (r->getCardNo()>0) + gdi.setText("CardNo", r->getCardNo()); + + gdi.setText("Name", r->getNameRaw()); + if (gdi.hasField("Club")) { + gdi.selectItemByData("Club", r->getClubId()); + } + gdi.selectItemByData("Class", r->getClassId()); + + oDataConstInterface dci = r->getDCI(); + if (gdi.hasField("Fee")) + gdi.setText("Fee", oe->formatCurrency(dci.getInt("Fee"))); + + gdi.setText("Phone", dci.getString("Phone")); + + gdi.check("RentCard", dci.getInt("CardFee") != 0); + if (gdi.hasField("Paid")) + gdi.check("Paid", dci.getInt("Paid")>0); + else if (gdi.hasField("PayMode")) { + int paidId = dci.getInt("Paid") > 0 ? r->getPaymentMode() : 1000; + gdi.selectItemByData("PayMode", paidId); + } + + if (gdi.hasField("AllStages")) { + gdi.check("AllStages", r->hasFlag(oRunner::FlagTransferNew)); + } + } + + gdi.popX(); + gdi.dropLine(2); + gdi.addButton("EntryOK", "OK", SportIdentCB).setDefault().setExtra(r ? r->getId() : 0); + gdi.addButton("EntryCancel", "Avbryt", SportIdentCB).setCancel(); + gdi.dropLine(0.1); + gdi.addString("EntryInfo", fontMediumPlus, "").setColor(colorDarkRed); + updateEntryInfo(gdi); + gdi.setInputFocus("CardNo"); + gdi.dropLine(2); + + RECT rc = {xb, yb, gdi.getWidth(), gdi.getHeight()}; + gdi.addRectangle(rc, colorLightCyan); + gdi.scrollToBottom(); + gdi.popX(); + gdi.setOnClearCb(SportIdentCB); +} + +void TabSI::updateEntryInfo(gdioutput &gdi) +{ + int fee = oe->interpretCurrency(gdi.getText("Fee", true)); + if (gdi.isChecked("RentCard")) { + int cardFee = oe->getDI().getInt("CardFee"); + if (cardFee > 0) + fee += cardFee; + } + if (gdi.isChecked("AllStages")) { + int nums = oe->getNumStages(); + int cs = oe->getStageNumber(); + if (nums > 0 && cs <= nums) { + int np = nums - cs + 1; + fee *= np; + } + + } + + string method; + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) { + bool invoice = true; + if (gdi.hasField("PayMode")) { + invoice = gdi.getSelectedItem("PayMode").first == 1000; + } + else + invoice = !gdi.isChecked("Paid"); + + if (!invoice) + method = lang.tl("Att betala"); + else + method = lang.tl("Faktureras"); + + gdi.setText("EntryInfo", lang.tl("X: Y. Tryck för att spara#" + + method + "#" + oe->formatCurrency(fee)), true); + } + else { + gdi.setText("EntryInfo", lang.tl("Press Enter to continue"), true); + + } +} + +void TabSI::generateSplits(const pRunner r, gdioutput &gdi) +{ + const bool wideFormat = oe->getPropertyInt("WideSplitFormat", 0) == 1; + if (wideFormat) { + addToPrintQueue(r); + while(checkpPrintQueue(gdi)); + } + else { + gdioutput gdiprint(2.0, gdi.getEncoding(), gdi.getHWND(), splitPrinter); + vector mp; + r->evaluateCard(true, mp); + r->printSplits(gdiprint); + printProtected(gdi, gdiprint); + //gdiprint.print(splitPrinter, oe, false, true); + } +} + +void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) { + if (printStartInfo) { + gdioutput gdiprint(2.0, gdi.getEncoding(), gdi.getHWND(), splitPrinter); + r.printStartInfo(gdiprint); + printProtected(gdi, gdiprint); + //gdiprint.print(splitPrinter, oe, false, true); + } +} + +void TabSI::printerSetup(gdioutput &gdi) +{ + gdi.printSetup(splitPrinter); +} + +void TabSI::checkMoreCardsInQueue(gdioutput &gdi) { + // Create a local list to avoid stack overflow + list cards = CardQueue; + CardQueue.clear(); + std::exception storedEx; + bool fail = false; + + while (!cards.empty()) { + SICard c = cards.front(); + cards.pop_front(); + try { + gdi.RemoveFirstInfoBox("SIREAD"); + insertSICard(gdi, c); + } + catch (std::exception &ex) { + fail = true; + storedEx = ex; + } + } + + if (fail) + throw storedEx; +} + +bool TabSI::autoAssignClass(pRunner r, const SICard &sic) { + if (r && r->getClassId()==0) { + vector classes; + int dist = oe->findBestClass(sic, classes); + + if (classes.size() == 1 && dist>=-1 && dist<=1) // Allow at most one wrong punch + r->setClassId(classes[0]->getId(), true); + } + + return r && r->getClassId() != 0; +} + +void TabSI::showManualInput(gdioutput &gdi) { + runnerMatchedId = -1; + gdi.setRestorePoint("ManualInput"); + gdi.fillDown(); + gdi.dropLine(0.7); + + int x = gdi.getCX(); + int y = gdi.getCY(); + + gdi.setCX(x+gdi.scaleLength(15)); + gdi.dropLine(); + gdi.addString("", 1, "Manuell inmatning"); + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addInput("Manual", "", 20, SportIdentCB, "Nummerlapp, SI eller Namn:"); + gdi.addInput("FinishTime", lang.tl("Aktuell tid"), 8, SportIdentCB, "Måltid:").setFgColor(colorGreyBlue).setExtra(1); + gdi.dropLine(1.2); + gdi.addCheckbox("StatusOK", "Godkänd", SportIdentCB, true); + gdi.addCheckbox("StatusDNF", "Utgått", SportIdentCB, false); + gdi.dropLine(-0.3); + gdi.addButton("ManualOK", "OK", SportIdentCB).setDefault(); + gdi.fillDown(); + gdi.dropLine(2); + gdi.popX(); + gdi.addString("FindMatch", 0, "", 0).setColor(colorDarkGreen); + gdi.dropLine(); + + RECT rc; + rc.left=x; + rc.right=gdi.getWidth()-10; + rc.top=y; + rc.bottom=gdi.getCY()+gdi.scaleLength(5); + gdi.dropLine(); + gdi.addRectangle(rc, colorLightBlue); + //gdi.refresh(); + gdi.scrollToBottom(); +} + +void TabSI::tieCard(gdioutput &gdi) { + int card = gdi.getTextNo("CardNo"); + pRunner r = oe->getRunner(runnerMatchedId, 0); + + if (r == 0) + throw meosException("Invalid binding"); + + if (oe->checkCardUsed(gdi, *r, card)) + return; + + if (r->getCardNo() > 0 && r->getCardNo() != card) { + if (!gdi.ask("X har redan bricknummer Y. Vill du ändra det?#" + r->getName() + "#" + itos(r->getCardNo()))) + return; + } + + bool rent = gdi.isChecked("RentCardTie"); + r->setCardNo(card, true, false); + r->getDI().setInt("CardFee", rent ? oe->getDI().getInt("CardFee") : 0); + r->synchronize(true); + + gdi.restore("ManualTie"); + gdi.pushX(); + gdi.fillRight(); + gdi.addStringUT(italicText, getLocalTimeOnly()); + if (!r->getBib().empty()) + gdi.addStringUT(0, r->getBib(), 0); + gdi.addStringUT(0, r->getName(), 0); + + if (r->getTeam() && r->getTeam()->getName() != r->getName()) + gdi.addStringUT(0, "(" + r->getTeam()->getName() + ")", 0); + else if (!r->getClub().empty()) + gdi.addStringUT(0, "(" + r->getClub() + ")", 0); + + gdi.addStringUT(1, itos(r->getCardNo()), 0).setColor(colorDarkGreen); + gdi.addString("EditAssign", 0, "Ändra", SportIdentCB).setExtra(r->getId()); + gdi.dropLine(1.5); + gdi.popX(); + + showAssignCard(gdi, false); +} + +void TabSI::showAssignCard(gdioutput &gdi, bool showHelp) { + gdi.enableInput("Interactive"); + gdi.disableInput("Database", true); + gdi.disableInput("PrintSplits"); + gdi.disableInput("StartInfo"); + gdi.disableInput("UseManualInput"); + gdi.setRestorePoint("ManualTie"); + gdi.fillDown(); + if (interactiveReadout) { + if (showHelp) + gdi.addString("", 10, "Avmarkera 'X' för att hantera alla bricktildelningar samtidigt.#" + lang.tl("Interaktiv inläsning")); + } + else { + if (showHelp) + gdi.addString("", 10, "Markera 'X' för att hantera deltagarna en och en.#" + lang.tl("Interaktiv inläsning")); + gEvent->assignCardInteractive(gdi, SportIdentCB); + gdi.refresh(); + return; + } + + runnerMatchedId = -1; + gdi.fillDown(); + gdi.dropLine(0.7); + + int x = gdi.getCX(); + int y = gdi.getCY(); + + gdi.setCX(x+gdi.scaleLength(15)); + gdi.dropLine(); + gdi.addString("", 1, "Knyt bricka / deltagare"); + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addInput("RunnerId", "", 20, SportIdentCB, "Nummerlapp, lopp-id eller namn:"); + gdi.addInput("CardNo", "", 8, SportIdentCB, "Bricknr:"); + gdi.dropLine(1.2); + gdi.addCheckbox("AutoTie", "Knyt automatiskt efter inläsning", SportIdentCB, oe->getPropertyInt("AutoTie", 1) != 0); + gdi.addCheckbox("RentCardTie", "Hyrd", SportIdentCB, oe->getPropertyInt("RentCard", 0) != 0); + + gdi.dropLine(-0.3); + gdi.addButton("TieOK", "OK", SportIdentCB).setDefault(); + gdi.disableInput("TieOK"); + gdi.setInputFocus("RunnerId"); + gdi.fillDown(); + gdi.dropLine(2); + gdi.popX(); + gdi.addString("FindMatch", 0, "", 0).setColor(colorDarkGreen); + gdi.dropLine(); + + RECT rc; + rc.left=x; + rc.right=gdi.getWidth()+gdi.scaleLength(5); + rc.top=y; + rc.bottom=gdi.getCY()+gdi.scaleLength(5); + gdi.dropLine(); + gdi.addRectangle(rc, colorLightBlue); + gdi.scrollToBottom(); +} + +pRunner TabSI::getRunnerByIdentifier(int identifier) const { + int id; + if (identifierToRunnerId.lookup(identifier, id)) { + pRunner r = oe->getRunner(id, 0); + if (r && r->getRaceIdentifier() == identifier) + return r; + else + minRunnerId = 0; // Map is out-of-date + } + + if (identifier < minRunnerId) + return 0; + + minRunnerId = MAXINT; + identifierToRunnerId.clear(); + + pRunner ret = 0; + vector runners; + oe->autoSynchronizeLists(false); + oe->getRunners(0, 0, runners, false); + for ( size_t k = 0; k< runners.size(); k++) { + if (runners[k]->getRaceNo() == 0) { + int i = runners[k]->getRaceIdentifier(); + identifierToRunnerId.insert(i, runners[k]->getId()); + minRunnerId = min(minRunnerId, i); + if (i == identifier) + ret = runners[k]; + } + } + return ret; +} + +bool TabSI::askOverwriteCard(gdioutput &gdi, pRunner r) const { + return gdi.ask("ask:overwriteresult#" + r->getCompleteIdentification()); +} + +void TabSI::showModeCardData(gdioutput &gdi) { + gdi.disableInput("Interactive", true); + gdi.enableInput("Database", true); + gdi.enableInput("PrintSplits"); + gdi.disableInput("StartInfo", true); + gdi.disableInput("UseManualInput", true); + + gdi.dropLine(); + gdi.fillDown(); + gdi.pushX(); + gdi.addString("", boldLarge, "Print Card Data"); + gdi.addString("", 10, "help:analyzecard"); + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("ClearMemory", "Clear Memory", SportIdentCB); + gdi.addButton("SaveMemory", "Spara...", SportIdentCB); + if (oe->empty()) { + gdi.addButton("CreateCompetition", "Create Competition", SportIdentCB); + if (savedCards.empty()) + gdi.disableInput("CreateCompetition"); + } + gdi.dropLine(3); + gdi.popX(); + bool first = true; + for (list >::iterator it = savedCards.begin(); it != savedCards.end(); ++it) { + gdi.dropLine(0.5); + if (!first) { + RECT rc = {30, gdi.getCY(), gdi.scaleLength(250), gdi.getCY() + 3}; + gdi.addRectangle(rc); + } + first = false; + + printCard(gdi, it->first, false); + } +} + +void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) { + if (type == GUI_LINK) { + TextInfo &ti = dynamic_cast(info); + int cardId = ti.getExtraInt(); + SICard &card = tabSI->getCard(cardId); + ti.id = "card" + itos(cardId); + gdi.removeControl("CardName"); + gdi.removeControl("ClubName"); + gdi.removeControl("OKCard"); + gdi.removeControl("CancelCard"); + + string name, club; + if (card.FirstName[0]) + name = card.FirstName + (card.LastName[0] ? (" " + string(card.LastName)) : ""); + club = card.Club; + bool noName = name.empty(); + bool noClub = club.empty(); + if (noName) + name = lang.tl("Namn"); + if (noClub) + club = lang.tl("Klubb"); + + InputInfo &ii = gdi.addInput(ti.xp-2, ti.yp-2, "CardName", name, 18, 0); + ii.setHandler(this); + InputInfo &ii2 = gdi.addInput(ti.xp + ii.getWidth(), ti.yp-2, "ClubName", club, 22, 0); + ii2.setExtra(noClub).setHandler(this); + ButtonInfo &bi = gdi.addButton(ii2.getX() + 2 + ii2.getWidth(), ti.yp-4, "OKCard", "OK", 0); + bi.setExtra(cardId).setHandler(this); + bi.setDefault(); + int w, h; + bi.getDimension(gdi, w, h); + gdi.addButton(bi.xp + w + 4, ti.yp-4, "CancelCard", "Avbryt", 0).setCancel().setHandler(this); + gdi.setInputFocus(ii.id, noName); + } + else if (type == GUI_BUTTON) { + ButtonInfo bi = dynamic_cast(info); + //OKCard or CancelCard + if (bi.id == "OKCard") { + int cardId = bi.getExtraInt(); + SICard &card = tabSI->getCard(cardId); + string name = gdi.getText("CardName"); + string club = gdi.getBaseInfo("ClubName").getExtra() ? "" : gdi.getText("ClubName"); + string given = getGivenName(name); + string familty = getFamilyName(name); + strncpy_s(card.FirstName, given.c_str(), sizeof(card.FirstName)-1); + strncpy_s(card.LastName, familty.c_str(), sizeof(card.LastName)-1); + strncpy_s(card.Club, club.c_str(), sizeof(card.Club)-1); + + string s = name; + if (!club.empty()) + s += ", " + club; + gdi.setText("card" + itos(cardId), s, true); + } + + gdi.removeControl("CardName"); + gdi.removeControl("ClubName"); + gdi.removeControl("OKCard"); + gdi.removeControl("CancelCard"); + } + else if (type == GUI_FOCUS) { + InputInfo &ii = dynamic_cast(info); + if (ii.getExtraInt()) { + ii.setExtra(0); + gdi.setInputFocus(ii.id, true); + } + } +} + + +void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const { + SICard &c = getCard(cardId); + if (c.readOutTime[0] == 0) + strcpy_s(c.readOutTime, getLocalTime().c_str()); + + gdi.pushX(); + gdi.fillRight(); + string name, clubName; + if (c.FirstName[0] != 0) { + name = string(c.FirstName) + " " + c.LastName; + clubName = c.Club; + } + else { + const RunnerDBEntry *r = oe->getRunnerDatabase().getRunnerByCard(c.CardNumber); + if (r) { + r->getName(name); + const oClub *club = oe->getRunnerDatabase().getClub(r->clubNo); + if (club) { + clubName = club->getName(); + strncpy_s(c.Club, clubName.c_str(), sizeof(c.Club)-1); + } + string given = r->getGivenName(); + string family = r->getFamilyName(); + strncpy_s(c.FirstName, given.c_str(), sizeof(c.FirstName)-1); + strncpy_s(c.LastName, family.c_str(), sizeof(c.LastName)-1); + } + } + + gdi.addString("", 1, "Bricka X#" + itos(c.CardNumber)); + + if (!forPrinter && name.empty()) + name = lang.tl("Okänd"); + + if (!name.empty()) { + if (!clubName.empty()) + name += ", " + clubName; + gdi.fillDown(); + gdi.addStringUT(0, name).setExtra(cardId).setHandler(&editCardData); + gdi.popX(); + } + gdi.fillDown(); + gdi.addStringUT(0, c.readOutTime); + gdi.popX(); + + int start = NOTIME; + if (c.CheckPunch.Code != -1) + gdi.addString("", 0, "Check: X#" + formatTimeHMS(c.CheckPunch.Time)); + + if (c.StartPunch.Code != -1) { + gdi.addString("", 0, "Start: X#" + formatTimeHMS(c.StartPunch.Time)); + start = c.StartPunch.Time; + } + int xp = gdi.getCX(); + int xp2 = xp + gdi.scaleLength(25); + int xp3 = xp2 + gdi.scaleLength(35); + int xp4 = xp3 + gdi.scaleLength(60); + int xp5 = xp4 + gdi.scaleLength(45); + + int accTime = 0; + int days = 0; + for (unsigned k = 0; k < c.nPunch; k++) { + int cy = gdi.getCY(); + gdi.addStringUT(cy, xp, 0, itos(k+1) + "."); + gdi.addStringUT(cy, xp2, 0, itos(c.Punch[k].Code)); + gdi.addStringUT(cy, xp3, 0, formatTimeHMS(c.Punch[k].Time % (24*3600))); + if (start != NOTIME) { + int legTime = analyzePunch(c.Punch[k], start, accTime, days); + if (legTime > 0) + gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTime(legTime)); + + gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days*3600*24 + accTime)); + } + else { + start = c.Punch[k].Time; + } + } + if (c.FinishPunch.Code != -1) { + int cy = gdi.getCY(); + gdi.addString("", cy, xp, 0, "Mål"); + gdi.addStringUT(cy, xp3, 0, formatTimeHMS(c.FinishPunch.Time % (24*3600))); + + if (start != NOTIME) { + int legTime = analyzePunch(c.FinishPunch, start, accTime, days); + if (legTime > 0) + gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTime(legTime)); + + gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days*3600*24 + accTime)); + } + gdi.addString("", 1, "Time: X#" + formatTime(days*3600*24 + accTime)); + } + + if (forPrinter) { + gdi.dropLine(1); + + vector< pair > lines; + oe->getExtraLines("SPExtra", lines); + + for (size_t k = 0; k < lines.size(); k++) { + gdi.addStringUT(lines[k].second, lines[k].first); + } + if (lines.size()>0) + gdi.dropLine(0.5); + + gdi.addString("", fontSmall, "Av MeOS: www.melin.nu/meos"); + } +} + +int TabSI::analyzePunch(SIPunch &p, int &start, int &accTime, int &days) { + int newAccTime = p.Time - start; + if (newAccTime < 0) { + newAccTime += 3600 * 24; + if (accTime > 12 * 3600) + days++; + } + else if (newAccTime < accTime - 12 * 3600) { + days++; + } + int legTime = newAccTime - accTime; + accTime = newAccTime; + return legTime; +} + +void TabSI::generateSplits(int cardId, gdioutput &gdi) { + gdioutput gdiprint(2.0, gdi.getEncoding(), gdi.getHWND(), splitPrinter); + printCard(gdiprint, cardId, true); + printProtected(gdi, gdiprint); +} + +void TabSI::printProtected(gdioutput &gdi, gdioutput &gdiprint) { + try { + gdiprint.print(splitPrinter, oe, false, true); + } + catch (meosException &ex) { + DWORD loaded; + if (gdi.getData("SIPageLoaded", loaded)) { + gdi.dropLine(); + gdi.fillDown(); + gdi.addString("", 0, ex.what(), 0).setColor(colorRed); + gdi.dropLine(); + gdi.scrollToBottom(); + } + else { + if (!printErrorShown) { + printErrorShown = true; + gdi.alert(ex.what()); + printErrorShown = false; + } + } + } +} + +void TabSI::createCompetitionFromCards(gdioutput &gdi) { + oe->newCompetition(lang.tl("Ny tävling")); + gdi.setWindowTitle(""); + map hashCount; + vector< pair > cards; + int zeroTime = 3600 * 24; + for (list >::iterator it = savedCards.begin(); it != savedCards.end(); ++it) { + size_t hash = 0; + if (it->second.StartPunch.Code != -1 && it->second.StartPunch.Time > 0) + zeroTime = min(zeroTime, it->second.StartPunch.Time); + + for (unsigned k = 0; k < it->second.nPunch; k++) { + hash = 997 * hash + (it->second.Punch[k].Code-30); + if (it->second.Punch[k].Code != -1 && it->second.Punch[k].Time > 0) + zeroTime = min(zeroTime, it->second.Punch[k].Time); + } + pair p(hash, &it->second); + ++hashCount[hash]; + cards.push_back(p); + } + + zeroTime -= 3600; + if (zeroTime < 0) + zeroTime += 3600 * 24; + zeroTime -= zeroTime % 1800; + oe->setZeroTime(formatTime(zeroTime)); + + int course = 0; + for (size_t k = 0; k < cards.size(); k++) { + if (!hashCount.count(cards[k].first)) + continue; + int count = hashCount[cards[k].first]; + if (count < 5 && count < int(cards.size()) /2) + continue; + + pCourse pc = oe->addCourse(lang.tl("Bana ") + itos(++course)); + for (unsigned j = 0; j < cards[k].second->nPunch; j++) { + pc->addControl(cards[k].second->Punch[j].Code); + } + oe->addClass(lang.tl("Klass ") + itos(course), pc->getId()); + hashCount.erase(cards[k].first); + } + + // Add remaining classes if suitable + for (size_t k = 0; k < cards.size(); k++) { + if (!hashCount.count(cards[k].first)) + continue; + int count = hashCount[cards[k].first]; + if (count == 1) + continue; // Don't allow singelton runner classes + + vector cls; + int dist = oe->findBestClass(*cards[k].second, cls); + + if (abs(dist) > 3) { + pCourse pc = oe->addCourse(lang.tl("Bana ") + itos(++course)); + for (unsigned j = 0; j < cards[k].second->nPunch; k++) { + pc->addControl(cards[k].second->Punch[j].Code); + } + oe->addClass(lang.tl("Klass ") + itos(course), pc->getId()); + hashCount.erase(cards[k].first); + } + } + + // Add competitors + for (size_t k = 0; k < cards.size(); k++) { + if (oe->isCardRead(*cards[k].second)) + continue; + + vector cls; + oe->findBestClass(*cards[k].second, cls); + + if (!cls.empty()) { + string name; + if (cards[k].second->FirstName[0]) + name = string(cards[k].second->FirstName); + if (cards[k].second->LastName[0]) + name += " " + string(cards[k].second->LastName); + + if (name.empty()) + name = lang.tl("Bricka X#" + itos(cards[k].second->CardNumber)); + + oe->addRunner(name, string(cards[k].second->Club), cls[0]->getId(), + cards[k].second->CardNumber, 0, true); + + processInsertCard(*cards[k].second); + } + } + + TabList &tc = dynamic_cast(*gdi.getTabs().get(TListTab)); + tc.loadPage(gdi, "ResultIndividual"); +} + +void TabSI::StoredStartInfo::checkAge() { + DWORD t = GetTickCount(); + const int minuteLimit = 3; + if (t > age && (t - age) > (1000*60*minuteLimit)) { + clear(); + } + age = t; +} + +void TabSI::StoredStartInfo::clear() { + age = GetTickCount(); + storedName.clear(); + storedCardNo.clear(); + storedClub.clear(); + storedFee.clear(); + storedPhone.clear(); + rentState = false; + storedStartTime.clear(); + hasPaid = false; + payMode = 1000; + //allStages = lastAllStages; // Always use last setting + storedClassId = 0; +} + +void TabSI::clearCompetitionData() { + savedCardUniqueId = 1; + checkedCardFlags.clear(); + currentAssignIndex = 0; +} + +SICard &TabSI::getCard(int id) const { + if (id < int(savedCards.size() / 2)) { + for (list< pair >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it){ + if (it->first==id) + return const_cast(it->second); + } + } + else { + for (list< pair >::const_reverse_iterator it = savedCards.rbegin(); it != savedCards.rend(); ++it){ + if (it->first==id) + return const_cast(it->second); + } + } + throw meosException("Interal error"); +} + +bool compareCardNo(const pRunner &r1, const pRunner &r2) { + int c1 = r1->getCardNo(); + int c2 = r2->getCardNo(); + if (c1 != c2) + return c1 < c2; + int f1 = r1->getFinishTime(); + int f2 = r2->getFinishTime(); + if (f1 != f2) + return f1 < f2; + + return false; +} + +string TabSI::getCardInfo(bool param, vector &count) const { + if (!param) { + assert(count.size() == 8); + return "Totalt antal unika avbockade brickor: X#" + itos(count[CNFCheckedAndUsed] + + count[CNFChecked] + + count[CNFCheckedNotRented] + + count[CNFCheckedRentAndNotRent]); + } + count.clear(); + count.resize(8); + for (map::const_iterator it = checkedCardFlags.begin(); + it != checkedCardFlags.end(); ++it) { + ++count[it->second]; + } + + string msg = "Uthyrda: X, Egna: Y, Avbockade uthyrda: Z#" + itos(count[CNFUsed] + count[CNFCheckedAndUsed]) + + "#" + itos(count[CNFNotRented] + count[CNFCheckedNotRented]) + + "#" + itos(count[CNFCheckedAndUsed]); + + return msg; +} + +void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) { + vector r; + const int cx = gdi.getCX(); + const int col1 = gdi.scaleLength(50); + const int col2 = gdi.scaleLength(200); + + if (cmd == "init") { + gdi.disableInput("Interactive"); + gdi.disableInput("Database"); + gdi.disableInput("PrintSplits"); + gdi.disableInput("UseManualInput"); + gdi.fillDown(); + gdi.addString("", 10, "help:checkcards"); + + gdi.dropLine(); + gdi.fillRight(); + gdi.pushX(); + gdi.addButton("CCSReport", "Rapport", SportIdentCB); + gdi.addButton("CCSClear", "Nollställ", SportIdentCB, + "Nollställ minnet; markera alla brickor som icke avbockade"); + gdi.addButton("CCSPrint", "Skriv ut...", SportIdentCB); + + gdi.popX(); + gdi.dropLine(3); + gdi.fillDown(); + gdi.setRestorePoint("CCSInit"); + showCheckCardStatus(gdi, "fillrunner"); + showCheckCardStatus(gdi, "stat"); + showCheckCardStatus(gdi, "tickoff"); + return; + } + else if (cmd == "fillrunner") { + oe->getRunners(0, 0, r); + + for (size_t k = 0; k < r.size(); k++) { + int cno = r[k]->getCardNo(); + if (cno == 0) + continue; + int cf = checkedCardFlags[cno]; + if (r[k]->getDI().getInt("CardFee") != 0) + checkedCardFlags[cno] = CardNumberFlags(cf | CNFUsed); + else + checkedCardFlags[cno] = CardNumberFlags(cf | CNFNotRented); + } + } + else if (cmd == "stat") { + vector count; + gdi.addString("CardInfo", fontMediumPlus, getCardInfo(true, count)); + gdi.addString("CardTicks", 0, getCardInfo(false, count)); + if (count[CNFCheckedRentAndNotRent] + count[CNFRentAndNotRent] > 0) { + oe->getRunners(0, 0, r); + stable_sort(r.begin(), r.end(), compareCardNo); + gdi.dropLine(); + string msg = "Brickor markerade som både uthyrda och egna: X#" + itos(count[CNFCheckedRentAndNotRent] + count[CNFRentAndNotRent]); + gdi.addString("", 1, msg).setColor(colorDarkRed); + gdi.dropLine(0.5); + for (size_t k = 0; k < r.size(); k++) { + int cno = r[k]->getCardNo(); + if (cno == 0 || r[k]->getRaceNo() > 0) + continue; + + if (checkedCardFlags[cno] == CNFCheckedRentAndNotRent || + checkedCardFlags[cno] == CNFRentAndNotRent) { + int yp = gdi.getCY(); + string cp = r[k]->getCompleteIdentification(); + bool rent = r[k]->getDI().getInt("CardFee") != 0; + string info = rent ? (" (" + lang.tl("Hyrd") + ")") : ""; + gdi.addStringUT(yp, cx, 0, itos(cno) + info); + gdi.addStringUT(yp, cx + col2, 0, cp); + } + } + } + } + else if (cmd == "report") { + oe->getRunners(0, 0, r); + stable_sort(r.begin(), r.end(), compareCardNo); + bool showHead = false; + int count = 0; + for (size_t k = 0; k < r.size(); k++) { + int cno = r[k]->getCardNo(); + if (cno == 0) + continue; + if (r[k]->getRaceNo() > 0) + continue; + CardNumberFlags f = checkedCardFlags[cno]; + if (f == CNFRentAndNotRent || f == CNFUsed) { + if (!showHead) { + gdi.dropLine(); + string msg = "Uthyrda brickor som inte avbockats"; + gdi.addString("", fontMediumPlus, msg); + gdi.fillDown(); + gdi.dropLine(0.5); + showHead = true; + } + int yp = gdi.getCY(); + gdi.addStringUT(yp, cx, 0, itos(++count)); + gdi.addStringUT(yp, cx + col1, 0, itos(cno)); + string cp = r[k]->getCompleteIdentification(); + + if (r[k]->getStatus() != StatusUnknown) + cp += " " + r[k]->getStatusS(); + else + cp += MakeDash(" -"); + + int s = r[k]->getStartTime(); + int f = r[k]->getFinishTime(); + if (s> 0 || f>0) { + cp += ", " + (s>0 ? r[k]->getStartTimeS() : string("?")) + MakeDash(" - ") + + (f>0 ? r[k]->getFinishTimeS() : string("?")); + } + gdi.addStringUT(yp, cx + col2, 0, cp); + } + } + + if (!showHead) { + gdi.dropLine(); + string msg = "Alla uthyrda brickor har bockats av."; + gdi.addString("", fontMediumPlus, msg).setColor(colorGreen); + } + } + else if (cmd == "tickoff") { + SICard sic; + sic.clear(0); + for (map::const_iterator it = checkedCardFlags.begin(); + it != checkedCardFlags.end(); ++it) { + int stat = it->second; + if (stat & CNFChecked) { + sic.CardNumber = it->first; + checkCard(gdi, sic, false); + } + } + gdi.refresh(); + return; + } + checkHeader = false; + gdi.dropLine(); +} + +void TabSI::checkCard(gdioutput &gdi, const SICard &card, bool updateAll) { + bool wasChecked = (checkedCardFlags[card.CardNumber] & CNFChecked) != 0 && updateAll; + + checkedCardFlags[card.CardNumber] = CardNumberFlags(checkedCardFlags[card.CardNumber] | CNFChecked); + vector count; + if (!checkHeader) { + checkHeader = true; + gdi.addString("", fontMediumPlus, "Avbockade brickor:"); + gdi.dropLine(0.5); + cardPosX = gdi.getCX(); + cardPosY = gdi.getCY(); + cardOffsetX = gdi.scaleLength(60); + cardNumCol = 12; + cardCurrentCol = 0; + } + + if (updateAll) { + gdi.setTextTranslate("CardInfo", getCardInfo(true, count)); + gdi.setTextTranslate("CardTicks", getCardInfo(false, count)); + } + TextInfo &ti = gdi.addStringUT(cardPosY, cardPosX + cardCurrentCol * cardOffsetX, 0, itos(card.CardNumber)); + if (wasChecked) + ti.setColor(colorRed); + if (++cardCurrentCol >= cardNumCol) { + cardCurrentCol = 0; + cardPosY += gdi.getLineHeight(); + } + + if (updateAll) { + gdi.scrollToBottom(); + gdi.refreshFast(); + } +} + +void TabSI::generatePayModeWidget(gdioutput &gdi) const { + vector< pair > pm; + oe->getPayModes(pm); + assert(pm.size() > 0); + if (pm.size() == 1) { + assert(pm[0].second == 0); + gdi.addCheckbox("Paid", "#" + pm[0].first, SportIdentCB, storedInfo.hasPaid); + } + else { + pm.insert(pm.begin(), make_pair(lang.tl("Faktureras"), 1000)); + gdi.addSelection("PayMode", 110, 100, SportIdentCB); + gdi.addItem("PayMode", pm); + gdi.selectItemByData("PayMode", storedInfo.payMode); + gdi.autoGrow("PayMode"); + } +} + +bool TabSI::writePayMode(gdioutput &gdi, int amount, oRunner &r) { + int paid = 0; + bool hasPaid = false; + + if (gdi.hasField("PayMode")) + hasPaid = gdi.getSelectedItem("PayMode").first != 1000; + + bool fixPay = gdi.isChecked("Paid"); + if (hasPaid || fixPay) { + paid = amount; + } + + r.getDI().setInt("Paid", paid); + if (hasPaid) { + r.setPaymentMode(gdi.getSelectedItem("PayMode").first); + } + return hasPaid || fixPay; +} + +void TabSI::addToPrintQueue(pRunner r) { + unsigned t = GetTickCount(); + printPunchRunnerIdQueue.push_back(make_pair(t, r->getId())); +} + +bool TabSI::checkpPrintQueue(gdioutput &gdi) { + if (printPunchRunnerIdQueue.empty()) + return false; + size_t printLen = oe->getPropertyInt("NumSplitsOnePage", 3); + if (printPunchRunnerIdQueue.size() < printLen) { + unsigned t = GetTickCount(); + unsigned diff = abs(int(t - printPunchRunnerIdQueue.front().first))/1000; + + if (diff < (unsigned)oe->getPropertyInt("SplitPrintMaxWait", 60)) + return false; // Wait a little longer + } + + gdioutput gdiprint(2.0, gdi.getEncoding(), gdi.getHWND(), splitPrinter); + vector mp; + for (size_t m = 0; m < printLen && !printPunchRunnerIdQueue.empty(); m++) { + int rid = printPunchRunnerIdQueue.front().second; + printPunchRunnerIdQueue.pop_front(); + pRunner r = oe->getRunner(rid, 0); + if (r) { + r->evaluateCard(true, mp); + r->printSplits(gdiprint); + } + gdiprint.dropLine(4); + } + + printProtected(gdi, gdiprint); + //gdiprint.print(splitPrinter, oe, false, true); + return true; +} + +void TabSI::printSIInfo(gdioutput &gdi, const string &port) const { + vector info; + gdi.fillDown(); + gSI->getInfoString(port, info); + for (size_t j = 0; j < info.size(); j++) + gdi.addStringUT(0, info[j]); +} diff --git a/code/TabSI.h b/code/TabSI.h new file mode 100644 index 0000000..438bb86 --- /dev/null +++ b/code/TabSI.h @@ -0,0 +1,229 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "tabbase.h" +#include "SportIdent.h" +#include "Printer.h" +#include "inthashmap.h" + +struct PunchInfo; +class csvparser; + +class TabSI : public TabBase { + public: + enum SIMode { + ModeReadOut, + ModeAssignCards, + ModeCheckCards, + ModeEntry, + ModeCardData + }; + +private: + /** Try to automatcally assign a class to runner (if none is given) + Return true if runner has a class on exist */ + bool autoAssignClass(pRunner r, const SICard &sic); + + void checkMoreCardsInQueue(gdioutput &gdi); + + pRunner autoMatch(const SICard &sic, pRunner db_r); + void processPunchOnly(gdioutput &gdi, const SICard &sic); + void startInteractive(gdioutput &gdi, const SICard &sic, + pRunner r, pRunner db_r); + bool processCard(gdioutput &gdi, pRunner runner, const SICard &csic, + bool silent=false); + bool processUnmatched(gdioutput &gdi, const SICard &csic, bool silent); + + void rentCardInfo(gdioutput &gdi, int width); + + bool interactiveReadout; + bool useDatabase; + bool printSplits; + bool printStartInfo; + bool manualInput; + PrinterObject splitPrinter; + list< pair > printPunchRunnerIdQueue; + void addToPrintQueue(pRunner r); + + vector punches; + vector cards; + vector filterDate; + + int runnerMatchedId; + bool printErrorShown; + void printProtected(gdioutput &gdi, gdioutput &gdiprint); + + //Interactive card assign + SIMode mode; + int currentAssignIndex; + + void printSIInfo(gdioutput &gdi, const string &port) const; + + void assignCard(gdioutput &gdi, const SICard &sic); + void entryCard(gdioutput &gdi, const SICard &sic); + + void updateEntryInfo(gdioutput &gdi); + void generateEntryLine(gdioutput &gdi, pRunner r); + int lastClassId; + int lastClubId; + string lastFee; + int inputId; + + void showCheckCardStatus(gdioutput &gdi, const string &cmd); + + string getCardInfo(bool param, vector &count) const; + // Formatting for card tick off + bool checkHeader; + int cardPosX; + int cardPosY; + int cardOffsetX; + int cardNumCol; + int cardCurrentCol; + + enum CardNumberFlags { + // Basic flags + CNFChecked = 1, + CNFUsed = 2, + CNFNotRented = 4, + + // Combinations + CNFCheckedAndUsed = 3, + CNFCheckedNotRented = 5, + CNFRentAndNotRent = 6, + CNFCheckedRentAndNotRent = 7, + }; + + map checkedCardFlags; + void checkCard(gdioutput &gdi, const SICard &sic, bool updateAll); + + void showReadPunches(gdioutput &gdi, vector &punches, set &dates); + void showReadCards(gdioutput &gdi, vector &cards); + + void showManualInput(gdioutput &gdi); + void showAssignCard(gdioutput &gdi, bool showHelp); + + pRunner getRunnerByIdentifier(int id) const; + mutable inthashmap identifierToRunnerId; + mutable int minRunnerId; + void tieCard(gdioutput &gdi); + + // Insert card without converting times and with/without runner + void processInsertCard(const SICard &csic); + + + void generateSplits(const pRunner r, gdioutput &gdi); + int logcounter; + csvparser *logger; + + string insertCardNumberField; + + void insertSICardAux(gdioutput &gdi, SICard &sic); + + // Ask if card is to be overwritten + bool askOverwriteCard(gdioutput &gdi, pRunner r) const; + + list< pair > savedCards; + int savedCardUniqueId; + SICard &getCard(int id) const; + + void showModeCardData(gdioutput &gdi); + + void printCard(gdioutput &gdi, int cardId, bool forPrinter) const; + void generateSplits(int cardId, gdioutput &gdi); + + static int analyzePunch(SIPunch &p, int &start, int &accTime, int &days); + + + void createCompetitionFromCards(gdioutput &gdi); + + int NC; + + class EditCardData : public GuiHandler { + TabSI *tabSI; + EditCardData(const EditCardData&); + EditCardData &operator=(const EditCardData&); + public: + EditCardData() : tabSI(0) {} + void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type); + friend class TabSI; + }; + EditCardData editCardData; + +protected: + void clearCompetitionData(); + +public: + + // Returns true if a repeated check should be done (there is more to print) + bool checkpPrintQueue(gdioutput &gdi); + + struct StoredStartInfo { + string storedName; + string storedCardNo; + string storedClub; + string storedFee; + string storedPhone; + string storedStartTime; + bool allStages; + bool rentState; + bool hasPaid; + int payMode; + DWORD age; + int storedClassId; + + void clear(); + void checkAge(); + StoredStartInfo() : rentState(false), age(0), storedClassId(0), hasPaid(0), payMode(0), allStages(false) {} + }; + + StoredStartInfo storedInfo; + void generatePayModeWidget(gdioutput &gdi) const; + static bool writePayMode(gdioutput &gdi, int amount, oRunner &r); + + static SportIdent &getSI(const gdioutput &gdi); + void printerSetup(gdioutput &gdi); + + void generateStartInfo(gdioutput &gdi, const oRunner &r); + bool hasPrintStartInfo() const {return printStartInfo;} + void setPrintStartInfo(bool info) {printStartInfo = info;} + + int siCB(gdioutput &gdi, int type, void *data); + + void logCard(const SICard &card); + + void setCardNumberField(const string &fieldId) {insertCardNumberField=fieldId;} + + //SICard CSIC; + SICard activeSIC; + list CardQueue; + + const char * getTypeStr() const {return "TSITab";} + TabType getType() const {return TSITab;} + + void insertSICard(gdioutput &gdi, SICard &sic); + + void refillComPorts(gdioutput &gdi); + + bool loadPage(gdioutput &gdi); + TabSI(oEvent *oe); + ~TabSI(void); +}; diff --git a/code/TabSpeaker.cpp b/code/TabSpeaker.cpp new file mode 100644 index 0000000..78f5da9 --- /dev/null +++ b/code/TabSpeaker.cpp @@ -0,0 +1,1048 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "gdifonts.h" + +#include "csvparser.h" +#include "SportIdent.h" +#include "meos_util.h" +#include "oListInfo.h" + +#include "TabSpeaker.h" +#include "TabList.h" +#include "speakermonitor.h" + +#include + +//Base position for speaker buttons +#define SPEAKER_BASE_X 40 + +TabSpeaker::TabSpeaker(oEvent *poe):TabBase(poe) +{ + classId=0; + ownWindow = false; + + lastControlToWatch = 0; + lastClassToWatch = 0; + watchLevel = oTimeLine::PMedium; + watchNumber = 5; + speakerMonitor = 0; +} + +TabSpeaker::~TabSpeaker() +{ + delete speakerMonitor; +} + + +int tabSpeakerCB(gdioutput *gdi, int type, void *data) +{ + TabSpeaker &ts = dynamic_cast(*gdi->getTabs().get(TSpeakerTab)); + + switch(type){ + case GUI_BUTTON: { + //Make a copy + ButtonInfo bu=*static_cast(data); + return ts.processButton(*gdi, bu); + } + case GUI_LISTBOX:{ + ListBoxInfo lbi=*static_cast(data); + return ts.processListBox(*gdi, lbi); + } + case GUI_EVENT: { + EventInfo ei=*static_cast(data); + return ts.handleEvent(*gdi, ei); + } + case GUI_CLEAR: + return ts.onClear(*gdi); + case GUI_TIMEOUT: + case GUI_TIMER: + ts.updateTimeLine(*gdi); + break; + } + return 0; +} + +int TabSpeaker::handleEvent(gdioutput &gdi, const EventInfo &ei) +{ + updateTimeLine(gdi); + return 0; +} + +int TabSpeaker::processButton(gdioutput &gdi, const ButtonInfo &bu) +{ + if (bu.id=="Settings") { + if (controlsToWatch.empty()) { + // Get default + vector ctrl; + oe->getControls(ctrl, true); + for (size_t k = 0; k < ctrl.size(); k++) { + if (ctrl[k]->isValidRadio()) { + vector cc; + ctrl[k]->getCourseControls(cc); + controlsToWatch.insert(cc.begin(), cc.end()); + } + } + } + gdi.restore("settings"); + gdi.unregisterEvent("DataUpdate"); + gdi.fillDown(); + gdi.addString("", boldLarge, "Speakerstöd"); + gdi.addString("", 0, "help:speaker_setup"); + gdi.dropLine(1); + gdi.addCheckbox("ShortNames", "Use initials in names", 0, oe->getPropertyInt("SpeakerShortNames", false) != 0); + gdi.dropLine(0.5); + + gdi.pushX(); + gdi.fillRight(); + gdi.addListBox("Classes", 200, 300, 0,"Klasser","", true); + + oe->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterNone); + gdi.setSelection("Classes", classesToWatch); + + gdi.addListBox("Controls", 200, 300, 0, "Kontroller","", true); + gdi.pushX(); + gdi.fillDown(); + + vector< pair > d; + oe->fillControls(d, oEvent::CTCourseControl); + gdi.addItem("Controls", d); + + gdi.setSelection("Controls", controlsToWatch); + + gdi.dropLine(); + gdi.addButton("OK", "OK", tabSpeakerCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", tabSpeakerCB).setCancel(); + + gdi.refresh(); + } + else if (bu.id=="ZoomIn") { + gdi.scaleSize(1.05); + } + else if (bu.id=="ZoomOut") { + gdi.scaleSize(1.0/1.05); + } + else if (bu.id=="Manual") { + gdi.unregisterEvent("DataUpdate"); + gdi.restore("settings"); + gdi.fillDown(); + gdi.addString("", boldLarge, "Inmatning av mellantider"); + gdi.dropLine(0.5); + manualTimePage(gdi); + } + else if (bu.id == "PunchTable") { + gdi.clearPage(false); + gdi.addButton("Cancel", "Stäng", tabSpeakerCB); + gdi.dropLine(); + gdi.addTable(oe->getPunchesTB(), gdi.getCX(), gdi.getCY()); + gdi.refresh(); + } + else if (bu.id == "Priority") { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Bevakningsprioritering"); + gdi.addString("", 10, "help:speakerprio"); + gdi.dropLine(); + gdi.fillRight(); + gdi.pushX(); + gdi.addString("", 0, "Klass:"); + gdi.addSelection("Class", 200, 200, tabSpeakerCB, "", "Välj klass"); + oe->fillClasses(gdi, "Class", oEvent::extraNone, oEvent::filterNone); + gdi.addButton("ClosePri", "Stäng", tabSpeakerCB); + gdi.dropLine(2); + gdi.popX(); + gdi.refresh(); + } + else if (bu.id == "ClosePri") { + savePriorityClass(gdi); + loadPage(gdi); + } + else if (bu.id == "LiveResult") { + gdioutput *gdi_new = createExtraWindow(uniqueTag("list"), MakeDash("MeOS - Live"), gdi.getWidth() + 64 + gdi.scaleLength(120)); + + gdi_new->clearPage(false); + gdi_new->addString("", boldLarge, "Liveresultat"); + gdi_new->addString("", 10, "help:liveresultat"); + gdi_new->dropLine(); + gdi_new->pushY(); + gdi_new->pushX(); + + TabList::makeClassSelection(*gdi_new); + oe->fillClasses(*gdi_new, "ListSelection", oEvent::extraNone, oEvent::filterNone); + + gdi_new->popY(); + gdi_new->setCX(gdi_new->getCX() + gdi_new->scaleLength(280)); + gdi_new->fillRight(); + gdi_new->pushX(); + TabList::makeFromTo(*gdi_new); + TabList::enableFromTo(*oe, *gdi_new, true, true); + + gdi_new->fillRight(); + gdi.dropLine(); + gdi_new->addButton("StartLive", "Starta", tabSpeakerCB).setDefault(); + gdi_new->addButton("CancelClose", "Avbryt", tabSpeakerCB).setCancel(); + + gdi_new->refresh(); + } + else if (bu.id == "StartLive") { + TabList &ts = dynamic_cast(*gdi.getTabs().get(TListTab)); + + oListInfo li; + oListParam &par = li.getParam();; + par.useControlIdResultTo = gdi.getSelectedItem("ResultSpecialTo").first; + par.useControlIdResultFrom = gdi.getSelectedItem("ResultSpecialFrom").first; + gdi.getSelection("ListSelection", par.selection); + + gdi.clearPage(false); + gdi.setFullScreen(true); + gdi.hideBackground(true); + ts.liveResult(gdi, li); + } + else if (bu.id == "Events") { + gdi.restore("classes"); + /* + shownEvents.clear(); + events.clear(); + */ + drawTimeLine(gdi); + } + else if (bu.id == "Window") { + oe->setupTimeLineEvents(0); + + gdioutput *gdi_new = createExtraWindow(uniqueTag("speaker"), MakeDash("MeOS - Speakerstöd"), gdi.getWidth() + 64 + gdi.scaleLength(120)); + if (gdi_new) { + TabSpeaker &tl = dynamic_cast(*gdi_new->getTabs().get(TSpeakerTab)); + tl.ownWindow = true; + tl.loadPage(*gdi_new); + //oe->renderTimeLineEvents(*gdi_new); + } + } + else if (bu.id=="StoreTime") { + storeManualTime(gdi); + } + else if (bu.id=="Cancel") { + loadPage(gdi); + } + else if (bu.id=="CancelClose") { + gdi.closeWindow(); + } + else if (bu.id=="OK") { + gdi.getSelection("Classes", classesToWatch); + gdi.getSelection("Controls", controlsToWatch); + if (controlsToWatch.empty()) + controlsToWatch.insert(-2); // Non empty but no control + + controlsToWatchSI.clear(); + for (set::iterator it=controlsToWatch.begin();it!=controlsToWatch.end();++it) { + pControl pc=oe->getControl(*it, false); + if (pc) { + pc->setRadio(true); + pc->synchronize(true); + controlsToWatchSI.insert(pc->Numbers, pc->Numbers+pc->nNumbers); + } + } + oe->setProperty("SpeakerShortNames", (int)gdi.isChecked("ShortNames")); + loadPage(gdi); + } + else if (bu.id.substr(0, 3)=="cid" ) { + classId=atoi(bu.id.substr(3, string::npos).c_str()); + bool shortNames = oe->getPropertyInt("SpeakerShortNames", false) != 0; + generateControlList(gdi, classId); + gdi.setRestorePoint("speaker"); + gdi.setRestorePoint("SpeakerList"); + + if (selectedControl.count(classId)==1) + oe->speakerList(gdi, classId, selectedControl[classId].getLeg(), + selectedControl[classId].getControl(), + selectedControl[classId].getPreviousControl(), + selectedControl[classId].isTotal(), + shortNames); + } + else if (bu.id.substr(0, 4)=="ctrl") { + bool shortNames = oe->getPropertyInt("SpeakerShortNames", false) != 0; + int ctrl = atoi(bu.id.substr(4, string::npos).c_str()); + int ctrlPrev = bu.getExtraInt(); + selectedControl[classId].setControl(ctrl, ctrlPrev); + gdi.restore("speaker"); + oe->speakerList(gdi, classId, selectedControl[classId].getLeg(), ctrl, ctrlPrev, + selectedControl[classId].isTotal(), shortNames); + } + + return 0; +} + +void TabSpeaker::drawTimeLine(gdioutput &gdi) { + gdi.restoreNoUpdate("SpeakerList"); + gdi.setRestorePoint("SpeakerList"); + + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(0.3); + gdi.addString("", 0, "Filtrering:"); + gdi.dropLine(-0.2); + gdi.addSelection("DetailLevel", 160, 100, tabSpeakerCB); + gdi.addItem("DetailLevel", lang.tl("Alla händelser"), oTimeLine::PLow); + gdi.addItem("DetailLevel", lang.tl("Viktiga händelser"), oTimeLine::PMedium); + gdi.addItem("DetailLevel", lang.tl("Avgörande händelser"), oTimeLine::PHigh); + gdi.selectItemByData("DetailLevel", watchLevel); + + gdi.dropLine(0.2); + gdi.addString("", 0, "Antal:"); + gdi.dropLine(-0.2); + gdi.addSelection("WatchNumber", 160, 200, tabSpeakerCB); + gdi.addItem("WatchNumber", lang.tl("X senaste#5"), 5); + gdi.addItem("WatchNumber", lang.tl("X senaste#10"), 10); + gdi.addItem("WatchNumber", lang.tl("X senaste#20"), 20); + gdi.addItem("WatchNumber", lang.tl("X senaste#50"), 50); + gdi.addItem("WatchNumber", "Alla", 0); + gdi.selectItemByData("WatchNumber", watchNumber); + gdi.dropLine(2); + gdi.popX(); + + string cls; + for (set::iterator it = classesToWatch.begin(); it != classesToWatch.end(); ++it) { + pClass pc = oe->getClass(*it); + if (pc) { + if (!cls.empty()) + cls += ", "; + cls += oe->getClass(*it)->getName(); + } + } + gdi.fillDown(); + gdi.addString("", 1, "Bevakar händelser i X#" + cls); + gdi.dropLine(); + + gdi.setRestorePoint("TimeLine"); + updateTimeLine(gdi); +} + +void TabSpeaker::updateTimeLine(gdioutput &gdi) { + int storedY = gdi.GetOffsetY(); + int storedHeight = gdi.getHeight(); + bool refresh = gdi.hasData("TimeLineLoaded"); + + if (refresh) + gdi.takeShownStringsSnapshot(); + + gdi.restoreNoUpdate("TimeLine"); + gdi.setRestorePoint("TimeLine"); + gdi.setData("TimeLineLoaded", 1); + + gdi.registerEvent("DataUpdate", tabSpeakerCB); + gdi.setData("DataSync", 1); + gdi.setData("PunchSync", 1); + + gdi.pushX(); gdi.pushY(); + gdi.updatePos(0,0,0, storedHeight); + gdi.popX(); gdi.popY(); + gdi.SetOffsetY(storedY); + + SpeakerMonitor &sm = *getSpeakerMonitor(); + int limit = 1000; + switch (watchLevel) { + case oTimeLine::PHigh: + limit = 3; + break; + case oTimeLine::PMedium: + limit = 10; + break; + } + + sm.setLimits(limit, watchNumber); + sm.setClassFilter(classesToWatch, controlsToWatch); + sm.show(gdi); + + if (refresh) + gdi.refreshSmartFromSnapshot(false); + else { + if (storedHeight == gdi.getHeight()) + gdi.refreshFast(); + else + gdi.refresh(); + } +} + +/* +void TabSpeaker::updateTimeLine(gdioutput &gdi) { + int storedY = gdi.GetOffsetY(); + int storedHeight = gdi.getHeight(); + bool refresh = gdi.hasData("TimeLineLoaded"); + + if (refresh) + gdi.takeShownStringsSnapshot(); + + gdi.restoreNoUpdate("TimeLine"); + gdi.setRestorePoint("TimeLine"); + gdi.setData("TimeLineLoaded", 1); + + gdi.registerEvent("DataUpdate", tabSpeakerCB); + gdi.setData("DataSync", 1); + gdi.setData("PunchSync", 1); + + gdi.pushX(); gdi.pushY(); + gdi.updatePos(0,0,0, storedHeight); + gdi.popX(); gdi.popY(); + gdi.SetOffsetY(storedY); + + int nextEvent = oe->getTimeLineEvents(classesToWatch, events, shownEvents, 0); + + oe->updateComputerTime(); + int timeOut = nextEvent * 1000 - oe->getComputerTimeMS(); + + string str = "Now: " + oe->getAbsTime(oe->getComputerTime()) + " Next:" + oe->getAbsTime(nextEvent) + " Timeout:" + itos(timeOut) + "\n"; + OutputDebugString(str.c_str()); + + if (timeOut > 0) { + gdi.addTimeoutMilli(timeOut, "timeline", tabSpeakerCB); + //gdi.addTimeout(timeOut, tabSpeakerCB); + } + bool showClass = classesToWatch.size()>1; + + oListInfo li; + const int classWidth = gdi.scaleLength(li.getMaxCharWidth(oe, classesToWatch, lClassName, "", normalText, false)); + const int timeWidth = gdi.scaleLength(60); + const int totWidth = gdi.scaleLength(450); + const int extraWidth = gdi.scaleLength(200); + string dash = MakeDash("- "); + const int extra = 5; + + int limit = watchNumber > 0 ? watchNumber : events.size(); + for (size_t k = events.size()-1; signed(k) >= 0; k--) { + oTimeLine &e = events[k]; + + if (e.getPriority() < watchLevel) + continue; + + if (--limit < 0) + break; + + int t = e.getTime(); + string msg = t>0 ? oe->getAbsTime(t) : MakeDash("--:--:--"); + pRunner r = pRunner(e.getSource(*oe)); + + RECT rc; + rc.top = gdi.getCY(); + rc.left = gdi.getCX(); + + int xp = rc.left + extra; + int yp = rc.top + extra; + + bool largeFormat = e.getPriority() >= oTimeLine::PHigh && k + 15 >= events.size(); + + if (largeFormat) { + gdi.addStringUT(yp, xp, 0, msg); + + int dx = 0; + if (showClass) { + pClass pc = oe->getClass(e.getClassId()); + if (pc) { + gdi.addStringUT(yp, xp + timeWidth, fontMediumPlus, pc->getName()); + dx = classWidth; + } + } + + if (r) { + string bib = r->getBib(); + if (!bib.empty()) + msg = bib + ", "; + else + msg = ""; + msg += r->getCompleteIdentification(); + int xlimit = totWidth + extraWidth - (timeWidth + dx); + gdi.addStringUT(yp, xp + timeWidth + dx, fontMediumPlus, msg, xlimit); + } + + yp += int(gdi.getLineHeight() * 1.5); + msg = dash + lang.tl(e.getMessage()); + gdi.addStringUT(yp, xp + 10, breakLines, msg, totWidth); + + const string &detail = e.getDetail(); + + if (!detail.empty()) { + gdi.addString("", gdi.getCY(), xp + 20, 0, detail).setColor(colorDarkGrey); + } + + if (r && e.getType() == oTimeLine::TLTFinish && r->getStatus() == StatusOK) { + splitAnalysis(gdi, xp + 20, gdi.getCY(), r); + } + + GDICOLOR color = colorLightRed; + + switch (e.getType()) { + case oTimeLine::TLTFinish: + if (r && r->statusOK()) + color = colorLightGreen; + else + color = colorLightRed; + break; + case oTimeLine::TLTStart: + color = colorLightYellow; + break; + case oTimeLine::TLTRadio: + color = colorLightCyan; + break; + case oTimeLine::TLTExpected: + color = colorLightBlue; + break; + } + + rc.bottom = gdi.getCY() + extra; + rc.right = rc.left + totWidth + extraWidth + 2 * extra; + gdi.addRectangle(rc, color, true); + gdi.dropLine(0.5); + } + else { + if (showClass) { + pClass pc = oe->getClass(e.getClassId()); + if (pc ) + msg += " (" + pc->getName() + ") "; + else + msg += " "; + } + else + msg += " "; + + if (r) { + msg += r->getCompleteIdentification() + " "; + } + msg += lang.tl(e.getMessage()); + gdi.addStringUT(gdi.getCY(), gdi.getCX(), breakLines, msg, totWidth); + + const string &detail = e.getDetail(); + + if (!detail.empty()) { + gdi.addString("", gdi.getCY(), gdi.getCX()+50, 0, detail).setColor(colorDarkGrey); + } + + if (r && e.getType() == oTimeLine::TLTFinish && r->getStatus() == StatusOK) { + splitAnalysis(gdi, xp, gdi.getCY(), r); + } + gdi.dropLine(0.5); + } + } + + if (refresh) + gdi.refreshSmartFromSnapshot(false); + else { + if (storedHeight == gdi.getHeight()) + gdi.refreshFast(); + else + gdi.refresh(); + } +} +*/ +void TabSpeaker::splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r) +{ + if (!r) + return; + + vector delta; + r->getSplitAnalysis(delta); + string timeloss = lang.tl("Bommade kontroller: "); + pCourse pc = 0; + bool first = true; + const int charlimit = 90; + for (size_t j = 0; j 0) { + if (pc == 0) { + pc = r->getCourse(true); + if (pc == 0) + break; + } + + if (!first) + timeloss += " | "; + else + first = false; + + timeloss += pc->getControlOrdinal(j) + ". " + formatTime(delta[j]); + } + if (timeloss.length() > charlimit || (!timeloss.empty() && !first && j+1 == delta.size())) { + gdi.addStringUT(yp, xp, 0, timeloss).setColor(colorDarkRed); + yp += gdi.getLineHeight(); + timeloss = ""; + } + } + if (first) { + gdi.addString("", yp, xp, 0, "Inga bommar registrerade").setColor(colorDarkGreen); + } +} + +pCourse deduceSampleCourse(pClass pc, vector &stages, int leg); + +void TabSpeaker::generateControlList(gdioutput &gdi, int classId) +{ + pClass pc=oe->getClass(classId); + + if (!pc) + return; + + bool keepLegs = false; + if (gdi.hasField("Leg")) { + DWORD clsSel = 0; + if (gdi.getData("ClassSelection", clsSel) && clsSel == pc->getId()) { + gdi.restore("LegSelection", true); + keepLegs = true; + } + } + + if (!keepLegs) + gdi.restore("classes", true); + + gdi.setData("ClassSelection", pc->getId()); + + pCourse course=0; + + int h,w; + gdi.getTargetDimension(w, h); + + gdi.fillDown(); + + int bw=gdi.scaleLength(100); + int nbtn=max((w-80)/bw, 1); + bw=(w-80)/nbtn; + int basex=SPEAKER_BASE_X; + int basey=gdi.getCY()+4; + + int cx=basex; + int cy=basey; + int cb=1; + + vector stages; + pc->getTrueStages(stages); + int leg = selectedControl[pc->getId()].getLeg(); + const bool multiDay = oe->hasPrevStage(); + + if (stages.size()>1 || multiDay) { + if (!keepLegs) { + gdi.setData("CurrentY", cy); + gdi.addSelection(cx, cy+2, "Leg", int(bw/gdi.getScale())-5, 100, tabSpeakerCB); + if (leg == 0 && stages[0].first != 0) { + leg = stages[0].first; + selectedControl[pc->getId()].setLeg(selectedControl[pc->getId()].isTotal(), leg); + } + + if (stages.size() > 1) { + for (size_t k=0; khasMultiCourse()) + course = pc->getCourse(courseLeg, 0, true); + else + course = pc->getCourse(true); + */ + vector controls; + + if (course) + course->getControls(controls); + int previousControl = 0; + for (size_t k = 0; k < controls.size(); k++) { + int cid = course->getCourseControlId(k); + if (controlsToWatch.count(cid) ) { + + if (selectedControl[classId].getControl() == -1) { + // Default control + selectedControl[classId].setControl(cid, previousControl); + } + + char bf[16]; + sprintf_s(bf, "ctrl%d", cid); + string name = course->getRadioName(cid); + /*if (controls[k]->hasName()) { + name = "#" + controls[k]->getName(); + if (controls[k]->getNumberDuplicates() > 1) + name += "-" + itos(numbering++); + } + else { + name = lang.tl("radio X#" + itos(numbering++)); + capitalize(name); + name = "#" + name; + } + */ + string tooltip = lang.tl("kontroll X (Y)#" + itos(k+1) +"#" + itos(controls[k]->getFirstNumber())); + capitalize(tooltip); + ButtonInfo &bi = gdi.addButton(cx, cy, bw, bf, "#" + name, tabSpeakerCB, "#" + tooltip, false, false); + bi.setExtra(previousControl); + previousControl = cid; + cx+=bw; + + cb++; + if (cb>nbtn) { + cb=1; + cy+=gdi.getButtonHeight()+4; + cx=basex; + } + } + } + gdi.fillDown(); + char bf[16]; + sprintf_s(bf, "ctrl%d", oPunch::PunchFinish); + gdi.addButton(cx, cy, bw, bf, "Mål", tabSpeakerCB, "", false, false).setExtra(previousControl); + + if (selectedControl[classId].getControl() == -1) { + // Default control + selectedControl[classId].setControl(oPunch::PunchFinish, previousControl); + } + + gdi.popX(); +} + +int TabSpeaker::processListBox(gdioutput &gdi, const ListBoxInfo &bu) +{ + if (bu.id=="Leg") { + if (classId>0) { + selectedControl[classId].setLeg(bu.data>=1000, bu.data%1000); + generateControlList(gdi, classId); + gdi.setRestorePoint("speaker"); + gdi.setRestorePoint("SpeakerList"); + + bool shortNames = oe->getPropertyInt("SpeakerShortNames", false) != 0; + oe->speakerList(gdi, classId, selectedControl[classId].getLeg(), + selectedControl[classId].getControl(), + selectedControl[classId].getPreviousControl(), + selectedControl[classId].isTotal(), + shortNames); + } + } + else if (bu.id == "DetailLevel") { + watchLevel = oTimeLine::Priority(bu.data); + shownEvents.clear(); + events.clear(); + + updateTimeLine(gdi); + } + else if (bu.id == "WatchNumber") { + watchNumber = bu.data; + updateTimeLine(gdi); + } + else if (bu.id == "Class") { + savePriorityClass(gdi); + int classId = int(bu.data); + loadPriorityClass(gdi, classId); + } + return 0; +} + +bool TabSpeaker::loadPage(gdioutput &gdi) +{ + oe->checkDB(); + + gdi.clearPage(false); + gdi.pushX(); + gdi.setRestorePoint("settings"); + + gdi.pushX(); + gdi.fillDown(); + + int h,w; + gdi.getTargetDimension(w, h); + + int bw=gdi.scaleLength(100); + int nbtn=max((w-80)/bw, 1); + bw=(w-80)/nbtn; + int basex = SPEAKER_BASE_X; + int basey=gdi.getCY(); + + int cx=basex; + int cy=basey; + int cb=1; + for (set::iterator it=classesToWatch.begin();it!=classesToWatch.end();++it) { + char classid[32]; + sprintf_s(classid, "cid%d", *it); + pClass pc=oe->getClass(*it); + + if (pc) { + gdi.addButton(cx, cy, bw, classid, "#" + pc->getName(), tabSpeakerCB, "", false, false); + cx+=bw; + cb++; + + if (cb>nbtn) { + cb=1; + cx=basex; + cy+=gdi.getButtonHeight()+4; + } + } + } + + int db = 0; + if (classesToWatch.empty()) { + gdi.addString("", boldLarge, "Speakerstöd"); + gdi.dropLine(); + cy=gdi.getCY(); + cx=gdi.getCX(); + } + else { + gdi.addButton(cx+db, cy, bw-2, "Events", "Händelser", tabSpeakerCB, "Löpande information om viktiga händelser i tävlingen", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + gdi.addButton(cx+db, cy, bw/5, "ZoomIn", "+", tabSpeakerCB, "Zooma in (Ctrl + '+')", false, false); + db += bw/5+2; + gdi.addButton(cx+db, cy, bw/5, "ZoomOut", MakeDash("-"), tabSpeakerCB, "Zooma ut (Ctrl + '-')", false, false); + db += bw/5+2; + } + gdi.addButton(cx+db, cy, bw-2, "Settings", "Inställningar...", tabSpeakerCB, "Välj vilka klasser och kontroller som bevakas", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + gdi.addButton(cx+db, cy, bw-2, "Manual", "Tidsinmatning", tabSpeakerCB, "Mata in radiotider manuellt", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + + gdi.addButton(cx+db, cy, bw-2, "PunchTable", "Stämplingar", tabSpeakerCB, "Visa en tabell över alla stämplingar", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + + gdi.addButton(cx+db, cy, bw-2, "LiveResult", "Liveresultat", tabSpeakerCB, "Visa rullande tider mellan kontroller i helskärmsläge", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + + + if (!ownWindow) { + gdi.addButton(cx+db, cy, bw-2, "Priority", "Prioritering", tabSpeakerCB, "Välj löpare att prioritera bevakning för", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + + + gdi.addButton(cx+db, cy, bw-2, "Window", "Nytt fönster", tabSpeakerCB, "", false, false); + if (++cb>nbtn) { + cb = 1, cx = basex, db = 0; + cy += gdi.getButtonHeight()+4; + } else db += bw; + } + gdi.setRestorePoint("classes"); + gdi.refresh(); + return true; +} + +void TabSpeaker::clearCompetitionData() +{ + controlsToWatch.clear(); + classesToWatch.clear(); + controlsToWatchSI.clear(); + selectedControl.clear(); + classId=0; + lastControl.clear(); + + lastControlToWatch = 0; + lastClassToWatch = 0; + + shownEvents.clear(); + events.clear(); + + delete speakerMonitor; + speakerMonitor = 0; +} + +void TabSpeaker::manualTimePage(gdioutput &gdi) const +{ + gdi.setRestorePoint("manual"); + + gdi.fillRight(); + gdi.pushX(); + gdi.addInput("Control", lastControl, 5, 0, "Kontroll"); + gdi.addInput("Runner", "", 6, 0, "Löpare"); + gdi.addInput("Time", "", 8, 0, "Tid"); + gdi.dropLine(); + gdi.addButton("StoreTime", "Spara", tabSpeakerCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", tabSpeakerCB).setCancel(); + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(3); + gdi.addString("", 10, "help:14692"); + + gdi.setInputFocus("Runner"); + gdi.refresh(); +} + +void TabSpeaker::storeManualTime(gdioutput &gdi) +{ + char bf[256]; + + int punch=gdi.getTextNo("Control"); + + if (punch<=0) + throw std::exception("Kontrollnummer måste anges."); + + lastControl=gdi.getText("Control"); + const string &r_str=gdi.getText("Runner"); + string time=gdi.getText("Time"); + + if (time.empty()) + time=getLocalTimeOnly(); + + int itime=oe->getRelativeTime(time); + + if (itime <= 0) + throw std::exception("Ogiltig tid."); + + pRunner r=oe->getRunnerByBibOrStartNo(r_str, false); + int r_no = atoi(r_str.c_str()); + if (!r) + r=oe->getRunnerByCardNo(r_no, itime); + + string Name; + int sino=r_no; + if (r) { + Name=r->getName(); + sino=r->getCardNo(); + } + else + Name = lang.tl("Okänd"); + + if (sino <= 0) { + sprintf_s(bf, "Ogiltigt bricknummer.#%d", sino); + throw std::exception(bf); + } + + oe->addFreePunch(itime, punch, sino, true); + + gdi.restore("manual", false); + gdi.addString("", 0, "Löpare: X, kontroll: Y, kl Z#" + Name + "#" + oPunch::getType(punch) + "#" + oe->getAbsTime(itime)); + + manualTimePage(gdi); +} + +void TabSpeaker::loadPriorityClass(gdioutput &gdi, int classId) { + + gdi.restore("PrioList"); + gdi.setRestorePoint("PrioList"); + gdi.setOnClearCb(tabSpeakerCB); + runnersToSet.clear(); + vector r; + oe->getRunners(classId, 0, r); + + int x = gdi.getCX(); + int y = gdi.getCY()+2*gdi.getLineHeight(); + int dist = gdi.scaleLength(25); + int dy = int(gdi.getLineHeight()*1.3); + for (size_t k = 0; kskip() /*|| r[k]->getLeg>0*/) + continue; + int pri = r[k]->getSpeakerPriority(); + int id = r[k]->getId(); + gdi.addCheckbox(x,y,"A" + itos(id), "", 0, pri>0); + gdi.addCheckbox(x+dist,y,"B" + itos(id), "", 0, pri>1); + gdi.addStringUT(y-dist/3, x+dist*2, 0, r[k]->getCompleteIdentification()); + runnersToSet.push_back(id); + y += dy; + } + gdi.refresh(); +} + +void TabSpeaker::savePriorityClass(gdioutput &gdi) { + oe->synchronizeList(oLRunnerId, true, false); + oe->synchronizeList(oLTeamId, false, true); + + for (size_t k = 0; kgetRunner(runnersToSet[k], 0); + if (r) { + int id = runnersToSet[k]; + if (!gdi.hasField("A" + itos(id))) { + runnersToSet.clear(); //Page not loaded. Abort. + return; + } + + bool a = gdi.isChecked("A" + itos(id)); + bool b = gdi.isChecked("B" + itos(id)); + int pri = (a?1:0) + (b?1:0); + pTeam t = r->getTeam(); + if (t) { + t->setSpeakerPriority(pri); + t->synchronize(true); + } + else { + r->setSpeakerPriority(pri); + r->synchronize(true); + } + } + } +} + +bool TabSpeaker::onClear(gdioutput &gdi) { + if (!runnersToSet.empty()) + savePriorityClass(gdi); + + return true; +} +SpeakerMonitor *TabSpeaker::getSpeakerMonitor() { + if (speakerMonitor == 0) + speakerMonitor = new SpeakerMonitor(*oe); + + return speakerMonitor; +} diff --git a/code/TabSpeaker.h b/code/TabSpeaker.h new file mode 100644 index 0000000..13fae7d --- /dev/null +++ b/code/TabSpeaker.h @@ -0,0 +1,117 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "tabbase.h" + +class SpeakerMonitor; + +class spkClassSelection { + // The currently selected leg + int selectedLeg; + // True if total results, otherwise stage results + bool total; + // Given a leg, get the corresponding (control, previous control) to watch + map > legToControl; +public: + spkClassSelection() : selectedLeg(0), total(false) {} + void setLeg(bool totalIn, int leg) {total = totalIn, selectedLeg=leg;} + int getLeg() const {return selectedLeg;} + bool isTotal() const {return total;} + + void setControl(int controlId, int previousControl) { + legToControl[selectedLeg] = make_pair(controlId, previousControl); + } + int getControl() { + if (legToControl.count(selectedLeg)==1) + return legToControl[selectedLeg].first; + else return -1; + } + int getPreviousControl() { + if (legToControl.count(selectedLeg)==1) + return legToControl[selectedLeg].second; + else return -1; + } +}; + +class TabSpeaker : + public TabBase { +private: + set controlsToWatch; + set classesToWatch; + set controlsToWatchSI; + + int lastControlToWatch; + int lastClassToWatch; + + set<__int64> shownEvents; + vector events; + oTimeLine::Priority watchLevel; + int watchNumber; + + void generateControlList(gdioutput &gdi, int classId); + void generateControlListForLeg(gdioutput &gdi, int classId, int leg); + + string lastControl; + + void manualTimePage(gdioutput &gdi) const; + void storeManualTime(gdioutput &gdi); + + //Curren class- + int classId; + //Map CourseNo -> selected Control. + //map selectedControl; + map selectedControl; + + bool ownWindow; + + void drawTimeLine(gdioutput &gdi); + void splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r); + + // Runner Id:s to set priority for + vector runnersToSet; + + SpeakerMonitor *speakerMonitor; + + SpeakerMonitor *getSpeakerMonitor(); + +public: + + bool onClear(gdioutput &gdi); + void loadPriorityClass(gdioutput &gdi, int classId); + void savePriorityClass(gdioutput &gdi); + + void updateTimeLine(gdioutput &gdi); + + //Clear selection data + void clearCompetitionData(); + + int processButton(gdioutput &gdi, const ButtonInfo &bu); + int processListBox(gdioutput &gdi, const ListBoxInfo &bu); + int handleEvent(gdioutput &gdi, const EventInfo &ei); + + const char * getTypeStr() const {return "TSpeakerTab";} + TabType getType() const {return TSpeakerTab;} + + bool loadPage(gdioutput &gdi); + TabSpeaker(oEvent *oe); + ~TabSpeaker(void); +}; diff --git a/code/TabTeam.cpp b/code/TabTeam.cpp new file mode 100644 index 0000000..a690aae --- /dev/null +++ b/code/TabTeam.cpp @@ -0,0 +1,1899 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "gdioutput.h" +#include "gdiconstants.h" + +#include "csvparser.h" +#include "SportIdent.h" +#include "meos_util.h" +#include + +#include "meosexception.h" +#include "TabTeam.h" +#include "TabRunner.h" +#include "MeOSFeatures.h" +#include "RunnerDB.h" + +#include "TabSI.h" + +TabTeam::TabTeam(oEvent *poe):TabBase(poe) +{ + clearCompetitionData(); +} + +TabTeam::~TabTeam(void) +{ +} + +int TeamCB(gdioutput *gdi, int type, void *data) +{ + TabTeam &tt = dynamic_cast(*gdi->getTabs().get(TTeamTab)); + + return tt.teamCB(*gdi, type, data); +} + +int teamSearchCB(gdioutput *gdi, int type, void *data) +{ + TabTeam &tc = dynamic_cast(*gdi->getTabs().get(TTeamTab)); + + return tc.searchCB(*gdi, type, data); +} + +int TabTeam::searchCB(gdioutput &gdi, int type, void *data) { + static DWORD editTick = 0; + string expr; + bool showNow = false; + bool filterMore = false; + + if (type == GUI_INPUTCHANGE) { + inputId++; + InputInfo &ii = *(InputInfo *)(data); + expr = trim(ii.text); + filterMore = expr.length() > lastSearchExpr.length() && + expr.substr(0, lastSearchExpr.length()) == lastSearchExpr; + editTick = GetTickCount(); + if (expr != lastSearchExpr) { + int nr = oe->getNumRunners(); + if (timeToFill < 50 || (filterMore && (timeToFill * lastFilter.size())/nr < 50)) + showNow = true; + else {// Delay filter + gdi.addTimeoutMilli(500, "Search: " + expr, teamSearchCB).setExtra((void *)inputId); + } + } + } + else if (type == GUI_TIMER) { + + TimerInfo &ti = *(TimerInfo *)(data); + + if (inputId != int(ti.getExtra())) + return 0; + + expr = ti.id.substr(8); + filterMore = expr.length() > lastSearchExpr.length() && + expr.substr(0, lastSearchExpr.length()) == lastSearchExpr; + showNow = true; + } + else if (type == GUI_EVENT) { + EventInfo &ev = *(EventInfo *)(data); + if (ev.getKeyCommand() == KC_FIND) { + gdi.setInputFocus("SearchText", true); + } + else if (ev.getKeyCommand() == KC_FINDBACK) { + gdi.setInputFocus("SearchText", false); + } + } + else if (type == GUI_FOCUS) { + InputInfo &ii = *(InputInfo *)(data); + + if (ii.text == getSearchString()) { + ((InputInfo *)gdi.setText("SearchText", ""))->setFgColor(colorDefault); + } + } + + if (showNow) { + stdext::hash_set filter; + + if (type == GUI_TIMER) + gdi.setWaitCursor(true); + + if (filterMore) { + + oe->findTeam(expr, 0, filter); + lastSearchExpr = expr; + // Filter more + if (filter.empty()) { + vector< pair > runners; + runners.push_back(make_pair(lang.tl("Ingen matchar 'X'#" + expr), -1)); + gdi.addItem("Teams", runners); + } + else + gdi.filterOnData("Teams", filter); + } + else { + oe->findTeam(expr, 0, filter); + lastSearchExpr = expr; + + vector< pair > runners; + oe->fillTeams(runners); + + if (filter.size() == runners.size()){ + } + else if (filter.empty()) { + runners.clear(); + runners.push_back(make_pair(lang.tl("Ingen matchar 'X'#" + expr), -1)); + } + else { + vector< pair > runners2; + + for (size_t k = 0; ksynchronize(); + t->evaluate(false); + + teamId=t->getId(); + + gdi.enableEditControls(true); + gdi.enableInput("Save"); + gdi.enableInput("Undo"); + gdi.enableInput("Remove"); + + oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); + gdi.selectItemByData("RClass", t->getClassId()); + gdi.selectItemByData("Teams", t->getId()); + + if (gdi.hasField("StatusIn")) { + gdi.selectItemByData("StatusIn", t->getInputStatus()); + int ip = t->getInputPlace(); + if (ip > 0) + gdi.setText("PlaceIn", ip); + else + gdi.setText("PlaceIn", MakeDash("-")); + + gdi.setText("TimeIn", t->getInputTimeS()); + if (gdi.hasField("PointIn")) + gdi.setText("PointIn", t->getInputPoints()); + } + + loadTeamMembers(gdi, 0, 0, t); + } + else { + teamId=0; + + gdi.enableEditControls(false); + gdi.disableInput("Save"); + gdi.disableInput("Undo"); + gdi.disableInput("Remove"); + + ListBoxInfo lbi; + gdi.getSelectedItem("RClass", lbi); + + gdi.selectItemByData("Teams", -1); + + if (gdi.hasField("StatusIn")) { + gdi.selectFirstItem("StatusIn"); + gdi.setText("PlaceIn", ""); + gdi.setText("TimeIn", "-"); + if (gdi.hasField("PointIn")) + gdi.setText("PointIn", ""); + } + + loadTeamMembers(gdi, lbi.data, 0, 0); + } + + updateTeamStatus(gdi, t); + gdi.refresh(); +} + +void TabTeam::updateTeamStatus(gdioutput &gdi, pTeam t) +{ + if (!t) { + gdi.setText("Name", ""); + if (gdi.hasField("StartNo")) + gdi.setText("StartNo", ""); + if (gdi.hasField("Club")) + gdi.setText("Club", ""); + bool hasFee = gdi.hasField("Fee"); + if (hasFee) { + gdi.setText("Fee", ""); + } + gdi.setText("Start", "-"); + gdi.setText("Finish", "-"); + gdi.setText("Time", "-"); + gdi.selectItemByData("Status", 0); + gdi.setText("TimeAdjust", "-"); + gdi.setText("PointAdjust", "-"); + + return; + } + + gdi.setText("Name", t->getName()); + if (gdi.hasField("StartNo")) + gdi.setText("StartNo", t->getBib()); + + if (gdi.hasField("Club")) + gdi.setText("Club", t->getClub()); + bool hasFee = gdi.hasField("Fee"); + if (hasFee) { + gdi.setText("Fee", oe->formatCurrency(t->getDI().getInt("Fee"))); + } + + gdi.setText("Start", t->getStartTimeS()); + gdi.setText("Finish",t->getFinishTimeS()); + gdi.setText("Time", t->getRunningTimeS()); + gdi.setText("TimeAdjust", getTimeMS(t->getTimeAdjustment())); + gdi.setText("PointAdjust", -t->getPointAdjustment()); + gdi.selectItemByData("Status", t->getStatus()); +} + +bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) { + if (teamId==0) + return 0; + + DWORD tid=teamId; + string name=gdi.getText("Name"); + + if (name.empty()) { + gdi.alert("Alla lag måste ha ett namn."); + return 0; + } + + bool create=false; + + pTeam t; + if (tid==0) { + t=oe->addTeam(name); + create=true; + } + else t=oe->getTeam(tid); + + teamId=t->getId(); + bool bibModified = false; + if (t) { + t->setName(name, true); + if (gdi.hasField("StartNo")) { + const string &bib = gdi.getText("StartNo"); + if (bib != t->getBib()) { + bibModified = true; + char pat[32]; + int no = oClass::extractBibPattern(bib, pat); + t->setBib(bib, no, no > 0, false); + } + } + string start = gdi.getText("Start"); + t->setStartTimeS(start); + if (t->getRunner(0)) + t->getRunner(0)->setStartTimeS(start); + + t->setFinishTimeS(gdi.getText("Finish")); + + if (gdi.hasField("Fee")) + t->getDI().setInt("Fee", oe->interpretCurrency(gdi.getText("Fee"))); + + t->apply(false, 0, false); + + if (gdi.hasField("Club")) { + ListBoxInfo lbi; + gdi.getSelectedItem("Club", lbi); + + if (!lbi.text.empty()) { + pClub pc=oe->getClub(lbi.text); + if (!pc) + pc = oe->addClub(lbi.text); + pc->synchronize(); + } + + t->setClub(lbi.text); + if (!dontReloadTeams) + oe->fillClubs(gdi, "Club"); + gdi.setText("Club", lbi.text); + } + ListBoxInfo lbi; + gdi.getSelectedItem("Status", lbi); + + RunnerStatus sIn = (RunnerStatus)lbi.data; + // Must be done AFTER all runners are set. But setting runner can modify status, so decide here. + bool setDNS = (sIn == StatusDNS) && (t->getStatus()!=StatusDNS); + bool checkStatus = (sIn != t->getStatus()); + + if (sIn == StatusUnknown && t->getStatus() == StatusDNS) + t->setTeamNoStart(false); + else if ((RunnerStatus)lbi.data != t->getStatus()) + t->setStatus((RunnerStatus)lbi.data, true, false); + + gdi.getSelectedItem("RClass", lbi); + + int classId = lbi.data; + bool newClass = t->getClassId() != classId; + set classes; + bool globalDep = false; + if (t->getClassRef()) + globalDep = t->getClassRef()->hasClassGlobalDependance(); + + classes.insert(classId); + classes.insert(t->getClassId()); + + bool readStatusIn = true; + if (newClass && t->getInputStatus() != StatusNotCompetiting && t->hasInputData()) { + if (gdi.ask("Vill du sätta resultatet från tidigare etapper till ?")) { + t->resetInputData(); + readStatusIn = false; + } + } + + if (newClass && !bibModified) { + pClass pc = oe->getClass(classId); + if (pc) { + pair snoBib = pc->getNextBib(); + if (snoBib.first > 0) { + t->setBib(snoBib.second, snoBib.first, true, false); + } + } + } + + t->setClassId(classId, true); + + if (gdi.hasField("TimeAdjust")) { + int time = convertAbsoluteTimeMS(gdi.getText("TimeAdjust")); + if (time != NOTIME) + t->setTimeAdjustment(time); + } + if (gdi.hasField("PointAdjust")) { + t->setPointAdjustment(-gdi.getTextNo("PointAdjust")); + } + + if (gdi.hasField("StatusIn") && readStatusIn) { + t->setInputStatus(RunnerStatus(gdi.getSelectedItem("StatusIn").first)); + t->setInputPlace(gdi.getTextNo("PlaceIn")); + t->setInputTime(gdi.getText("TimeIn")); + if (gdi.hasField("PointIn")) + t->setInputPoints(gdi.getTextNo("PointIn")); + } + + pClass pc=oe->getClass(classId); + + if (pc) { + globalDep |= pc->hasClassGlobalDependance(); + + for (unsigned i=0;igetNumStages(); i++) { + char bf[16]; + sprintf_s(bf, "R%d", i); + if (!gdi.hasField("SI" + itos(i))) // Skip if field not loaded in page + continue; + + if (pc->getLegRunner(i)==i) { + + const string name=gdi.getText(bf); + if (name.empty()) { //Remove + t->removeRunner(gdi, true, i); + } + else { + pRunner r=t->getRunner(i); + char bf2[16]; + sprintf_s(bf2, "SI%d", i); + int cardNo = gdi.getTextNo(bf2); + + if (r) { + bool newName = name != r->getName(); + int oldId = gdi.getExtraInt(bf); + // Same runner set + if (oldId == r->getId()) { + if (newName) { + r->updateFromDB(name, r->getClubId(), r->getClassId(), + cardNo, 0); + r->setName(name, true); + } + r->setCardNo(cardNo, true); + + if (gdi.isChecked("RENT" + itos(i))) + r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee")); + else + r->getDI().setInt("CardFee", 0); + + r->synchronize(true); + continue; + } + + if (newName) { + if (!t->getClub().empty()) + r->setClub(t->getClub()); + r->resetPersonalData(); + r->updateFromDB(name, r->getClubId(), r->getClassId(), + cardNo, 0); + } + } + else + r=oe->addRunner(name, t->getClubId(), t->getClassId(), cardNo, 0, false); + + r->setName(name, true); + r->setCardNo(cardNo, true); + r->synchronize(); + t->setRunner(i, r, true); + } + } + } + + } + if (setDNS) + t->setTeamNoStart(true); + + if (t->checkValdParSetup()) { + gdi.alert("Laguppställningen hade fel, som har rättats"); + } + + if (t->getRunner(0)) + t->getRunner(0)->setStartTimeS(start); + + t->evaluate(true); + + if (globalDep) + oe->reEvaluateAll(classes, false); + + if (!dontReloadTeams) { + fillTeamList(gdi); + //updateTeamStatus(gdi, t); + } + if (checkStatus && sIn != t->getStatus()) { + gdi.alert("Status matchar inte deltagarnas status."); + } + } + + if (create) { + selectTeam(gdi, 0); + gdi.setInputFocus("Name", true); + } + else if (!dontReloadTeams) { + selectTeam(gdi, t); + } + return true; +} + +int TabTeam::teamCB(gdioutput &gdi, int type, void *data) +{ + if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id=="Save") { + return save(gdi, false); + } + if (bi.id == "Cancel") { + loadPage(gdi); + return 0; + } + else if (bi.id=="TableMode") { + if (currentMode == 0 && teamId>0) + save(gdi, true); + + currentMode = 1; + loadPage(gdi); + } + else if (bi.id=="FormMode") { + if (currentMode != 0) { + currentMode = 0; + gdi.enableTables(); + loadPage(gdi); + } + } + else if (bi.id=="Undo") { + pTeam t = oe->getTeam(teamId); + selectTeam(gdi, t); + return 0; + } + else if (bi.id=="Search") { + ListBoxInfo lbi; + gdi.getSelectedItem("Teams", lbi); + oe->fillTeams(gdi, "Teams"); + stdext::hash_set foo; + pTeam t=oe->findTeam(gdi.getText("SearchText"), lbi.data, foo); + + if (t) { + selectTeam(gdi, t); + gdi.selectItemByData("Teams", t->getId()); + } + else + gdi.alert("Laget hittades inte"); + } + else if (bi.id == "ImportTeams") { + if (teamId>0) + save(gdi, true); + showTeamImport(gdi); + } + else if (bi.id == "DoImportTeams") { + doTeamImport(gdi); + } + else if (bi.id == "AddTeamMembers") { + if (teamId>0) + save(gdi, true); + showAddTeamMembers(gdi); + } + else if (bi.id == "DoAddTeamMembers") { + doAddTeamMembers(gdi); + } + else if (bi.id == "SaveTeams") { + saveTeamImport(gdi, bi.getExtraInt() != 0); + } + else if (bi.id == "ShowAll") { + fillTeamList(gdi); + } + else if (bi.id == "DirectEntry") { + gdi.restore("DirectEntry", false); + gdi.fillDown(); + gdi.dropLine(); + gdi.addString("", boldText, "Direktanmälan"); + gdi.addString("", 0, "Du kan använda en SI-enhet för att läsa in bricknummer."); + gdi.dropLine(0.2); + + int leg = bi.getExtraInt(); + gdi.fillRight(); + gdi.addInput("DirName", "", 16, TeamCB, "Namn:"); + gdi.addInput("DirCard", "", 8, TeamCB, "Bricka:"); + + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.setCardNumberField("DirCard"); + gdi.setPostClearCb(TeamCB); + bool rent = false; + gdi.dropLine(1.1); + + gdi.addCheckbox("DirRent", "Hyrd", 0, rent); + gdi.dropLine(-0.2); + + gdi.addButton("DirOK", "OK", TeamCB).setDefault().setExtra(leg); + gdi.addButton("Cancel", "Avbryt", TeamCB).setCancel(); + + gdi.disableInput("DirOK"); + gdi.refreshFast(); + } + else if (bi.id == "DirOK") { + pTeam t = oe->getTeam(teamId); + if (!t || !t->getClassRef()) + return 0; + + int leg = bi.getExtraInt(); + string name = gdi.getText("DirName"); + int storedId = gdi.getBaseInfo("DirName").getExtraInt(); + + int card = gdi.getTextNo("DirCard"); + + + if (card <= 0 || name.empty()) + throw meosException("Internal error"); //Cannot happen + + pRunner r = 0; + if (storedId > 0) { + r = oe->getRunner(storedId, 0); + if (r != 0 && (r->getName() != name || r->getCardNo() != card)) + r = 0; // Ignore match + } + + bool rExists = r != 0; + + pRunner old = oe->getRunnerByCardNo(card, 0, true, true); + if (old && r != old) { + throw meosException("Brickan används av X.#" + old->getName() ); + } + + + pClub clb = 0; + if (!rExists) { + pRunner rOrig = oe->getRunnerByCardNo(card, 0, false, false); + if (rOrig) + clb = rOrig->getClubRef(); + } + + bool rent = gdi.isChecked("DirRent"); + + if (r == 0) { + r = oe->addRunner(name, clb ? clb->getId() : t->getClubId(), t->getClassId(), card, 0, false); + } + if (rent) + r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee")); + + t->synchronize(); + pRunner oldR = t->getRunner(leg); + t->setRunner(leg, 0, false); + t->synchronize(true); + if (oldR) { + if (rExists) { + switchRunners(t, leg, r, oldR); + } + else { + oldR->setClassId(0, true); + vector mp; + oldR->evaluateCard(true, mp, 0, true); + oldR->synchronize(true); + t->setRunner(leg, r, true); + t->checkValdParSetup(); + } + } + else { + t->setRunner(leg, r, true); + t->checkValdParSetup(); + } + + selectTeam(gdi, t); + } + else if (bi.id == "Browse") { + const char *target = (const char *)bi.getExtra(); + vector< pair > ext; + ext.push_back(make_pair("Laguppställning", "*.csv;*.txt")); + string fileName = gdi.browseForOpen(ext, "csv"); + if (!fileName.empty()) + gdi.setText(target, fileName); + } + else if (bi.id == "ChangeKey") { + pTeam t = oe->getTeam(teamId); + if (!t || !t->getClassRef()) + return 0; + + pClass pc = t->getClassRef(); + gdi.restore("ChangeKey", false); + gdi.fillRight(); + gdi.pushX(); + gdi.dropLine(); + gdi.addSelection("ForkKey", 100, 400, 0, "Gafflingsnyckel:"); + int nf = pc->getNumForks(); + vector< pair > keys; + for (int f = 0; f < nf; f++) { + keys.push_back( make_pair(itos(f+1), f)); + } + int currentKey = max(t->getStartNo()-1, 0) % nf; + gdi.addItem("ForkKey", keys); + gdi.selectItemByData("ForkKey", currentKey); + + gdi.dropLine(0.9); + gdi.addButton("SaveKey", "Ändra", TeamCB); + gdi.refreshFast(); + } + else if (bi.id == "SaveKey") { + pTeam t = oe->getTeam(teamId); + if (!t || !t->getClassRef()) + return 0; + + pClass pc = t->getClassRef(); + int nf = pc->getNumForks(); + ListBoxInfo lbi; + gdi.getSelectedItem("ForkKey", lbi); + for (int k = 0; k < nf; k++) { + for (int j = 0; j < 2; j++) { + int newSno = t->getStartNo(); + if (j == 0) + newSno += k; + else + newSno -=k; + + if (newSno <= 0) + continue; + + int currentKey = max(newSno-1, 0) % nf; + if (currentKey == lbi.data) { + t->setStartNo(newSno, false); + t->apply(false, 0, false); + t->synchronize(true); + for (int i = 0; i < t->getNumRunners(); i++) { + pRunner r = t->getRunner(i); + if (r) { + vector mp; + r->evaluateCard(true, mp); + r->synchronize(true); + } + } + selectTeam(gdi, t); + return 0; + } + } + } + } + else if (bi.id.substr(0,2)=="MR") { + int leg = atoi(bi.id.substr(2, string::npos).c_str()); + + if (teamId != 0) { + save(gdi, false); + pTeam t = oe->getTeam(teamId); + if (t != 0) { + pRunner r = t->getRunner(leg); + if (r) { + TabRunner *tr = (TabRunner *)gdi.getTabs().get(TRunnerTab); + tr->loadPage(gdi, r->getId()); + } + } + } + } + else if (bi.id.substr(0,2)=="DR") { + int leg=atoi(bi.id.substr(2, string::npos).c_str()); + pTeam t = oe->getTeam(teamId); + if (t == 0) + return 0; + pClass pc = t->getClassRef(); + if (pc == 0) + return 0; + + gdi.restore("SelectR", false); + gdi.setRestorePoint("SelectR"); + gdi.dropLine(); + gdi.fillDown(); + + gdi.addString("", fontMediumPlus, "Välj löpare för sträcka X#" + pc->getLegNumber(leg)); + gdi.setData("Leg", leg); + + gdi.setRestorePoint("DirectEntry"); + gdi.addString("", 0, "help:teamwork"); + gdi.dropLine(0.5); + + gdi.addButton("DirectEntry", "Direktanmälan...", TeamCB).setExtra(leg); + set presented; + gdi.pushX(); + gdi.fillRight(); + int w,h; + gdi.getTargetDimension(w, h); + w = max(w, gdi.getWidth()); + int limit = max(w - gdi.scaleLength(150), gdi.getCX() + gdi.scaleLength(200)); + set< pair > rToList; + set usedR; + string anon = lang.tl("N.N."); + set clubs; + + for (int i = 0; i < t->getNumRunners(); i++) { + if (pc->getLegRunnerIndex(i) == 0) { + pRunner r = t->getRunner(i); + if (!r) + continue; + if (r->getClubId() > 0) + clubs.insert(r->getClubId()); // Combination teams + if (r && r->getName() != anon) { + rToList.insert( make_pair(r->getName(), r->getId())); + } + } + } + showRunners(gdi, "Från laget", rToList, limit, usedR); + vector clsR; + oe->getRunners(0, 0, clsR, true); + rToList.clear(); + if (t->getClubId() > 0) + clubs.insert(t->getClubId()); + + if (!clubs.empty()) { + for (size_t i = 0; i < clsR.size(); i++) { + if (clsR[i]->getRaceNo() > 0) + continue; + if (clubs.count(clsR[i]->getClubId()) == 0) + continue; + if (clsR[i]->getClassId() != t->getClassId()) + continue; + if (clsR[i]->getName() == anon) + continue; + rToList.insert( make_pair(clsR[i]->getName(), clsR[i]->getId())); + } + + showRunners(gdi, "Från klassen", rToList, limit, usedR); + rToList.clear(); + + for (size_t i = 0; i < clsR.size(); i++) { + if (clsR[i]->getRaceNo() > 0) + continue; + if (clubs.count(clsR[i]->getClubId()) == 0) + continue; + if (clsR[i]->getName() == anon) + continue; + rToList.insert( make_pair(clsR[i]->getName(), clsR[i]->getId())); + } + showRunners(gdi, "Från klubben", rToList, limit, usedR); + } + + + vector< pair > otherR; + + for (size_t i = 0; i < clsR.size(); i++) { + if (clsR[i]->getRaceNo() > 0) + continue; + if (clsR[i]->getName() == anon) + continue; + if (usedR.count(clsR[i]->getId())) + continue; + const string &club = clsR[i]->getClub(); + string id = clsR[i]->getName() + ", " + clsR[i]->getClass(); + if (!club.empty()) + id += " (" + club + ")"; + + otherR.push_back(make_pair(id, clsR[i]->getId())); + } + gdi.fillDown(); + if (!otherR.empty()) { + gdi.addString("", 1, "Övriga"); + gdi.fillRight(); + gdi.addSelection("SelectR", 250, 400, TeamCB); + gdi.addButton("SelectRunner", "OK", TeamCB).setExtra(leg); + gdi.fillDown(); + gdi.addButton("Cancel", "Avbryt", TeamCB); + + gdi.addItem("SelectR", otherR); + } + else { + gdi.addButton("Cancel", "Avbryt", TeamCB); + } + gdi.refresh(); + } + else if (bi.id=="SelectRunner") { + ListBoxInfo lbi; + gdi.getSelectedItem("SelectR", lbi); + pRunner r = oe->getRunner(lbi.data, 0); + if (r == 0) { + throw meosException("Ingen deltagare vald."); + } + int leg = (int)gdi.getData("Leg"); + + pTeam t = oe->getTeam(teamId); + processChangeRunner(gdi, t, leg, r); + } + else if (bi.id=="Add") { + if (teamId>0) { + + string name = gdi.getText("Name"); + pTeam t = oe->getTeam(teamId); + if (!name.empty() && t && t->getName() != name) { + if (gdi.ask("Vill du lägga till laget 'X'?#" + name)) { + t = oe->addTeam(name); + teamId = t->getId(); + } + save(gdi, false); + return true; + } + + save(gdi, false); + } + + pTeam t = oe->addTeam(oe->getAutoTeamName()); + + ListBoxInfo lbi; + gdi.getSelectedItem("RClass", lbi); + + int clsId; + if (signed(lbi.data)>0) + clsId = lbi.data; + else + clsId = oe->getFirstClassId(true); + + pClass pc = oe->getClass(clsId); + if (pc) { + pair snoBib = pc->getNextBib(); + if (snoBib.first > 0) { + t->setBib(snoBib.second, snoBib.first, true, false); + } + } + + t->setClassId(clsId, true); + + fillTeamList(gdi); + //oe->fillTeams(gdi, "Teams"); + selectTeam(gdi, t); + + //selectTeam(gdi, 0); + //gdi.selectItemByData("Teams", -1); + gdi.setInputFocus("Name", true); + } + else if (bi.id=="Remove") { + DWORD tid=teamId; + + if (tid==0) + throw std::exception("Inget lag valt."); + + pTeam t = oe->getTeam(tid); + + if (!t || t->isRemoved()) { + selectTeam(gdi, 0); + } + else if (gdi.ask("Vill du verkligen ta bort laget?")) { + vector runners; + vector noRemove; + for (int k = 0; k < t->getNumRunners(); k++) { + pRunner r = t->getRunner(k); + if (r && r->getRaceNo() == 0) { + if (r->getCard() == 0) + runners.push_back(r->getId()); + else + noRemove.push_back(r->getId()); + } + } + oe->removeTeam(tid); + oe->removeRunner(runners); + + for (size_t k = 0; kgetRunner(noRemove[k], 0); + if (r) { + r->setClassId(0, true); + r->synchronize(); + } + } + + fillTeamList(gdi); + //oe->fillTeams(gdi, "Teams"); + selectTeam(gdi, 0); + gdi.selectItemByData("Teams", -1); + } + } + } + else if (type == GUI_LINK) { + TextInfo ti = dynamic_cast(*(BaseInfo *)data); + if (ti.id == "SelectR") { + int leg = (int)gdi.getData("Leg"); + pTeam t = oe->getTeam(teamId); + int rid = ti.getExtraInt(); + pRunner r = oe->getRunner(rid, 0); + processChangeRunner(gdi, t, leg, r); + } + } + else if (type==GUI_LISTBOX) { + ListBoxInfo bi=*(ListBoxInfo *)data; + + if (bi.id=="Teams") { + if (gdi.isInputChanged("")) { + pTeam t = oe->getTeam(teamId); + bool newName = t && t->getName() != gdi.getText("Name"); + bool newBib = gdi.hasField("StartNo") && t && t->getBib() != gdi.getText("StartNo"); + save(gdi, true); + + if (newName || newBib) { + fillTeamList(gdi); + } + } + pTeam t=oe->getTeam(bi.data); + selectTeam(gdi, t); + } + else if (bi.id=="RClass") { //New class selected. + DWORD tid=teamId; + //gdi.getData("TeamID", tid); + + if (tid){ + pTeam t=oe->getTeam(tid); + pClass pc=oe->getClass(bi.data); + + if (pc && pc->getNumDistinctRunners() == shownDistinctRunners && + pc->getNumStages() == shownRunners) { + // Keep team setup, i.e. do nothing + } + else if (t && pc && (t->getClassId()==bi.data + || t->getNumRunners()==pc->getNumStages()) ) + loadTeamMembers(gdi, 0,0,t); + else + loadTeamMembers(gdi, bi.data, 0, t); + } + else loadTeamMembers(gdi, bi.data, 0, 0); + } + else { + + ListBoxInfo lbi; + gdi.getSelectedItem("RClass", lbi); + + if (signed(lbi.data)>0){ + pClass pc=oe->getClass(lbi.data); + + if (pc) { + vector rCache; + for(unsigned i=0;igetNumStages();i++){ + char bf[16]; + sprintf_s(bf, "R%d", i); + if (bi.id==bf){ + pRunner r=oe->getRunner(bi.data, 0); + if (r) { + sprintf_s(bf, "SI%d", i); + int cno = r->getCardNo(); + gdi.setText(bf, cno > 0 ? itos(cno) : ""); + warnDuplicateCard(gdi, bf, cno, r, rCache); + } + } + } + } + } + } + } + else if (type==GUI_INPUTCHANGE) { + InputInfo &ii=*(InputInfo *)data; + pClass pc=oe->getClass(classId); + if (pc){ + for(unsigned i=0;igetNumStages();i++){ + char bf[16]; + sprintf_s(bf, "R%d", i); + if (ii.id == bf) { + for (unsigned k=i+1; kgetNumStages(); k++) { + if (pc->getLegRunner(k)==i) { + sprintf_s(bf, "R%d", k); + gdi.setText(bf, ii.text); + } + } + break; + } + } + } + + if (ii.id == "DirName" || ii.id == "DirCard") { + gdi.setInputStatus("DirOK", !gdi.getText("DirName").empty() && + gdi.getTextNo("DirCard") > 0); + + } + } + else if (type == GUI_INPUT) { + InputInfo &ii=*(InputInfo *)data; + if (ii.id == "DirName" || ii.id == "DirCard") { + gdi.setInputStatus("DirOK", !gdi.getText("DirName").empty() && + gdi.getTextNo("DirCard") > 0); + + } + if (ii.id == "DirCard") { + int cno = gdi.getTextNo("DirCard"); + if (cno > 0 && gdi.getText("DirName").empty()) { + bool matched = false; + pRunner r = oe->getRunnerByCardNo(cno, 0, true, false); + if (r && (r->getStatus() == StatusUnknown || r->getStatus() == StatusDNS) ) { + // Switch to exactly this runner. Has not run before + gdi.setText("DirName", r->getName())->setExtra(r->getId()); + matched = true; + } + else { + r = oe->getRunnerByCardNo(cno, 0, false, false); + if (r) { + // Copy only the name. + gdi.setText("DirName", r->getName())->setExtra(0); + matched = true; + } + else if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::RunnerDb)) { + const RunnerDBEntry *rdb = oe->getRunnerDatabase().getRunnerByCard(cno); + if (rdb) { + string name; + rdb->getName(name); + gdi.setText("DirName", name)->setExtra(0); + matched = true; + } + } + } + if (r) + gdi.check("DirRent", r->getDCI().getInt("CardFee") != 0); + if (matched) + gdi.setInputStatus("DirOK", true); + } + } + pClass pc=oe->getClass(classId); + if (pc) { + for(unsigned i=0;igetNumStages();i++){ + if (ii.id == "SI" + itos(i)) { + int cardNo = atoi(ii.text.c_str()); + pTeam t = oe->getTeam(teamId); + if (t) { + vector rc; + warnDuplicateCard(gdi, ii.id, cardNo, t->getRunner(i), rc); + } + break; + } + } + } + + } + else if (type==GUI_CLEAR) { + if (teamId>0) + save(gdi, true); + + return true; + } + else if (type==GUI_POSTCLEAR) { + // Clear out SI-link + TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab)); + tsi.setCardNumberField(""); + return true; + } + return 0; +} + + +void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t) +{ + if (ClassId==0) + if (t) ClassId=t->getClassId(); + + classId=ClassId; + gdi.restore("",false); + + pClass pc=oe->getClass(ClassId); + if (!pc) return; + + shownRunners = pc->getNumStages(); + shownDistinctRunners = pc->getNumDistinctRunners(); + + gdi.setRestorePoint(); + gdi.newColumn(); + + gdi.fillDown(); + char bf[16]; + char bf_si[16]; + int xp = gdi.getCX(); + int yp = gdi.getCY(); + int numberPos = xp; + xp += gdi.scaleLength(25); + int dx[6] = {0, 184, 220, 290, 316, 364}; + for (int i = 0; i<6; i++) + dx[i] = gdi.scaleLength(dx[i]); + + gdi.addString("", yp, xp + dx[0], 0, "Namn:"); + gdi.addString("", yp, xp + dx[2], 0, "Bricka:"); + gdi.addString("", yp, xp + dx[3], 0, "Hyrd:"); + gdi.addString("", yp, xp + dx[5], 0, "Status:"); + gdi.dropLine(0.5); + vector rCache; + + for (unsigned i=0;igetNumStages();i++) { + yp = gdi.getCY(); + + sprintf_s(bf, "R%d", i); + gdi.pushX(); + bool hasSI = false; + gdi.addStringUT(yp, numberPos, 0, pc->getLegNumber(i)+"."); + if (pc->getLegRunner(i)==i) { + + gdi.addInput(xp + dx[0], yp, bf, "", 18, TeamCB);//Name + gdi.addButton(xp + dx[1], yp-2, gdi.scaleLength(28), "DR" + itos(i), "<>", TeamCB, "Knyt löpare till sträckan.", false, false); // Change + sprintf_s(bf_si, "SI%d", i); + hasSI = true; + gdi.addInput(xp + dx[2], yp, bf_si, "", 5, TeamCB).setExtra(i); //Si + + gdi.addCheckbox(xp + dx[3], yp + gdi.scaleLength(10), "RENT"+itos(i), "", 0, false); //Rentcard + } + else { + //gdi.addInput(bf, "", 24); + gdi.addInput(xp + dx[0], yp, bf, "", 18, 0);//Name + gdi.disableInput(bf); + } + gdi.addButton(xp + dx[4], yp-2, gdi.scaleLength(38), "MR" + itos(i), "...", TeamCB, "Redigera deltagaren.", false, false); // Change + + gdi.addString(("STATUS"+itos(i)).c_str(), yp+gdi.scaleLength(5), xp + dx[5], 0, "#MMMMMMMMMMMMMMMM"); + gdi.setText("STATUS"+itos(i), "", false); + gdi.dropLine(0.5); + gdi.popX(); + + + if (t) { + pRunner r=t->getRunner(i); + if (r) { + gdi.setText(bf, r->getNameRaw())->setExtra(r->getId()); + + if (hasSI) { + int cno = r->getCardNo(); + gdi.setText(bf_si, cno > 0 ? itos(cno) : ""); + warnDuplicateCard(gdi, bf_si, cno, r, rCache); + gdi.check("RENT" + itos(i), r->getDCI().getInt("CardFee") != 0); + } + string sid = "STATUS"+itos(i); + if (r->statusOK()) { + TextInfo * ti = (TextInfo *)gdi.setText(sid, "OK, " + r->getRunningTimeS(), false); + if (ti) + ti->setColor(colorGreen); + } + else if (r->getStatus() != StatusUnknown) { + TextInfo * ti = (TextInfo *)gdi.setText(sid, r->getStatusS() + ", " + r->getRunningTimeS(), false); + if (ti) + ti->setColor(colorRed); + } + } + } + } + + gdi.setRestorePoint("SelectR"); + gdi.addString("", 1, "help:7618"); + gdi.dropLine(); + int numF = pc->getNumForks(); + + if (numF>1 && t) { + gdi.addString ("", 1, "Gafflingsnyckel X#" + itos(1+(max(t->getStartNo()-1, 0) % numF))).setColor(colorGreen); + string crsList; + bool hasCrs = false; + for (size_t k = 0; k < pc->getNumStages(); k++) { + pCourse crs = pc->getCourse(k, t->getStartNo()); + string cS; + if (crs != 0) { + cS = crs->getName(); + hasCrs = true; + } + else + cS = MakeDash("-"); + + if (!crsList.empty()) + crsList += ", "; + crsList += cS; + + if (hasCrs && crsList.length() > 50) { + gdi.addStringUT(0, crsList); + crsList.clear(); + } + } + if (hasCrs && !crsList.empty()) { + gdi.addStringUT(0, crsList); + } + + if (hasCrs) { + gdi.dropLine(0.5); + gdi.setRestorePoint("ChangeKey"); + gdi.addButton("ChangeKey", "Ändra lagets gaffling", TeamCB); + } + } + gdi.refresh(); +} + +bool TabTeam::loadPage(gdioutput &gdi, int id) { + teamId = id; + return loadPage(gdi); +} + +bool TabTeam::loadPage(gdioutput &gdi) +{ + shownRunners = 0; + shownDistinctRunners = 0; + + oe->checkDB(); + oe->reEvaluateAll(set(), true); + + gdi.selectTab(tabId); + gdi.clearPage(false); + + if (currentMode == 1) { + Table *tbl=oe->getTeamsTB(); + addToolbar(gdi); + gdi.dropLine(1); + gdi.addTable(tbl, gdi.getCX(), gdi.getCY()); + return true; + } + + gdi.fillDown(); + gdi.addString("", boldLarge, "Lag(flera)"); + + gdi.pushX(); + gdi.fillRight(); + + gdi.registerEvent("SearchRunner", teamSearchCB).setKeyCommand(KC_FIND); + gdi.registerEvent("SearchRunnerBack", teamSearchCB).setKeyCommand(KC_FINDBACK); + gdi.addInput("SearchText", "", 17, teamSearchCB, "", "Sök på namn, bricka eller startnummer.").isEdit(false).setBgColor(colorLightCyan).ignore(true); + gdi.dropLine(-0.2); + gdi.addButton("ShowAll", "Visa alla", TeamCB).isEdit(false); + + gdi.dropLine(2); + gdi.popX(); + gdi.fillDown(); + gdi.addListBox("Teams", 250, 440, TeamCB, "", "").isEdit(false).ignore(true); + gdi.setInputFocus("Teams"); + fillTeamList(gdi); + + int posXForButtons = gdi.getCX(); + int posYForButtons = gdi.getCY(); + + gdi.newColumn(); + gdi.fillDown(); + gdi.pushX(); + gdi.addInput("Name", "", 24, 0, "Lagnamn:"); + + gdi.fillRight(); + bool drop = false; + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Bib)) { + gdi.addInput("StartNo", "", 4, 0, "Nr:", "Nummerlapp"); + drop = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy); + } + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + gdi.addCombo("Club", 180, 300, 0, "Klubb:"); + oe->fillClubs(gdi, "Club"); + drop = true; + } + + if (drop) { + gdi.dropLine(3); + gdi.popX(); + } + + gdi.addSelection("RClass", 170, 300, TeamCB, "Klass:"); + oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); + gdi.addItem("RClass", lang.tl("Ny klass"), 0); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) + gdi.addInput("Fee", "", 5, 0, "Avgift:"); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(3); + + gdi.pushX(); + gdi.fillRight(); + + gdi.addInput("Start", "", 8, 0, "Starttid:"); + gdi.addInput("Finish", "", 8, 0, "Måltid:"); + + const bool timeAdjust = oe->getMeOSFeatures().hasFeature(MeOSFeatures::TimeAdjust); + const bool pointAdjust = oe->getMeOSFeatures().hasFeature(MeOSFeatures::PointAdjust); + + if (timeAdjust || pointAdjust) { + gdi.dropLine(3); + gdi.popX(); + if (timeAdjust) { + gdi.addInput("TimeAdjust", "", 8, 0, "Tidstillägg:"); + } + if (pointAdjust) { + gdi.addInput("PointAdjust", "", 8, 0, "Poängavdrag:"); + } + } + + /*if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::TimeAdjust)) { + gdi.addInput("TimeAdjust", "", 5, 0, "Tidstillägg:"); + } + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::PointAdjust)) { + gdi.addInput("PointAdjust", "", 5, 0, "Poängavdrag:"); + }*/ + + gdi.fillDown(); + gdi.dropLine(3); + gdi.popX(); + + gdi.pushX(); + gdi.fillRight(); + + gdi.addInput("Time", "", 6, 0, "Tid:").isEdit(false).ignore(true); + gdi.disableInput("Time"); + + gdi.fillDown(); + gdi.addSelection("Status", 100, 160, 0, "Status:", "tooltip_explain_status"); + oe->fillStatus(gdi, "Status"); + + gdi.popX(); + gdi.selectItemByData("Status", 0); + + gdi.dropLine(1.5); + + const bool multiDay = oe->hasPrevStage(); + + if (multiDay) { + int xx = gdi.getCX(); + int yy = gdi.getCY(); + gdi.dropLine(0.5); + gdi.fillDown(); + int dx = int(gdi.getLineHeight()*0.7); + int ccx = xx + dx; + gdi.setCX(ccx); + gdi.addString("", 1, "Resultat från tidigare etapper"); + gdi.dropLine(0.3); + gdi.fillRight(); + + gdi.addSelection("StatusIn", 100, 160, 0, "Status:", "tooltip_explain_status"); + oe->fillStatus(gdi, "StatusIn"); + gdi.selectItemByData("Status", 0); + gdi.addInput("PlaceIn", "", 5, 0, "Placering:"); + int xmax = gdi.getCX() + dx; + gdi.setCX(ccx); + gdi.dropLine(3); + gdi.addInput("TimeIn", "", 5, 0, "Tid:"); + if (oe->hasRogaining()) { + gdi.addInput("PointIn", "", 5, 0, "Poäng:"); + } + gdi.dropLine(3); + RECT rc; + rc.right = xx; + rc.top = yy; + rc.left = max(xmax, gdi.getWidth()-dx); + rc.bottom = gdi.getCY(); + + gdi.addRectangle(rc, colorLightGreen, true, false); + gdi.dropLine(1.5); + gdi.popX(); + } + + gdi.fillRight(); + gdi.addButton("Save", "Spara", TeamCB, "help:save"); + gdi.disableInput("Save"); + gdi.addButton("Undo", "Ångra", TeamCB); + gdi.disableInput("Undo"); + + gdi.popX(); + gdi.dropLine(2.5); + gdi.addButton("Remove", "Radera", TeamCB); + gdi.disableInput("Remove"); + gdi.addButton("Add", "Nytt lag", TeamCB); + + gdi.setOnClearCb(TeamCB); + + addToolbar(gdi); + + RECT rc; + rc.left = posXForButtons; + rc.top = posYForButtons; + + gdi.setCY(posYForButtons + gdi.scaleLength(4)); + gdi.setCX(posXForButtons + gdi.getLineHeight()); + gdi.fillDown(); + gdi.addString("", 1, "Verktyg"); + gdi.dropLine(0.3); + gdi.fillRight(); + gdi.addButton("ImportTeams", "Importera laguppställningar", TeamCB); + gdi.addButton("AddTeamMembers", "Skapa anonyma lagmedlemmar", TeamCB, "Fyll obesatta sträckor i alla lag med anonyma tillfälliga lagmedlemmar (N.N.)"); + rc.right = gdi.getCX() + gdi.getLineHeight(); + gdi.dropLine(1.5); + rc.bottom = gdi.getHeight(); + gdi.addRectangle(rc, colorLightCyan); + + gdi.setRestorePoint(); + + selectTeam(gdi, oe->getTeam(teamId)); + + gdi.refresh(); + return true; +} + +void TabTeam::fillTeamList(gdioutput &gdi) { + timeToFill = GetTickCount(); + oe->fillTeams(gdi, "Teams"); + timeToFill = GetTickCount() - timeToFill; + lastSearchExpr = ""; + ((InputInfo *)gdi.setText("SearchText", getSearchString()))->setFgColor(colorGreyBlue); + lastFilter.clear(); +} + + +const string &TabTeam::getSearchString() const { + return lang.tl("Sök (X)#Ctrl+F"); +} + +void TabTeam::addToolbar(gdioutput &gdi) const { + + const int button_w=gdi.scaleLength(130); + + gdi.addButton(2+0*button_w, 2, button_w, "FormMode", + "Formulärläge", TeamCB, "", false, true).fixedCorner(); + gdi.check("FormMode", currentMode==0); + + gdi.addButton(2+1*button_w, 2, button_w, "TableMode", + "Tabelläge", TeamCB, "", false, true).fixedCorner(); + gdi.check("TableMode", currentMode==1); + +} + +void TabTeam::showTeamImport(gdioutput &gdi) { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Importera laguppställningar"); + + gdi.addString("", 10, "help:teamlineup"); + gdi.dropLine(); + gdi.setRestorePoint("TeamLineup"); + gdi.pushX(); + + gdi.fillRight(); + gdi.addInput("FileName", "", 40, 0, "Filnamn:"); + gdi.dropLine(0.9); + gdi.addButton("Browse", "Bläddra", TeamCB).setExtra("FileName"); + gdi.dropLine(3); + gdi.popX(); + gdi.fillDown(); + gdi.addCheckbox("OnlyExisting", "Använd befintliga deltagare", 0, false, + "Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka)"); + gdi.fillRight(); + gdi.addButton("DoImportTeams", "Importera", TeamCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", TeamCB).setCancel(); + + gdi.refresh(); +} + +void TabTeam::doTeamImport(gdioutput &gdi) { + string file = gdi.getText("FileName"); + bool useExisting = gdi.isChecked("OnlyExisting"); + + + csvparser csv; + map classNameToNumber; + vector cls; + oe->getClasses(cls, true); + for (size_t k = 0; k < cls.size();k++) { + classNameToNumber[cls[k]->getName()] = cls[k]->getNumStages(); + } + gdi.fillDown(); + csv.importTeamLineup(file, classNameToNumber, teamLineup); + + gdi.restore("TeamLineup", false); + + gdi.dropLine(); + for (size_t k = 0; k < teamLineup.size(); k++) { + string tdesc = teamLineup[k].teamClass +", " + teamLineup[k].teamName; + if (!teamLineup[k].teamClub.empty()) + tdesc += ", " + teamLineup[k].teamClub; + gdi.addStringUT(1, tdesc); + for (size_t j = 0; j < teamLineup[k].members.size(); j++) { + TeamLineup::TeamMember &member = teamLineup[k].members[j]; + if (member.name.empty()) + continue; + + string mdesc = " " + itos(j+1) + ". "; + bool warn = false; + + if (useExisting) { + pRunner r = findRunner(member.name, member.cardNo); + if (r != 0) + mdesc += r->getCompleteIdentification(); + else { + mdesc += member.name + lang.tl(" (ej funnen)"); + warn = true; + } + } + else { + mdesc += member.name + " (" + itos(member.cardNo) + ") " + member.club; + } + + if (!member.course.empty()) { + if (oe->getCourse(member.course)) + mdesc += " : " + member.course; + else { + mdesc += " : " + lang.tl("Banan saknas"); + warn = true; + } + } + + if (!member.cls.empty()) { + if (oe->getClass(member.cls)) + mdesc += " [" + member.cls + "]"; + else { + mdesc += " " + lang.tl("Klassen saknas"); + warn = true; + } + } + + TextInfo &ti = gdi.addStringUT(0, mdesc); + if (warn) + ti.setColor(colorRed); + } + gdi.dropLine(); + } + gdi.fillRight(); + gdi.addButton("ImportTeams", "<< Bakåt", TeamCB); + gdi.addButton("SaveTeams", "Spara laguppställningar", TeamCB).setDefault().setExtra(useExisting); + gdi.addButton("Cancel", "Avbryt", TeamCB).setCancel(); + gdi.refresh(); +} + +void TabTeam::saveTeamImport(gdioutput &gdi, bool useExisting) { + for (size_t k = 0; k < teamLineup.size(); k++) { + pClub club = !teamLineup[k].teamClub.empty() ? oe->getClubCreate(0, teamLineup[k].teamClub) : 0; + pTeam t = oe->addTeam(teamLineup[k].teamName, club ? club->getId() : 0, oe->getClass(teamLineup[k].teamClass)->getId()); + + for (size_t j = 0; j < teamLineup[k].members.size(); j++) { + TeamLineup::TeamMember &member = teamLineup[k].members[j]; + if (member.name.empty()) + continue; + + pRunner r = 0; + if (useExisting) { + r = findRunner(member.name, member.cardNo); + if (r && !member.course.empty()) { + pCourse pc = oe->getCourse(member.course); + r->setCourseId(pc ? pc->getId() : 0); + } + if (r && !member.cls.empty()) { + pClass rcls = oe->getClass(member.cls); + r->setClassId(rcls ? rcls->getId() : 0, true); + } + } + else { + r = oe->addRunner(member.name, member.club, 0, member.cardNo, 0, false); + + if (r && !member.course.empty()) { + pCourse pc = oe->getCourse(member.course); + r->setCourseId(pc ? pc->getId() : 0); + } + + if (r && !member.cls.empty()) { + pClass rcls = oe->getClass(member.cls); + r->setClassId(rcls ? rcls->getId() : 0, true); + } + } + + t->setRunner(j, r, false); + if (r) + r->synchronize(true); + } + + t->synchronize(); + gdi.dropLine(); + } + loadPage(gdi); +} + +pRunner TabTeam::findRunner(const string &name, int cardNo) const { + string n = canonizeName(name.c_str()); + + if (cardNo != 0) { + vector pr; + oe->getRunnersByCard(cardNo, pr); + for (size_t k = 0; k < pr.size(); k++) { + string a = canonizeName(pr[k]->getName().c_str()); + if (a == n) + return pr[k]; + } + } + else { + vector pr; + oe->getRunners(0, 0, pr, false); + for (size_t k = 0; k < pr.size(); k++) { + string a = canonizeName(pr[k]->getName().c_str()); + if (a == n) + return pr[k]; + } + } + return 0; +} + +void TabTeam::showAddTeamMembers(gdioutput &gdi) { + gdi.clearPage(false); + gdi.addString("", boldLarge, "Tillsätt tillfälliga anonyma lagmedlemmar"); + + gdi.addString("", 10, "help:anonymous_team"); + gdi.dropLine(); + gdi.pushX(); + + gdi.fillDown(); + gdi.addInput("Name", lang.tl("N.N."), 24, 0, "Anonymt namn:"); + gdi.fillDown(); + gdi.addCheckbox("OnlyRequired", "Endast på obligatoriska sträckor", 0, true); + gdi.addCheckbox("WithFee", "Med anmälningsavgift (lagets klubb)", 0, true); + + gdi.fillRight(); + gdi.addButton("DoAddTeamMembers", "Tillsätt", TeamCB).setDefault(); + gdi.addButton("Cancel", "Avbryt", TeamCB).setCancel(); + + gdi.refresh(); +} + +void TabTeam::doAddTeamMembers(gdioutput &gdi) { + vector t; + oe->getTeams(0, t, true); + bool onlyReq = gdi.isChecked("OnlyRequired"); + bool withFee = gdi.isChecked("WithFee"); + string nn = gdi.getText("Name"); + + for (size_t k = 0; k < t.size(); k++) { + pTeam mt = t[k]; + pClass cls = mt->getClassRef(); + if (cls == 0) + continue; + bool ch = false; + for (int j = 0; j < mt->getNumRunners(); j++) { + if (mt->getRunner(j) == 0) { + LegTypes lt = cls->getLegType(j); + if (onlyReq && lt == LTExtra || lt == LTIgnore || lt == LTParallelOptional) + continue; + pRunner r = 0; + if (withFee) { + r = oe->addRunner(nn, mt->getClubId(), 0, 0, 0, false); + r->synchronize(); + mt->setRunner(j, r, false); + r->addClassDefaultFee(true); + } + else { + r = oe->addRunnerVacant(0); + r->setName(nn, false); + //oe->addRunner(nn, oe->getVacantClub(), 0, 0, 0, false); + r->synchronize(); + mt->setRunner(j, r, false); + } + ch = true; + } + } + if (ch) { + mt->apply(false, 0, false); + mt->synchronize(); + for (int j = 0; j < mt->getNumRunners(); j++) { + if (mt->getRunner(j) != 0) { + mt->getRunner(j)->synchronize(); + } + } + } + } + + loadPage(gdi); +} + +void TabTeam::showRunners(gdioutput &gdi, const char *title, + const set< pair > &rToList, + int limitX, set &usedR) { + + if (rToList.empty()) + return; + + bool any = false; + for(set< pair >::const_iterator it = rToList.begin(); it != rToList.end(); ++it) { + if (usedR.count(it->second)) + continue; + usedR.insert(it->second); + + if (!any) { + gdi.addString("", boldText, title); + gdi.dropLine(1.2); + gdi.popX(); + any = true; + } + + if (gdi.getCX() > limitX) { + gdi.dropLine(1.5); + gdi.popX(); + } + + gdi.addString("SelectR", 0, "#" + it->first, TeamCB).setExtra(it->second); + } + + if (any) { + gdi.dropLine(2); + gdi.popX(); + } +} + +void TabTeam::processChangeRunner(gdioutput &gdi, pTeam t, int leg, pRunner r) { + if (r && t && leg < t->getNumRunners()) { + pRunner oldR = t->getRunner(leg); + gdioutput::AskAnswer ans = gdioutput::AnswerNo; + if (r == oldR) { + gdi.restore("SelectR"); + return; + } + else if (oldR) { + if (r->getTeam()) { + ans = gdi.askCancel("Vill du att X och Y byter sträcka?#" + + r->getName() + "#" + oldR->getName()); + } + else { + ans = gdi.askCancel("Vill du att X tar sträckan istället för Y?#" + + r->getName() + "#" + oldR->getName()); + } + } + else { + ans = gdi.askCancel("Vill du att X går in i laget?#" + r->getName()); + } + + if (ans == gdioutput::AnswerNo) + return; + else if (ans == gdioutput::AnswerCancel) { + gdi.restore("SelectR"); + return; + } + + save(gdi, true); + vector mp; + switchRunners(t, leg, r, oldR); + /*if (r->getTeam()) { + pTeam otherTeam = r->getTeam(); + int otherLeg = r->getLegNumber(); + otherTeam->setRunner(otherLeg, oldR, true); + if (oldR) + oldR->evaluateCard(true, mp, 0, true); + otherTeam->checkValdParSetup(); + otherTeam->apply(true, 0, false); + otherTeam->synchronize(true); + } + else if (oldR) { + t->setRunner(leg, 0, false); + t->synchronize(true); + oldR->setClassId(r->getClassId(), true); + oldR->evaluateCard(true, mp, 0, true); + oldR->synchronize(true); + } + + t->setRunner(leg, r, true); + r->evaluateCard(true, mp, 0, true); + t->checkValdParSetup(); + t->apply(true, 0, false); + t->synchronize(true);*/ + loadPage(gdi); + } +} + +void TabTeam::switchRunners(pTeam t, int leg, pRunner r, pRunner oldR) { + vector mp; + + if (r->getTeam()) { + pTeam otherTeam = r->getTeam(); + int otherLeg = r->getLegNumber(); + otherTeam->setRunner(otherLeg, oldR, true); + if (oldR) + oldR->evaluateCard(true, mp, 0, true); + otherTeam->checkValdParSetup(); + otherTeam->apply(true, 0, false); + otherTeam->synchronize(true); + } + else if (oldR) { + t->setRunner(leg, 0, false); + t->synchronize(true); + oldR->setClassId(r->getClassId(), true); + oldR->evaluateCard(true, mp, 0, true); + oldR->synchronize(true); + } + + t->setRunner(leg, r, true); + r->evaluateCard(true, mp, 0, true); + t->checkValdParSetup(); + t->apply(true, 0, false); + t->synchronize(true); +} + +void TabTeam::clearCompetitionData() { + shownRunners = 0; + shownDistinctRunners = 0; + teamId = 0; + inputId = 0; + timeToFill = 0; + currentMode = 0; +} + +bool TabTeam::warnDuplicateCard(gdioutput &gdi, string id, int cno, pRunner r, vector &allRCache) { + pRunner warnCardDupl = 0; + + if (r && !r->getCard()) { + if (allRCache.empty()) // Fill cache if not initialized + oe->getRunners(0, 0, allRCache, false); + + for (size_t k = 0; k < allRCache.size(); k++) { + if (!r->canShareCard(allRCache[k], cno)) { + warnCardDupl = allRCache[k]; + break; + } + } + } + + InputInfo &cardNo = dynamic_cast(gdi.getBaseInfo(id.c_str())); + if (warnCardDupl) { + cardNo.setBgColor(colorLightRed); + gdi.updateToolTip(id, "Brickan används av X.#" + warnCardDupl->getCompleteIdentification()); + cardNo.refresh(); + return warnCardDupl->getTeam() == r->getTeam(); + } + else { + if (cardNo.getBgColor() != colorDefault) { + cardNo.setBgColor(colorDefault); + gdi.updateToolTip(id, ""); + cardNo.refresh(); + } + return false; + } +} diff --git a/code/TabTeam.h b/code/TabTeam.h new file mode 100644 index 0000000..4d6bcfa --- /dev/null +++ b/code/TabTeam.h @@ -0,0 +1,93 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "tabbase.h" + +struct TeamLineup; + +class TabTeam : + public TabBase +{ +private: + bool save(gdioutput &gdi, bool dontReloadTeams); + + string lastSearchExpr; + stdext::hash_set lastFilter; + DWORD timeToFill; + int inputId; + int searchCB(gdioutput &gdi, int type, void *data); + + int teamId; + int classId; + void selectTeam(gdioutput &gdi, pTeam t); + void updateTeamStatus(gdioutput &gdi, pTeam t); + void loadTeamMembers(gdioutput &gdi, int ClassId, + int ClubId, pTeam t); + + int shownRunners; + int shownDistinctRunners; + const string &getSearchString() const; + + void fillTeamList(gdioutput &gdi); + void addToolbar(gdioutput &gdi) const; + + int currentMode; + + void showTeamImport(gdioutput &gdi); + void doTeamImport(gdioutput &gdi); + void saveTeamImport(gdioutput &gdi, bool useExisting); + void showAddTeamMembers(gdioutput &gdi); + void doAddTeamMembers(gdioutput &gdi); + + void showRunners(gdioutput &gdi, const char *title, + const set< pair > &rToList, + int limitX, set &usedR); + + + void processChangeRunner(gdioutput &gdi, pTeam t, int leg, pRunner r); + + pRunner findRunner(const string &name, int cardNo) const; + vector teamLineup; + + // Returns true if the warning concerns the same team + bool warnDuplicateCard(gdioutput &gdi, string id, int cno, pRunner r, vector &allRCache); + + void switchRunners(pTeam team, int leg, pRunner r, pRunner oldR); + + +protected: + void clearCompetitionData(); + +public: + + const char * getTypeStr() const {return "TTeamTab";} + TabType getType() const {return TTeamTab;} + + int teamCB(gdioutput &gdi, int type, void *data); + + bool loadPage(gdioutput &gdi, int id); + bool loadPage(gdioutput &gdi); + TabTeam(oEvent *oe); + ~TabTeam(void); + friend int teamSearchCB(gdioutput *gdi, int type, void *data); + +}; diff --git a/code/Table.cpp b/code/Table.cpp new file mode 100644 index 0000000..84928a7 --- /dev/null +++ b/code/Table.cpp @@ -0,0 +1,2316 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "Table.h" +#include "gdioutput.h" +#include "meos_util.h" +#include +#include +#include +#include "oEvent.h" +#include "localizer.h" +#include +#include "gdiconstants.h" +#include "meosexception.h" +#include "recorder.h" + +extern HINSTANCE hInst; +const char *tId="_TABLE_SEL"; + +const Table *TableSortIndex::table = 0; + +int Table::uniqueId = 1; + +Table::Table(oEvent *oe_, int rowH, + const string &name, const string &iName) +{ + id = uniqueId++; + commandLock = false; + oe=oe_; + tableName=name; + internalName = iName; + nTitles=0; + PrevSort=-1; + baseRowHeight=rowH; + rowHeight = 0; + highRow=-1; + highCol=-1; + colSelected=-1; + + editRow=-1; + editCol=-1; + drawFilterLabel=false; + currentSortColumn=-1; + hEdit=0; + + hdcCompatible=0; + hbmStored=0; + + hdcCompatibleCell = 0; + hbmStoredCell = 0; + partialCell = false; + + startSelect = false; + ownerCounter = 0; + clearCellSelection(0); + tableProp = -1; + dataPointer = -1; + + clearOnHide = true; + doAutoSelectColumns = true; + + generator = 0; + generatorPtr = 0; +} + +Table::~Table(void) +{ + assert(ownerCounter == 0); + if (hEdit) + DestroyWindow(hEdit); +} + + +void Table::releaseOwnership() { + ownerCounter--; + if (ownerCounter == 0) + delete this; +} + +void Table::clearCellSelection(gdioutput *gdi) { + upperRow = -1; + lowerRow = -1; + upperCol = -1; + lowerCol = -1; + if (gdi) { + HDC hDC = GetDC(gdi->getTarget()); + clearSelectionBitmap(gdi, hDC); + ReleaseDC(gdi->getTarget(), hDC); + } +} + +int Table::addColumn(const string &Title, int width, bool isnum, bool formatRight) { + ColInfo ri; + strcpy_s(ri.name, lang.tl(Title).c_str()); + ri.baseWidth = width; + ri.width = 0; + ri.padWidthZeroSort = 0; + ri.isnumeric = isnum; + ri.formatRight = formatRight; + Titles.push_back(ri); + columns.push_back(nTitles); + nTitles++; + return Titles.size()-1; +} + +int Table::addColumnPaddedSort(const string &title, int width, int padding, bool formatRight) { + ColInfo ri; + strcpy_s(ri.name, lang.tl(title).c_str()); + ri.baseWidth = width; + ri.width = 0; + ri.padWidthZeroSort = padding; + ri.isnumeric = false; + ri.formatRight = formatRight; + Titles.push_back(ri); + columns.push_back(nTitles); + nTitles++; + return Titles.size()-1; +} + + +void Table::moveColumn(int src, int target) +{ + if (src==target) + return; + + vector::iterator it_s=find(columns.begin(), columns.end(), src); + vector::iterator it_t=find(columns.begin(), columns.end(), target); + + if (it_s!=columns.end()) { + + if (it_s0 && idToRow.lookup(rowId, ix)) { + dataPointer = ix; + return; + } + + TableRow tr(nTitles, object); + tr.height=rowHeight; + tr.id = rowId; + TableSortIndex tsi; + + if (Data.empty()) { + sortIndex.clear(); + tsi.index=0; + sortIndex.push_back(tsi); + tsi.index=1; + sortIndex.push_back(tsi); + + tsi.index=2; + Data.resize(2, tr); + + for (unsigned i=0;i0) + idToRow[rowId]=Data.size(); + + dataPointer = Data.size(); + sortIndex.push_back(tsi); + Data.push_back(tr); +} + +void Table::set(int column, oBase &owner, int id, const string &data, bool canEdit, CellType type) +{ + if (dataPointer >= Data.size() || dataPointer<2) + throw std::exception("Internal table error: wrong data pointer"); + + TableRow &row=Data[dataPointer]; + TableCell &cell=row.cells[column]; + cell.contents=data; + cell.owner=&owner; + cell.id=id; + cell.canEdit=canEdit; + cell.type=type; +} + +void Table::filter(int col, const string &filt, bool forceFilter) +{ + const string &oldFilter=Titles[col].filter; + vector baseIndex; + + if (filt==oldFilter && (!forceFilter || filt.empty())) + return; + else if (strncmp(oldFilter.c_str(), filt.c_str(), oldFilter.length())==0) { + //Filter more... + baseIndex.resize(2); + baseIndex[0]=sortIndex[0]; + baseIndex[1]=sortIndex[1]; + swap(baseIndex, sortIndex); + Titles[col].filter=filt; + } + else { + //Filter less -> refilter all! + Titles[col].filter=filt; + sortIndex.resize(Data.size()); + for (size_t k=0; k '9')) + i++; + + int key = atoi(str + i); + Data[sortIndex[k].index].intKey = key; + if (key == 0) + Data[sortIndex[k].index].key = Data[sortIndex[k].index].cells[col].contents; + } + + if (hasDeci) { // Times etc. + for(size_t k=2; k '9')) + i++; + + int key = 0; + + while (str[i] >= '0' && str[i] <= '9') { + key = key * 10 + (str[i] - '0'); + i++; + } + + if (str[i] == ':' || str[i]==',' || str[i] == '.' || (str[i] == '-' && key != 0)) { + bool valid = true; + for (int j = 1; j <= 4; j++) { + if (valid && str[i+j] >= '0' && str[i+j] <= '9') + key = key * 10 + (str[i+j] - '0'); + else { + key *= 10; + valid = false; + } + } + } + else { + key *= 10000; + } + + Data[sortIndex[k].index].intKey = key; + if (key == 0) + Data[sortIndex[k].index].key = Data[sortIndex[k].index].cells[col].contents; + } + } + } + else { + if (Titles[col].padWidthZeroSort) { + for (size_t k=2; k 1) { + intKey |= unsigned(strBuff[1])<<8; + intKey |= unsigned(strBuff[2]); + } + } + } + else { + for (size_t k=2; k 1) { + intKey |= unsigned(strBuff[1])<<8; + intKey |= unsigned(strBuff[2]); + } + } + else { + intKey = 0xFEFEFEFE; + } + } + } + } + assert(TableSortIndex::table == 0); + TableSortIndex::table = this; + //DWORD sStart = GetTickCount(); + std::stable_sort(sortIndex.begin()+2, sortIndex.end()); + //DWORD sEnd = GetTickCount(); + //string st = itos(sEnd-sStart); + TableSortIndex::table = 0; + PrevSort=col; + + if (reverse) + std::reverse(sortIndex.begin()+2, sortIndex.end()); + } + else { + std::reverse(sortIndex.begin()+2, sortIndex.end()); + + if (PrevSort==col) + PrevSort=-(10+col); + else + PrevSort=col; + } +} + +int TablesCB(gdioutput *gdi, int type, void *data) +{ + if (type!=GUI_LINK || gdi->Tables.empty()) + return 0; + + TableInfo &tai=gdi->Tables.front(); + Table *t=tai.table; + + TextInfo *ti=(TextInfo *)data; + + + if (ti->id.substr(0,4)=="sort"){ + int col=atoi(ti->id.substr(4).c_str()); + t->sort(col); + } + + gdi->refresh(); + //gdi->Restore(); + //t->Render(*gdi); +//*/ + return 0; +} + +void Table::getDimension(gdioutput &gdi, int &dx, int &dy, bool filteredResult) const +{ + rowHeight = gdi.scaleLength(baseRowHeight); + + if (filteredResult) + dy = rowHeight * (1+sortIndex.size()); + else + dy = rowHeight * (1+max(2,Data.size())); + + dx=1; + for(size_t i=0;i=rc.right || yrc.bottom) + row=-1; + + bool ret = false; + + if (startSelect) { + int c = getColumn(x, true); + if (c != -1) + upperCol = c; + c = getRow(y, true); + if (c != -1 && c>=0) { + upperRow = max(c, 2); + } + + HDC hDC=GetDC(hWnd); + if (unsigned(highRow)=0 && col>=0) { + POINT pt = {x, y}; + ClientToScreen(hWnd, &pt); + HWND hUnder = WindowFromPoint(pt); + + if (hUnder == hWnd) { + //int index=sortIndex[row].index; + TableRow &trow=Data[row]; + TableCell &cell=trow.cells[col]; + + if (highRow!=row || highCol!=col) { + + HDC hDC=GetDC(hWnd); + + if (unsigned(highRow)= 2) { + DWORD c; + if (cell.canEdit) + c=RGB(240, 240, 150); + else + c=RGB(240, 200, 140); + + highlightCell(hDC, gdi, cell, c, 0,0); + } + + ReleaseDC(hWnd, hDC); + SetCapture(hWnd); + highCol=col; + highRow=row; + } + ret = true; + } + } + + if (ret) + return true; + + if (unsigned(highRow)(data); + Table &t = gdi->getTable(); + t.selection(*gdi, lbi.text, lbi.data); + } + return 0; +} + +void Table::selection(gdioutput &gdi, const string &text, int data) { + if (size_t(selectionRow) >= Data.size() || size_t(selectionCol) >= Titles.size()) + throw std::exception("Index out of bounds."); + + TableCell &cell = Data[selectionRow].cells[selectionCol]; + int id = Data[selectionRow].id; + string output = cell.contents; + cell.owner->inputData(cell.id, text, data, output, false); + cell.contents = output; + reloadRow(id); + RECT rc; + getRowRect(selectionRow, rc); + InvalidateRect(gdi.getTarget(), &rc, false); +} + +#ifndef MEOSDB + +bool Table::keyCommand(gdioutput &gdi, KeyCommandCode code) { + if (commandLock) + return false; + commandLock = true; + + try { + if (code == KC_COPY) + exportClipboard(gdi); + else if (code == KC_PASTE) { + importClipboard(gdi); + }else if (code == KC_DELETE) { + deleteSelection(gdi); + } + else if (code == KC_REFRESH) { + gdi.setWaitCursor(true); + update(); + autoAdjust(gdi); + gdi.refresh(); + } + else if (code == KC_INSERT) { + insertRow(gdi); + gdi.refresh(); + } + else if (code == KC_PRINT) { + gdioutput gdiPrint("temp", gdi.getScale(), gdi.getEncoding()); + gdiPrint.clearPage(false); + gdiPrint.print(getEvent(), this); + } + } + catch (...) { + commandLock = false; + throw; + } + + commandLock = false; + return false; +} + +#endif + +bool Table::deleteSelection(gdioutput &gdi) { + int r1, r2; + getRowRange(r1, r2); + if (r1 != -1 && r2 != -1 && r1<=r2) { + if (!gdi.ask("Vill du radera X rader från tabellen?#" + itos(r2-r1+1))) + return false; + gdi.setWaitCursor(true); + int failed = deleteRows(r1, r2); + gdi.refresh(); + gdi.setWaitCursor(false); + if (failed > 0) + gdi.alert("X rader kunde inte raderas.#" + itos(failed)); + } + return true; +} + +void Table::hide(gdioutput &gdi) { + try { + destroyEditControl(gdi); + } + catch (std::exception &ex) { + gdi.alert(ex.what()); + } + + clearCellSelection(0); + ReleaseCapture(); + if (clearOnHide) { + Data.clear(); + sortIndex.clear(); + idToRow.clear(); + clear(); + } +} + +void Table::clear() { + Data.clear(); + sortIndex.clear(); + idToRow.clear(); +} + +bool Table::destroyEditControl(gdioutput &gdi) { + colSelected=-1; + + if (hEdit) { + try { + if (!enter(gdi)) + return false; + } + catch (std::exception &) { + if (hEdit) { + DestroyWindow(hEdit); + hEdit=0; + } + throw; + } + if (hEdit) { + DestroyWindow(hEdit); + hEdit=0; + } + } + gdi.removeControl(tId); + + if (drawFilterLabel) { + drawFilterLabel=false; + gdi.refresh(); + } + + return true; +} + +bool Table::mouseLeftDown(gdioutput &gdi, int x, int y) { + partialCell = true; + clearCellSelection(&gdi); + + if (!destroyEditControl(gdi)) + return false; + + if (highRow==0) { + colSelected=highCol; + startX=x; + startY=y; + //sort(highCol); + //gdi.refresh(); + //mouseMove(gdi, x, y); + } + else if (highRow==1) { + //filter(highCol, "lots"); + RECT rc=Data[1].cells[columns[0]].absPos; + //rc.right=rc.left+tableWidth; + editRow=highRow; + editCol=highCol; + + hEdit=CreateWindowEx(0, "EDIT", Titles[highCol].filter.c_str(), + WS_TABSTOP|WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL|WS_BORDER, + rc.left+105, rc.top, tableWidth-105, (rc.bottom-rc.top-1), gdi.getTarget(), + 0, hInst, 0); + drawFilterLabel=true; + SendMessage(hEdit, EM_SETSEL, 0, -1); + SetFocus(hEdit); + SendMessage(hEdit, WM_SETFONT, (WPARAM) gdi.getGUIFont(), 0); + gdi.refresh(); + } + else { + SetFocus(gdi.getHWND()); + SetCapture(gdi.getTarget()); + lowerCol = getColumn(x); + lowerRow = getRow(y); + startSelect = true; + } + return false; +} + +bool Table::mouseLeftDblClick(gdioutput &gdi, int x, int y) +{ + clearCellSelection(&gdi); + + if (!destroyEditControl(gdi)) + return false; + + if (unsigned(highRow)>=Data.size() || unsigned(highCol)>=Titles.size()) { + return false; + } + + + if (highRow != 0 && highRow != 1) { + if (editCell(gdi, highRow, highCol)) + return true; + } + return false; +} + +bool Table::editCell(gdioutput &gdi, int row, int col) { + TableCell &cell = Data[row].cells[col]; + + if (cell.type == cellAction) { + ReleaseCapture(); + gdi.makeEvent("CellAction", internalName, cell.id, cell.owner ? cell.owner->getId() : 0, false); + return true; + } + + if (!cell.canEdit) { + MessageBeep(-1); + return true; + } + ReleaseCapture(); + + editRow = row; + editCol = col; + + RECT &rc=cell.absPos; + + if (cell.type == cellSelection || cell.type == cellCombo) { + selectionRow = row; + selectionCol = col; + + vector< pair > out; + size_t selected = 0; + cell.owner->fillInput(cell.id, out, selected); + + int width = 40; + for (size_t k = 0; k(width, 8*out[k].first.length()); + + if (cell.type == cellSelection) { + gdi.addSelection(rc.left+gdi.OffsetX, rc.top+gdi.OffsetY, tId, + max(int((rc.right-rc.left+1)/gdi.scale), width), (rc.bottom-rc.top)*10, + tblSelectionCB).setExtra(id); + } + else { + gdi.addCombo(rc.left+gdi.OffsetX, rc.top+gdi.OffsetY, tId, + max(int((rc.right-rc.left+1)/gdi.scale), width), (rc.bottom-rc.top)*10, + tblSelectionCB).setExtra(id); + } + gdi.addItem(tId, out); + gdi.selectItemByData(tId, selected); + return true; + } + else if (cell.type==cellEdit) { + hEdit=CreateWindowEx(0, "EDIT", cell.contents.c_str(), + WS_TABSTOP|WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL|WS_BORDER, + rc.left, rc.top, rc.right-rc.left+1, (rc.bottom-rc.top), gdi.getTarget(), + 0, hInst, 0); + SendMessage(hEdit, EM_SETSEL, 0, -1); + SetFocus(hEdit); + SendMessage(hEdit, WM_SETFONT, (WPARAM) gdi.getGUIFont(), 0); + return true; + } + + return false; +} + +RGBQUAD RGBA(BYTE r, BYTE g, BYTE b, BYTE a) { + RGBQUAD q = {b,g,r,a}; + return q; +} + +RGBQUAD RGBA(DWORD c) { + RGBQUAD q = {GetBValue(c),GetGValue(c),GetRValue(c),0}; + return q; +} + +RGBQUAD transform(RGBQUAD src, double scale) { + src.rgbRed = BYTE(min(src.rgbRed * scale, 255.0)); + src.rgbGreen = BYTE(min(src.rgbGreen * scale, 255.0)); + src.rgbBlue = BYTE(min(src.rgbBlue * scale, 255.0)); + return src; +} + +void gradRect(HDC hDC, int left, int top, int right, int bottom, + bool horizontal, RGBQUAD c1, RGBQUAD c2) { + + TRIVERTEX vert[2]; + vert [0] .x = left; + vert [0] .y = top; + vert [0] .Red = 0xff00 & (DWORD(c1.rgbRed)<<8); + vert [0] .Green = 0xff00 & (DWORD(c1.rgbGreen)<<8); + vert [0] .Blue = 0xff00 & (DWORD(c1.rgbBlue)<<8); + vert [0] .Alpha = 0xff00 & (DWORD(c1.rgbReserved)<<8); + + vert [1] .x = right; + vert [1] .y = bottom; + vert [1] .Red = 0xff00 & (DWORD(c2.rgbRed)<<8); + vert [1] .Green = 0xff00 & (DWORD(c2.rgbGreen)<<8); + vert [1] .Blue = 0xff00 & (DWORD(c2.rgbBlue)<<8); + vert [1] .Alpha = 0xff00 & (DWORD(c2.rgbReserved)<<8); + + GRADIENT_RECT gr[1]; + gr[0].UpperLeft=0; + gr[0].LowerRight=1; + + if (horizontal) + GradientFill(hDC,vert, 2, gr, 1,GRADIENT_FILL_RECT_H); + else + GradientFill(hDC,vert, 2, gr, 1,GRADIENT_FILL_RECT_V); +} + +void Table::initEmpty() { + if (Data.empty()) { + addRow(0,0); + Data.resize(2, TableRow(nTitles,0)); + sortIndex.resize(2); + } +} + +void drawSymbol(gdioutput &gdi, HDC hDC, int height, + const TextInfo &ti, const string &symbol, bool highLight) { + int cx = ti.xp - gdi.GetOffsetX() + ti.xlimit/2; + int cy = ti.yp - gdi.GetOffsetY() + height/2 - 2; + int h = int(height * 0.4); + int w = h/3; + h-=2; + + RGBQUAD a,b; + if (highLight) { + a = RGBA(32, 114, 14, 0); + b = RGBA(64, 211, 44, 0); + } + else { + a = RGBA(32, 114, 114, 0); + b = RGBA(84, 231, 64, 0); + } + gradRect(hDC, cx-w, cy-h, cx+w, cy+h, false, a, b); + gradRect(hDC, cx-h, cy-w, cx+h, cy+w, false, a, b); + + POINT pt; + MoveToEx(hDC, cx-w, cy-h, &pt); + SelectObject(hDC, GetStockObject(DC_PEN)); + SetDCPenColor(hDC, RGB(14, 80, 7)); + LineTo(hDC, cx+w, cy-h); + LineTo(hDC, cx+w, cy-w); + LineTo(hDC, cx+h, cy-w); + LineTo(hDC, cx+h, cy+w); + LineTo(hDC, cx+w, cy+w); + LineTo(hDC, cx+w, cy+h); + LineTo(hDC, cx-w, cy+h); + LineTo(hDC, cx-w, cy+w); + LineTo(hDC, cx-h, cy+w); + LineTo(hDC, cx-h, cy-w); + LineTo(hDC, cx-w, cy-w); + LineTo(hDC, cx-w, cy-h); +} + + +void Table::highlightCell(HDC hDC, gdioutput &gdi, const TableCell &cell, DWORD color, int dx, int dy) +{ + SelectObject(hDC, GetStockObject(DC_BRUSH)); + SelectObject(hDC, GetStockObject(NULL_PEN)); + + SetDCBrushColor(hDC, color); + + RECT rc=cell.absPos; + rc.left+=dx; + rc.right+=dx; + rc.top+=dy; + rc.bottom+=dy; + + Rectangle(hDC, rc.left+1, rc.top, + rc.right+2, rc.bottom); + + TextInfo ti; + + if (cell.type == cellAction && cell.contents[0] == '@') { + ti.xp = rc.left + gdi.OffsetX; + ti.yp = rc.top + gdi.OffsetY; + ti.xlimit = rc.right - rc.left; + + drawSymbol(gdi, hDC, rowHeight, ti, cell.contents, true); + //SetDCPenColor(hDC, RGB(190,190,190)); + } + else { + gdi.formatString(ti, hDC); + SetBkMode(hDC, TRANSPARENT); + rc.left+=4; + rc.top+=2; + DrawText(hDC, cell.contents.c_str(), -1, &rc, DT_LEFT|DT_NOPREFIX); + } +} + +void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen) +{ + gdi.resetLast(); + initEmpty(); + updateDimension(gdi); + + table_xp=dx-gdi.OffsetX; + table_yp=dy-gdi.OffsetY; + + if (currentSortColumn==-1) + sort(0); + + int wi, he; + getDimension(gdi, wi, he, true); + + tableWidth=wi; + tableHeight=he; + + //Find first and last row + int yreltop=(screen.top-(dy-gdi.OffsetY)-rowHeight+1)/rowHeight; + int yrelbottom=(screen.bottom-(dy-gdi.OffsetY)-1)/rowHeight; + + int firstRow=max(yreltop,0); + int lastRow=min(yrelbottom, int(sortIndex.size())); + + int firstCol=0; + int lastCol=columns.size(); + + xpos.resize(columns.size()+1); + + xpos[0]=dx-gdi.OffsetX; + for (size_t i=1;i<=columns.size();i++) + xpos[i]=xpos[i-1]+Titles[columns[i-1]].width+1; + + //Find first and last visible column + while(firstCol0 && xpos[lastCol-1]>screen.right) + lastCol--; + + SelectObject(hDC, GetStockObject(DC_BRUSH)); + SelectObject(hDC, GetStockObject(DC_PEN)); + + SetDCPenColor(hDC, RGB(190,190,190)); + SetDCBrushColor(hDC, RGB(60,25,150)); + + //Title + TextInfo ti; + gdi.formatString(ti, hDC); + HLS hls; + hls.RGBtoHLS(GetSysColor(COLOR_ACTIVECAPTION)); + hls.lighten(2); + hls.saturation = min(90,hls.saturation); + DWORD lightColor = hls.HLStoRGB(); + + if (firstRow==0 && lastRow>=0) { + //Rectangle(hDC, dx-gdi.OffsetX, dy-gdi.OffsetY, + // dx+tableWidth-gdi.OffsetX, dy+rowHeight-gdi.OffsetY); + RGBQUAD c1 = RGBA(GetSysColor(COLOR_ACTIVECAPTION)); + gradRect(hDC, dx-gdi.OffsetX, dy-gdi.OffsetY, + dx+tableWidth-gdi.OffsetX, dy+rowHeight-gdi.OffsetY, false, + c1, transform(c1, 0.7)); + + RECT rc; + rc.left=dx+5-gdi.OffsetX; + rc.right=rc.left+gdi.scaleLength(150); + rc.top=dy+3-gdi.OffsetY; + rc.bottom=rc.top+rowHeight; + ti.format = 1; + gdi.formatString(ti, hDC); + SetTextColor(hDC, RGB(255,255,255)); + DrawText(hDC, lang.tl(tableName).c_str(), -1, &rc, DT_LEFT|DT_NOPREFIX); + DrawText(hDC, lang.tl(tableName).c_str(), -1, &rc, DT_CALCRECT|DT_NOPREFIX); + ti.format = 0; + gdi.formatString(ti, hDC); + SetTextColor(hDC, RGB(255,255,255)); + char bf[256]; + string info = lang.tl(string("sortering: X, antal rader: Y#") + Titles[currentSortColumn].name + "#" + itos(sortIndex.size()-2)); + //sprintf_s(bf, .c_str(), + // Titles[currentSortColumn].name, int(sortIndex.size())-2); + rc.left=rc.right+30; + rc.right=dx + tableWidth - gdi.OffsetX - 10; + DrawText(hDC, info.c_str(), info.length(), &rc, DT_LEFT|DT_NOPREFIX); + + SetTextColor(hDC, RGB(0,0,0)); + + if (drawFilterLabel) { + SetDCBrushColor(hDC, RGB(100,200,100)); + + Rectangle(hDC, dx-gdi.OffsetX, dy+2*rowHeight-gdi.OffsetY, + dx+tableWidth-gdi.OffsetX, dy+3*rowHeight-gdi.OffsetY); + + rc.left=dx+5-gdi.OffsetX; + rc.right=rc.left+100; + rc.top=dy+3+2*rowHeight-gdi.OffsetY; + rc.bottom=rc.top+rowHeight; + char tbf[2]; + tbf[0]=Titles[editCol].name[0]; + tbf[1]=0; + CharLower(tbf); + string filter = lang.tl("Urval %c%s:")+" "; + sprintf_s(bf, filter.c_str(), tbf[0], + Titles[editCol].name+1, int(sortIndex.size())-2); + + DrawText(hDC, bf, -1, &rc, DT_RIGHT|DT_NOPREFIX); + } + } + + int yp; + yp=dy+rowHeight; + + if (firstRow<=2 && lastRow>=1) { + string filterText = lang.tl("Urval..."); + + for (int k=firstCol;k(lastRow + margin, sortIndex.size()); + for (int k1 = rStart; k1 < rEnd; k1++){ + int yp = dy + rowHeight*(k1+1); + TableRow &tr = Data[sortIndex[k1].index]; + for(size_t k=0;k= sortIndex.size()) + throw std::exception("Index out of range"); + const TableRow &tr = Data[sortIndex[row].index]; + + if ( size_t(col) >= columns.size()) + throw std::exception("Index out of range"); + + col = columns[col]; + return *((TableCell *)&tr.cells[col]); +} + +void Table::clearSelectionBitmap(gdioutput *gdi, HDC hDC) +{ + if (gdi) + restoreSelection(*gdi, hDC); + + if (hdcCompatibleCell) { + DeleteDC(hdcCompatibleCell); + hdcCompatibleCell = 0; + } + + if (hbmStoredCell) { + DeleteObject(hbmStoredCell); + hbmStoredCell = 0; + } +} + +void Table::restoreSelection(gdioutput &gdi, HDC hDC) { + if (partialCell) { + RECT rc = lastCell; + rc.left -= gdi.OffsetX; + rc.right -= gdi.OffsetX; + rc.top -= gdi.OffsetY; + rc.bottom -= gdi.OffsetY; + InvalidateRect(gdi.getTarget(), &rc, false); + partialCell = false; + } + else if (hdcCompatibleCell) { + //Restore bitmap + int cx = lastCell.right - lastCell.left + 1; + int cy = lastCell.bottom - lastCell.top + 1; + int x = lastCell.left - 1 - gdi.OffsetX; + int y = lastCell.top - 1 - gdi.OffsetY; + BitBlt(hDC, x, y, cx, cy, hdcCompatibleCell, 0, 0, SRCCOPY); + } +} + +void Table::drawSelection(gdioutput &gdi, HDC hDC, bool forceDraw) { + bool modified = false; + if (lowerColOld != lowerCol || upperCol != upperColOld || + lowerRow != lowerRowOld || upperRow != upperRowOld) { + modified = true; + restoreSelection(gdi, hDC); + } + + if (lowerCol != -1 && upperCol != -1 && + lowerRow != -1 && upperRow != -1 && + (forceDraw || modified)) { + TableCell &c1 = Data[lowerRow].cells[lowerCol]; + TableCell &c2 = Data[upperRow].cells[upperCol]; + RECT rc; + rc.top = min(c1.absPos.top, c2.absPos.top) + gdi.OffsetY; + rc.left = min(c1.absPos.left, c2.absPos.left) + gdi.OffsetX; + rc.right = max(c1.absPos.right, c2.absPos.right) + 1 + gdi.OffsetX; + rc.bottom = max(c1.absPos.bottom, c2.absPos.bottom) + gdi.OffsetY; + + if (modified) { + int cx=rc.right-rc.left + 1; + int cy=rc.bottom-rc.top + 1; + + clearSelectionBitmap(&gdi, hDC); + + lastCell = rc; + int x = lastCell.left - 1 - gdi.OffsetX; + int y = lastCell.top - 1 - gdi.OffsetY; + int maxX, maxY; + gdi.getTargetDimension(maxX, maxY); + + if (x<=0 || y<=0 || (x+cx)>=maxX || (y+cy)>=maxY) { + partialCell = true; + } + else { + hdcCompatibleCell = CreateCompatibleDC(hDC); + hbmStoredCell = CreateCompatibleBitmap(hDC, cx, cy); + + // Select the bitmaps into the compatible DC. + SelectObject(hdcCompatibleCell, hbmStoredCell); + BitBlt(hdcCompatibleCell, 0, 0, cx, cy, hDC, x, y, SRCCOPY); + partialCell = false; + } + } + + SelectObject(hDC, GetStockObject(NULL_BRUSH)); + SelectObject(hDC, GetStockObject(DC_PEN)); + SetDCPenColor(hDC, RGB(0,0, 128)); + Rectangle(hDC, rc.left - gdi.OffsetX, rc.top - gdi.OffsetY, + rc.right - gdi.OffsetX, rc.bottom - gdi.OffsetY); + + lowerColOld = lowerCol; + upperColOld = upperCol; + lowerRowOld = lowerRow; + upperRowOld = upperRow; + } +} + +void Table::scrollToCell(gdioutput &gdi, int row, int col) { + if (size_t(row) >= Data.size() || size_t(col) >= Data[row].cells.size()) + return; + const RECT &rc = Data[row].cells[col].absPos; + int maxX, maxY; + gdi.getTargetDimension(maxX, maxY); + int xo = gdi.OffsetX; + int yo = gdi.OffsetY; + if (rc.right > maxX) { + xo = gdi.OffsetX + (rc.right - maxX) + 10; + } + else if (rc.left < 0) { + xo = gdi.OffsetX + rc.left - 10; + } + + if (rc.bottom > maxY) { + yo = gdi.OffsetY + (rc.bottom - maxY) + 10; + } + else if (rc.top < 0) { + yo = gdi.OffsetY + rc.top - 10; + } + + if (xo != gdi.OffsetX || yo != gdi.OffsetY) { + gdi.setOffset(xo, yo, true); + //gdi.refreshFast(); + //Sleep(300); + } +} + +void Table::print(gdioutput &gdi, HDC hDC, int dx, int dy) +{ + vector widths(columns.size()); + vector skip(columns.size(), true); + int rh = 0; + + for (size_t j=0;j(widths[j], ti.textRect.right-ti.textRect.left); + rh = max(rh, ti.textRect.bottom-ti.textRect.top); + } + const int extra = 10; + + for (size_t j=0;j(widths[j], + int(1.1*(ti.textRect.right-ti.textRect.left)+extra)); + rh = max(rh, ti.textRect.bottom-ti.textRect.top); + } + } + } + + rh = int(rh*1.3); + vector adj_xp(columns.size()); + int w = widths[0]; + for (size_t j=1;j= Data.size() || size_t(editCol) >= Data[editRow].cells.size()) + throw std::exception("Index out of bounds"); + + string output; + TableCell &cell=Data[editRow].cells[editCol]; + cell.owner->inputData(cell.id, bf, 0, output, false); + cell.contents=output; + if (hEdit != 0) + DestroyWindow(hEdit); + hEdit=0; + reloadRow(Data[editRow].id); + RECT rc; + getRowRect(editRow, rc); + InvalidateRect(gdi.getTarget(), &rc, false); +} + +const string &Table::getTableText(gdioutput &gdi, int editRow, int editCol) { + if (size_t(editRow) >= Data.size() || size_t(editCol) >= Data[editRow].cells.size()) + throw std::exception("Index out of bounds"); + + string output; + TableCell &cell=Data[editRow].cells[editCol]; + + return cell.contents; +} + + +bool Table::enter(gdioutput &gdi) +{ + if (hEdit) { + if (unsigned(editRow)=2) { + + { + string cmd; + if (gdi.getRecorder().recording()) + cmd = "setTableText(" + itos(editRow) + ", " + itos(editCol) + ", \"" + string(bf) + "\");"; + setTableText(gdi, editRow, editCol, bf); + gdi.getRecorder().record(cmd); + return true; + }/* + catch(const std::exception &ex) { + string msg(ex.what()); + gdi.alert(msg); + }*/ + } + else if (editRow==1) {//Filter + filter(editCol, bf); + DestroyWindow(hEdit); + hEdit=0; + drawFilterLabel = false; + gdi.refresh(); + return true; + } + } + } + else if (gdi.hasField(tId)) { + ListBoxInfo lbi; + gdi.getSelectedItem(tId, lbi); + + if (lbi.isCombo()) { + if (size_t(selectionRow) < Data.size() && size_t(selectionCol) < Titles.size()) { + selection(gdi, lbi.text, lbi.data); + } + } + } + return false; +} + +void Table::escape(gdioutput &gdi) +{ + if (hEdit) { + DestroyWindow(hEdit); + hEdit = 0; + } + gdi.removeControl(tId); + drawFilterLabel=false; + gdi.refresh(); +} + +bool Table::inputChange(gdioutput &gdi, HWND hdt) +{ + if (hEdit==hdt) { + + if (drawFilterLabel) { + char bf[256]; + GetWindowText(hEdit, bf, 256); + filter(editCol, bf); + updateDimension(gdi); + gdi.refresh(); + } + + return true; + } + return false; +} + +int Table::getColumn(int x, bool limit) const +{ + if (columns.empty()) + return -1; + + if (x=int(sortIndex.size())) + r = sortIndex.size() - 1; + } + if (r>=0 && r= int(Data.size())) + throw std::exception("Index out of bounds."); + + TableRow &row=Data[index]; + oBase *obj = row.getObject(); + if (obj) { + TableUpdateInfo tui; + tui.object = obj; + tui.id = rowId; + oe->generateTableData(internalName, *this, tui); + } +} + +vector Table::getColumns() const +{ + vector cols(Titles.size()); + + // Get selected columns + for (size_t k=0; k &sel) +{ + vector newcols; + + for (size_t k=0; k::const_iterator it = sel.begin(); + + while(it != sel.end()) { + if (count(newcols.begin(), newcols.end(), *it)==0) + newcols.push_back(*it); + ++it; + } + + swap(columns, newcols); + doAutoSelectColumns = false; +} + +void Table::resetColumns() +{ + columns.resize(Titles.size()); + + for (size_t k=0;kgenerateTableData(internalName, *this, tui); + } + else { + generator(*this, generatorPtr); + } + + //Refilter all + for (size_t k=0;k= sortIndex.size()) + throw std::exception("Index out of range"); + const TableRow &tr = Data[sortIndex[k].index]; + html += ""; + for (size_t j = col1; j<= size_t(col2); j++) { + if ( j >= columns.size()) + throw std::exception("Index out of range"); + int col = columns[j]; + const TableCell &cell = tr.cells[col]; + html += "" + cell.contents + ""; + if (j == col1) + txt += cell.contents; + else + txt += "\t" + cell.contents; + } + txt += "\r\n"; + html += ""; + } + + html += ""; +} + +void Table::getRowRange(int &rowLo, int &rowHi) const { + int row1 = -1, row2 = -1; + for (size_t k = 0; k < sortIndex.size(); k++) { + if (upperRow == sortIndex[k].index) + row1 = k; + if (lowerRow == sortIndex[k].index) + row2 = k; + } + rowLo = min(row1, row2); + rowHi = max(row1, row2); +} + +void Table::getColRange(int &colLo, int &colHi) const { + int col1 = -1, col2 = -1; + for (size_t k = 0; k < columns.size(); k++) { + if (upperCol == columns[k]) + col1 = k; + if (lowerCol == columns[k]) + col2 = k; + } + colLo = min(col1, col2); + colHi = max(col1, col2); +} + +void Table::exportClipboard(gdioutput &gdi) +{ + string str;// = "
ab
"; + string txt; + + int col1 = -1, col2 = -1; + getColRange(col1, col2); + /*for (size_t k = 0; k < columns.size(); k++) { + if (upperCol == columns[k]) + col1 = k; + if (lowerCol == columns[k]) + col2 = k; + }*/ + + int row1 = -1, row2 = -1; + getRowRange(row1, row2); + /*for (size_t k = 0; k < sortIndex.size(); k++) { + if (upperRow == sortIndex[k].index) + row1 = k; + if (lowerRow == sortIndex[k].index) + row2 = k; + }*/ + + if (col1 == -1 || col2 == -1 || row1 == -1 || row2 == -1) + return; + + getExportData(min(col1, col2), max(col1, col2), + min(row1, row2), max(row1, row2), str, txt); + + gdi.copyToClipboard(str, true, txt); + + /*if (OpenClipboard(gdi.getHWND()) != false) { + + EmptyClipboard(); + + const char *HTML = str.c_str(); + size_t len = str.length() + 1; + + size_t bsize = len*2; + char *bf = new char[bsize]; + + //Convert to UTF-8 + WORD *wide = new WORD[len]; + MultiByteToWideChar(CP_ACP, 0, HTML, -1, LPWSTR(wide), len);//To Wide + memset(bf, 0, bsize); + WideCharToMultiByte(CP_UTF8, 0, LPCWSTR(wide), -1, bf, bsize, NULL, NULL); + delete[] wide; + + len = strlen(bf) + 1; + + const char cbd[]= + "Version:0.9\n" + "StartHTML:%08u\n" + "EndHTML:%08u\n" + "StartFragment:%08u\n" + "EndFragment:%08u\n"; + + char head[256]; + sprintf_s(head, cbd, 1,0,0,0); + + int offset=strlen(head); + //Fill header with relevant information + int ho_start = offset; + int ho_end = offset + len; + sprintf_s(head, cbd, offset,offset+len,ho_start,ho_end); + + + HANDLE hMem=GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, offset+len); + LPVOID data=GlobalLock(hMem); + + memcpy(LPSTR(data), head, offset); + memcpy(LPSTR(data)+offset, bf, len); + + GlobalUnlock(hMem); + + // Text format + HANDLE hMemText = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, txt.length()+1); + LPVOID dataText=GlobalLock(hMemText); + memcpy(LPSTR(dataText), txt.c_str() , txt.length()+1); + GlobalUnlock(hMemText); + + + UINT CF_HTML = RegisterClipboardFormat("HTML format"); + + SetClipboardData(CF_HTML, hMem); + SetClipboardData(CF_TEXT, hMemText); + + delete[] bf; + CloseClipboard(); + }*/ +} + + +void Table::importClipboard(gdioutput &gdi) +{ + if (!canPaste()) + throw std::exception("Operationen stöds ej"); + + string str; + if (OpenClipboard(gdi.getHWND()) != false) { + HANDLE data = GetClipboardData(CF_TEXT); + if (data) { + LPVOID lptstr = GlobalLock(data); + if (lptstr) { + str = string(((char*)lptstr)); + GlobalUnlock(data); + } + } + CloseClipboard(); + } + if (!str.empty()) { + // Parse raw data + vector< vector > table(1); + const char *ptr = str.c_str(); + string word; + while (*ptr) { + if (*ptr != '\t' && *ptr != '\r' && *ptr != '\n') { + word.append(ptr, 1); + } + else if (*ptr == '\t') { + table.back().push_back(word); + word.clear(); + } + else if (*ptr == '\n') { + table.back().push_back(word); + table.push_back(vector()); + word.clear(); + } + ++ptr; + } + if (!word.empty()) + table.back().push_back(word); + else if (table.back().empty()) + table.pop_back(); + + if (table.empty()) + return; + + int rowS = 2; + int colS = 0; + + size_t tw = 0; + for (size_t k = 0; k columns.size()) + throw std::exception("Antalet columner i urklippet är större än antalet kolumner i tabellen."); + + if (upperRow == -1) { + if (!gdi.ask("Vill du klistra in X nya rader i tabellen?#"+itos(table.size()))) + return; + rowS = sortIndex.size(); // Add new rows + } + else { + int col1 = -1, col2 = -1; + getColRange(col1, col2); + int row1 = -1, row2 = -1; + getRowRange(row1, row2); + + if ( (row1 + table.size()) > sortIndex.size() ) + throw std::exception("Antalet rader i urklipp får inte plats i selektionen."); + + if ( (col1 + tw) > columns.size() ) + throw std::exception("Antalet kolumner i urklipp får inte plats i selektionen."); + + bool wrongSize = false; + + if (row1 != row2 && (row2 - row1 + 1) != table.size()) + wrongSize = true; + + if (col1 != col2 && (col2 - col1 +1 ) != tw) + wrongSize = true; + + if (wrongSize && !gdi.ask("Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall?")) + return; + + rowS = row1; + colS = col1; + } + + bool addedRow = false; + + for (size_t k = 0; k sortIndex.size()) { + throw std::exception("Index out of range"); + } + else if ( (rowS + k) == sortIndex.size()) { + // Add data + TableUpdateInfo tui; + tui.doAdd = true; + oe->generateTableData(internalName, *this, tui); + addedRow = true; + //sortIndex.push_back(TableSortIndex(Data.size()-1, "")); + } + + TableRow &tr = Data[sortIndex[rowS + k].index]; + for (size_t j = 0; j= columns.size()) + throw std::exception("Index out of range"); + int col = columns[colS + j]; + + TableCell &cell=tr.cells[col]; + string output; + + size_t index = 0; + + if (cell.type==cellSelection || cell.type==cellCombo) { + vector< pair > out; + size_t selected = 0; + cell.owner->fillInput(cell.id, out, selected); + index = -1; + for (size_t i = 0; iinputData(cell.id, table[k][j], index, output, false); + cell.contents = output; + } + else if (cell.type == cellCombo) { + cell.owner->inputData(cell.id, table[k][j], index, output, false); + cell.contents = output; + } + } + catch(const std::exception &ex) { + string msg(ex.what()); + } + } + } + + if (addedRow) { + TableUpdateInfo tui; + tui.doRefresh = true; + oe->generateTableData(internalName, *this, tui); + + updateDimension(gdi); + int dx,dy; + getDimension(gdi, dx, dy, true); + gdi.scrollTo(0, dy + table_yp + gdi.OffsetY); + } + gdi.refresh(); + } +} + +int Table::deleteRows(int row1, int row2) +{ + if (!canDelete()) + throw std::exception("Operationen stöds ej"); + + int failed = 0; + for (size_t k = row1; k<=size_t(row2); k++) { + if ( k >= sortIndex.size()) + throw std::exception("Index out of range"); + const TableRow &tr = Data[sortIndex[k].index]; + oBase *ob = tr.cells[0].owner; + if (!ob) + throw std::exception("Null pointer exception"); + if (ob->canRemove()) + ob->remove(); + else + failed++; + } + + clearCellSelection(0); + clearSelectionBitmap(0,0); + update(); + return failed; +} + +void Table::insertRow(gdioutput &gdi) { + if (!canInsert()) + throw std::exception("Operationen stöds ej"); + + TableUpdateInfo tui; + tui.doAdd = true; + tui.doRefresh = true; + oe->generateTableData(internalName, *this, tui); + int dx,dy; + updateDimension(gdi); + getDimension(gdi, dx, dy, true); + gdi.scrollTo(0, dy + table_yp + gdi.OffsetY); +} + +void Table::autoAdjust(gdioutput &gdi) { + initEmpty(); + if (Titles.empty()) + return; + HDC hDC = GetDC(gdi.getTarget()); + RECT rc = {0,0,0,0}; + TextInfo ti; + string filterText = lang.tl("Urval..."); + string filterName = lang.tl("Namn"); + ti.format = 0; + gdi.formatString(ti, hDC); + int sum = 0; + for (size_t k = 0; k(1, dsize/1973); + int sameCount = 0; + for (size_t r = 0; r < dsize; r+=sample) { + const TableCell &c = Data[r].cells[k]; + if (r==0 && c.contents == filterName) + w = max(w, 100); + + const string &str = r != 1 ? c.contents : filterText; + int len = str.length(); + if (len == minlen) { + sameCount++; + if (sameCount > 40) + continue; + } + + if (len > minlen - diff) { + sameCount = 0; + if (Titles[k].isnumeric && r>2) + DrawText(hDC, (str + "55").c_str(), len, &rc, DT_CALCRECT|DT_NOPREFIX); + else + DrawText(hDC, str.c_str(), len, &rc, DT_CALCRECT|DT_NOPREFIX); + w = max(w, rc.right - rc.left); + if (r>2) + minlen = max(len, minlen); + } + } + Titles[k].baseWidth = int( (w + 25)/ gdi.getScale()); + } + if (columns.empty()) + columns.push_back(0); + + for (size_t k = 0; k empty(Titles.size(), true); + int nonEmpty = 0; + + // Filter away empty and all-equal columns + for (size_t k = 0; k 2 && Data[2].cells[k].type == cellAction) + nonEmpty++; + empty[k] = false; + } + else { + if (Data[2].cells[k].type == cellAction) { + nonEmpty++; + empty[k] = false; + } + else { + const string &first = Data.size() > 3 ? + Data[2].cells[k].contents : _EmptyString; + + for (size_t r = 2; r 1) { + columns.clear(); + string id = lang.tl("Id"); + string mod = lang.tl("Ändrad"); + for (size_t k = 0; k. + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include +#include "oBase.h" +#include "inthashmap.h" + +#define TableXMargin 40 +#define TableYMargin 30 + +enum CellType {cellEdit, cellSelection, cellAction, cellCombo}; +enum KeyCommandCode; + +class Table; +typedef void (*GENERATETABLEDATA)(Table &table, void *ptr); + + +struct TableUpdateInfo { + bool doAdd; + bool doRefresh; + oBase *object; + int id; + TableUpdateInfo() : doAdd(false), object(0), id(0), doRefresh(false) {} +}; + + +class TableCell +{ + string contents; + RECT absPos; + + DWORD id; + oBase *owner; + bool canEdit; + CellType type; + + friend class TableRow; + friend class Table; + friend int tblSelectionCB(gdioutput *gdi, int type, void *data); +}; + +class TableRow +{ +protected: + string key; + int intKey; + + vector cells; + int id; + + string *SortString; + int sInt; + + int ypos; + int height; + oBase *ob; + +public: + oBase *getObject() const {return ob;} + void setObject(oBase &obj); + bool operator<(const TableRow &r){return *SortString<*r.SortString;} + static bool cmpint(const TableRow &r1, const TableRow &r2) {return r1.sInt Titles; + vector xpos; + unsigned nTitles; + int PrevSort; + mutable int rowHeight; + int baseRowHeight; + vector Data; + size_t dataPointer; // Insertation pointer + vector sortIndex; + vector columns; + inthashmap idToRow; + //highlight + int highRow; + int highCol; + + // Selected columns. For drag/drop and sort + int colSelected; + int startX; + int startY; + + //Edit selection + int editRow; + int editCol; + + // Selected rectangle + int upperRow; + int lowerRow; + int upperCol; + int lowerCol; + + int upperRowOld; + int lowerRowOld; + int upperColOld; + int lowerColOld; + + bool startSelect; + + HWND hEdit; + + //For moving objects + HDC hdcCompatible; + HBITMAP hbmStored; + int lastX; + int lastY; + + // For cell seletion + HDC hdcCompatibleCell; + HBITMAP hbmStoredCell; + RECT lastCell; + bool partialCell; + + //static bool filterMatchString(const string &c, const char *filt); + void highlightCell(HDC hDC, gdioutput &gdi, const TableCell &cell, DWORD color, int dx, int dy); + + void moveCell(HDC hDC, gdioutput &gdi, const TableCell &cell, int dx, int dy); + void startMoveCell(HDC hDC, const TableCell &cell); + void stopMoveCell(HDC hDC, const TableCell &cell, int dx, int dy); + void restoreCell(HDC hDC, const TableCell &cell); + + void moveColumn(int src, int target); + + int tableWidth; + int tableHeight; + bool drawFilterLabel; + int currentSortColumn; + + void initEmpty(); + + int getColumn(int x, bool limit = false) const; + int getRow(int y, bool limit = false) const; + + void redrawCell(gdioutput &gdi, HDC hDC, int c, int r); + + //Draw coordinates + int table_xp; + int table_yp; + + oEvent *oe; + + void clearSelectionBitmap(gdioutput *gdi, HDC hDC); + void restoreSelection(gdioutput &gdi, HDC hDC); + + void drawSelection(gdioutput &gdi, HDC hDC, bool forceDraw); + TableCell &getCell(int row, int col) const; //Index as displayed + void scrollToCell(gdioutput &gdi, int row, int col); + + bool destroyEditControl(gdioutput &gdi); + + void getExportData(int col1, int col2, int row1, int row2, + string &html, string &txt) const; + + // Delete rows in selected range. Return number of rows that could not be removed + int deleteRows(int row1, int row2); + + void getRowRange(int &rowLo, int &rowHi) const; + void getColRange(int &colLo, int &colHi) const; + int ownerCounter; + DWORD tableProp; + + int selectionRow; + int selectionCol; + + void getRowRect(int row, RECT &rc) const; + + bool compareRow(int indexA, int indexB) const; +public: + + void setTableText(gdioutput &gdi, int editRow, int editCol, const string &bf); + const string &getTableText(gdioutput &gdi, int editRow, int editCol); + + int getTableId() const {return id;} + static void resetTableIds() {uniqueId = 1;} + + void setGenerator(GENERATETABLEDATA gen, void *genPtr) { + generatorPtr = genPtr; + generator = gen; + } + + void clear(); + void setClearOnHide(bool coh) {clearOnHide = coh;} + int getNumDataRows() const; + + void clearCellSelection(gdioutput *gdi); + + /// Return translated table name + const string& getTableName() const {return tableName;} + /// Get the internal identifier of the table + const string& getInternalName() const {return internalName;} + + bool hasAutoSelect() const {return doAutoSelectColumns;} + + void updateDimension(gdioutput &gdi); + void selection(gdioutput &gdi, const string &text, int data); + + enum { + CAN_PASTE = 1, + CAN_INSERT = 2, + CAN_DELETE = 4, + }; + + bool canPaste() const {return (tableProp & CAN_PASTE) != 0;} + bool canInsert() const {return (tableProp & CAN_INSERT) != 0;} + bool canDelete() const {return (tableProp & CAN_DELETE) != 0;} + void setTableProp(DWORD w) {tableProp = w;} + + void hide(gdioutput &gdi); //Ensure no edit contol is visible + void addOwnership() {ownerCounter++;} + void releaseOwnership(); + + void autoAdjust(gdioutput &gdi); // Adjust column widths + void autoSelectColumns(); + + void insertRow(gdioutput &gdi); // Insert a new row in the table + bool deleteSelection(gdioutput &gdi); + void setPosition(int x, int y, int maxX, int maxY) {t_xpos = x, t_ypos = y; t_maxX = maxX, t_maxY = maxY;} + void exportClipboard(gdioutput &gdi); + void importClipboard(gdioutput &gdi); + + + bool hasEditControl() {return hEdit!=0;} + + struct ColSelection { + ColSelection() : selected(false), index(0) {} + string name; + bool selected; + int index; + }; + + vector< ColSelection > getColumns() const; + void selectColumns(const set &sel); + + oEvent *getEvent() const {return oe;} + void getDimension(gdioutput &gdi, int &dx, int &dy, bool filteredResult) const; + void draw(gdioutput &gdi, HDC hDC, int dx, int dy, + const RECT &screen); + + void print(gdioutput &gdi, HDC hDC, int dx, int dy); + + //Returns true if capture is taken + bool mouseMove(gdioutput &gdi, int x, int y); + bool mouseLeftDown(gdioutput &gdi, int x, int y); + bool mouseLeftUp(gdioutput &gdi, int x, int y); + bool mouseLeftDblClick(gdioutput &gdi, int x, int y); + + bool editCell(gdioutput &gdi, int row, int col); + + bool keyCommand(gdioutput &gdi, KeyCommandCode code); + void sort(int col); + void filter(int col, const string &filt, bool forceFilter=false); + + int addColumn(const string &Title, int width, bool isnum, bool formatRight = false); + int addColumnPaddedSort(const string &title, int width, int padding, bool formatRight = false); + + void reserve(size_t siz); + + TableRow *getRowById(int rowId); + void addRow(int rowId, oBase *object); + void set(int column, oBase &owner, int id, const string &data, + bool canEdit=true, CellType type=cellEdit); + + //Reload a row from data + void reloadRow(int rowId); + + bool UpDown(gdioutput &gdi, int direction); + bool tabFocus(gdioutput &gdi, int direction); + bool enter(gdioutput &gdi); + void escape(gdioutput &gdi); + bool inputChange(gdioutput &gdi, HWND hEdit); + void resetColumns(); + void update(); + + Table(oEvent *oe_, int rowHeight, + const string &name, const string &tname); + ~Table(void); + + friend struct TableSortIndex; +}; + +struct TableSortIndex { + //TableSortIndex(const Table &t) : table(&t) {} + const static Table *table; + int index; + bool operator<(const TableSortIndex &t) const {return table->compareRow(index,t.index);} + //{return table->Data[index].key < table->Data[t.index].key;} + //bool operator<=(const TableSortIndex &t) const {return table->Data[index].key <= table->Data[t.index].key;} +}; + +enum {TID_CLASSNAME, TID_COURSE, TID_NUM, TID_ID, TID_MODIFIED, +TID_RUNNER, TID_CLUB, TID_START, TID_TIME, +TID_FINISH, TID_STATUS, TID_RUNNINGTIME, TID_PLACE, +TID_CARD, TID_TEAM, TID_LEG, TID_CONTROL, TID_CODES, TID_FEE, TID_PAID, +TID_INPUTTIME, TID_INPUTSTATUS, TID_INPUTPOINTS, TID_INPUTPLACE, +TID_NAME, TID_NATIONAL, TID_SEX, TID_YEAR, TID_INDEX, TID_ENTER, TID_STARTNO}; diff --git a/code/TimeStamp.cpp b/code/TimeStamp.cpp new file mode 100644 index 0000000..5417c9d --- /dev/null +++ b/code/TimeStamp.cpp @@ -0,0 +1,134 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// TimeStamp.cpp: implementation of the TimeStamp class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "meos.h" +#include "TimeStamp.h" +#include + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +const __int64 minYearConstant = 2014 - 1601; + +TimeStamp::TimeStamp() +{ + Time=0; + //Update(); +} + +TimeStamp::~TimeStamp() +{ + +} + +void TimeStamp::update(TimeStamp &ts) +{ + Time=max(Time, ts.Time); +} + +void TimeStamp::update() +{ + SYSTEMTIME st; + GetLocalTime(&st); + + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + + __int64 ¤ttime=*(__int64*)&ft; + + Time=unsigned((currenttime/10000000L) - minYearConstant*365*24*3600); +} + +int TimeStamp::getAge() const +{ + SYSTEMTIME st; + GetLocalTime(&st); + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + __int64 ¤ttime=*(__int64*)&ft; + + int CTime=int((currenttime/10000000)-minYearConstant*365*24*3600); + + return CTime-Time; +} + +string TimeStamp::getStamp() const +{ + __int64 ft64=(__int64(Time)+minYearConstant*365*24*3600)*10000000; + FILETIME &ft=*(FILETIME*)&ft64; + SYSTEMTIME st; + FileTimeToSystemTime(&ft, &st); + + char bf[32]; + sprintf_s(bf, "%d%02d%02d%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); + + return bf; +} + +string TimeStamp::getStampString() const +{ + __int64 ft64=(__int64(Time)+minYearConstant*365*24*3600)*10000000; + FILETIME &ft=*(FILETIME*)&ft64; + SYSTEMTIME st; + FileTimeToSystemTime(&ft, &st); + + char bf[32]; + sprintf_s(bf, "%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); + + return bf; +} + +void TimeStamp::setStamp(string s) +{ + if (s.size()<14) + return; + SYSTEMTIME st; + memset(&st, 0, sizeof(st)); + + //const char *ptr=s.c_str(); + //sscanf(s.c_str(), "%4hd%2hd%2hd%2hd%2hd%2hd", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); + st.wYear=atoi(s.substr(0, 4).c_str()); + st.wMonth=atoi(s.substr(4, 2).c_str()); + st.wDay=atoi(s.substr(6, 2).c_str()); + st.wHour=atoi(s.substr(8, 2).c_str()); + st.wMinute=atoi(s.substr(10, 2).c_str()); + st.wSecond=atoi(s.substr(12, 2).c_str()); + + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + + __int64 ¤ttime=*(__int64*)&ft; + + Time = unsigned((currenttime/10000000)-minYearConstant*365*24*3600); +} diff --git a/code/TimeStamp.h b/code/TimeStamp.h new file mode 100644 index 0000000..af73c52 --- /dev/null +++ b/code/TimeStamp.h @@ -0,0 +1,49 @@ +// TimeStamp.h: interface for the TimeStamp class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TIMESTAMP_H__CC16BFC5_ECD9_4D76_AC98_79F802314B65__INCLUDED_) +#define AFX_TIMESTAMP_H__CC16BFC5_ECD9_4D76_AC98_79F802314B65__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class TimeStamp +{ + unsigned int Time; +public: + void setStamp(string s); + string getStamp() const; + string getStampString() const; + int getAge() const; + unsigned int getModificationTime() const {return Time;} + + void update(); + void update(TimeStamp &ts); + TimeStamp(); + virtual ~TimeStamp(); +}; + +#endif // !defined(AFX_TIMESTAMP_H__CC16BFC5_ECD9_4D76_AC98_79F802314B65__INCLUDED_) diff --git a/code/autotask.cpp b/code/autotask.cpp new file mode 100644 index 0000000..e4e27cd --- /dev/null +++ b/code/autotask.cpp @@ -0,0 +1,338 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include + +#include "oEvent.h" +#include "autotask.h" +#include "TabAuto.h" +#include "TabSI.h" +#include "meos_util.h" +#include "socket.h" + +const int SYNC_FACTOR = 4; + +//#define DEBUGPRINT +//#define NODELAY + +AutoTask::AutoTask(HWND hWnd, oEvent &oeIn, gdioutput &gdiIn) : hWndMain(hWnd), oe(oeIn), gdi(gdiIn) { + currentRevision = 0; + lock = false; + lastSynchTime = 0; + lastTriedSynchTime = 0; + + autoSaveTimeBase = autoSaveTime = oe.getPropertyInt("AutoSaveTimeOut", (3*60+15)*1000); + synchBaseTime = oe.getPropertyInt("SynchronizationTimeOut", 2500); + maxDelay = oe.getPropertyInt("MaximumSpeakerDelay", 10000)/SYNC_FACTOR; +} + +void AutoTask::autoSave() { + if (!oe.empty()) { + string msg; + try { + if (oe.getNumRunners() > 500) + gdi.setWaitCursor(true); + + DWORD tic = GetTickCount(); + oe.save(); + DWORD toc = GetTickCount(); + + if (toc > tic) { + int timeToSave = toc - tic; + int interval = max(autoSaveTimeBase, timeToSave * 10); + if (abs(interval - autoSaveTime) > 4000) { + autoSaveTime = interval; + resetSaveTimer(); + } + } + } + catch(std::exception &ex) { + msg=ex.what(); + } + catch(...) { + msg="Ett okänt fel inträffade."; + } + + if (!msg.empty()) { + gdi.alert(msg); + } + else + gdi.addInfoBox("", "Tävlingsdata har sparats.", 10); + + gdi.setWaitCursor(false); + + } +} + +void AutoTask::resetSaveTimer() { + KillTimer(hWndMain, 1); + SetTimer(hWndMain, 1, autoSaveTime, 0); //Autosave +} + +void AutoTask::setTimers() { + SetTimer(hWndMain, 2, 100, 0); //Interface timeout + SetTimer(hWndMain, 3, synchBaseTime, 0); //DataSync +} + +void AutoTask::interfaceTimeout(const vector &windows) { + TabAuto *tabAuto = dynamic_cast(gdi.getTabs().get(TAutoTab)); + TabSI *tabSI = dynamic_cast(gdi.getTabs().get(TSITab)); + + if (lock) + return; + lock = true; + + string msg; + try { + DWORD tick = GetTickCount(); + for (size_t k = 0; kCheckInterfaceTimeouts(tick); + } + + if (tabAuto) + tabAuto->timerCallback(gdi); + + if (tabSI) + while(tabSI->checkpPrintQueue(gdi)); + } + catch(std::exception &ex) { + msg=ex.what(); + } + catch(...) { + msg="Ett okänt fel inträffade."; + } + if (!msg.empty()) { + gdi.alert(msg); + gdi.setWaitCursor(false); + } + lock = false; +} + +void AutoTask::addSynchTime(DWORD tick) { + if (tick > 1000 * 60) + return; // Ignore extreme times + + if (synchQueue.size () > 8) + synchQueue.pop_front(); + + synchQueue.push_back(tick); +} + +DWORD AutoTask::getAvgSynchTime() { +#ifdef NODELAY + return 0; +#else + double res = 0; + for (size_t k = 0; k < synchQueue.size(); k++) { + double sq = synchQueue[k]; + res += sq*sq; + } + + if (res > 0) + res = sqrt(res) / double(synchQueue.size()); + + return min(int(res), maxDelay); +#endif +} + +void AutoTask::synchronize(const vector &windows) { + DWORD tic = GetTickCount(); + DWORD avg = getAvgSynchTime(); + //OutputDebugString(("AVG Update Time: " + itos(avg)).c_str()); + if (tic > lastSynchTime) { + DWORD since = tic - lastSynchTime; + if (since < avg * SYNC_FACTOR) { + //OutputDebugString((" skipped: " + itos(since) + "\n").c_str()); + return; + } + //else + //OutputDebugString((" check: tsl = " + itos(since) + "\n").c_str()); + } + else + lastSynchTime = tic; + + if (oe.hasDirectSocket()) { + // Clear any incomming messages (already in db) + vector pi; + oe.getDirectSocket().getPunchQueue(pi); + } + + // Store last time we tried to synch + lastTriedSynchTime = tic; + + if (synchronizeImpl(windows)) { + DWORD toc = GetTickCount(); + if (toc > tic) + addSynchTime(toc-tic); + + lastSynchTime = toc; +#ifdef DEBUGPRINT + OutputDebugString((" updated: " + itos(toc-tic) + "\n").c_str()); +#endif + } + + //OutputDebugString(" no update\n"); +} + +void AutoTask::advancePunchInformation(const vector &windows) { + DWORD tic = GetTickCount(); + DWORD avg = getAvgSynchTime(); + //OutputDebugString(("Direct Update Time: " + itos(avg)).c_str()); + if (tic > lastSynchTime) { + DWORD since = tic-lastSynchTime; + if (since < avg * SYNC_FACTOR) { + //OutputDebugString((" skipped: " + itos(since) + "\n").c_str()); + return; + } + } + else + lastSynchTime = tic; + + DWORD since = tic - lastTriedSynchTime; + if (since > DWORD(synchBaseTime*4)) { // Synchronize all instead. + synchronize(windows); + return; + } + + if (advancePunchInformationImpl(windows)) { + DWORD toc = GetTickCount(); + if (toc > tic) + addSynchTime(toc-tic); + lastSynchTime = toc; +#ifdef DEBUGPRINT + OutputDebugString((" direct update: " + itos(toc-tic) + "\n").c_str()); +#endif + } +} + +bool AutoTask::synchronizeImpl(const vector &windows) { + if (lock) + return false; + lock = true; + + DWORD d=0; + bool doSync = false; + bool doSyncPunch = false; + TabAuto *tabAuto = dynamic_cast(gdi.getTabs().get(TAutoTab)); + + for (size_t k = 0; kgetData("DataSync", d)) { + doSync = true; + } + if (windows[k] && windows[k]->getData("PunchSync", d)) { + doSyncPunch = true; + doSync = true; + } + } + + string msg; + bool ret = false; + try { + if (doSync || (tabAuto && tabAuto->synchronize)) { + + if (tabAuto && tabAuto->synchronizePunches) + doSyncPunch = true; + + if ( oe.autoSynchronizeLists(doSyncPunch) || oe.getRevision() != currentRevision) { + ret = true; + if (getAvgSynchTime() > 1000) + gdi.setWaitCursor(true); + + if (doSync) { + for (size_t k = 0; kmakeEvent("DataUpdate", "autosync", 0, 0, false); + } + catch(std::exception &ex) { + msg = ex.what(); + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + } + } + } + + if (tabAuto) + tabAuto->syncCallback(gdi); + } + } + oe.resetSQLChanged(false, true); + } + catch (std::exception &ex) { + msg = ex.what(); + } + catch (...) { + msg = "Ett okänt fel inträffade."; + } + + currentRevision = oe.getRevision(); + + if (!msg.empty()) { + gdi.alert(msg); + } + lock = false; + gdi.setWaitCursor(false); + return ret; +} + +bool AutoTask::advancePunchInformationImpl(const vector &windows) { + DWORD d=0; + bool doSync = false; + bool doSyncPunch = false; + + for (size_t k = 0; kgetData("DataSync", d)) { + doSync = true; + } + if (windows[k] && windows[k]->getData("PunchSync", d)) { + doSyncPunch = true; + doSync = true; + } + } + + //string msg; + try { + if (oe.hasDirectSocket()) { + //OutputDebugString("Advance punch info\n"); + vector pi; + oe.getDirectSocket().getPunchQueue(pi); + bool ret = oe.advancePunchInformation(windows, pi, doSyncPunch, doSync); + if (ret) + oe.resetSQLChanged(false, true); + + return ret; + } + } + catch (std::exception &ex) { + OutputDebugString(ex.what()); + //msg = ex.what(); + } + catch (...) { + //msg = "Ett okänt fel inträffade."; + } + + return false; +} diff --git a/code/autotask.h b/code/autotask.h new file mode 100644 index 0000000..060cafe --- /dev/null +++ b/code/autotask.h @@ -0,0 +1,74 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include + +class oEvent; +class gdioutput; + +class AutoTask { +private: + oEvent &oe; + gdioutput &gdi; + AutoTask &operator=(const AutoTask &); + + bool synchronizeImpl(const vector &gdi); + bool advancePunchInformationImpl(const vector &windows); + + long currentRevision; + bool lock; + + deque synchQueue; + deque directQueue; + + DWORD lastSynchTime; + DWORD lastTriedSynchTime; + void addSynchTime(DWORD tick); + DWORD getAvgSynchTime(); + + HWND hWndMain; + + int autoSaveTime; + int autoSaveTimeBase; + + int synchBaseTime; + int maxDelay; // The maximal delay between syncs +public: + + void setTimers(); + + void resetSaveTimer(); + + AutoTask(HWND hWnd, oEvent &oe, gdioutput &gdi); + void autoSave(); + /** Trigger timed text updates and gdi timeouts, service timeouts. */ + void interfaceTimeout(const vector &windows); + + /** Read updates from SQL (if connected) and update windows due to changed competition data.*/ + void synchronize(const vector &windows); + + /** Fetch fast advance information.*/ + void advancePunchInformation(const vector &windows); +}; diff --git a/code/bitmap1.bmp b/code/bitmap1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b750a47767fd552979c9d010d6bdac93e0d23d60 GIT binary patch literal 8694 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 Dgu!65 literal 0 HcmV?d00001 diff --git a/code/classconfiginfo.cpp b/code/classconfiginfo.cpp new file mode 100644 index 0000000..549d62c --- /dev/null +++ b/code/classconfiginfo.cpp @@ -0,0 +1,207 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include "oEvent.h" +#include "classconfiginfo.h" +#include "meos_util.h" + +void ClassConfigInfo::clear() { + individual.clear(); + relay.clear(); + patrol.clear(); + + legNStart.clear(); + raceNStart.clear(); + + legResult.clear(); + raceNRes.clear(); + + rogainingClasses.clear(); + timeStart.clear(); + hasMultiCourse = false; + hasMultiEvent = false; + hasRentedCard = false; + classWithoutCourse.clear(); + maximumLegNumber = 0; + results = false; + starttimes = false; +} + +bool ClassConfigInfo::empty() const { + return individual.empty() && relay.empty() && patrol.empty() && raceNStart.empty(); +} + +void ClassConfigInfo::getIndividual(set &sel) const { + sel.insert(individual.begin(), individual.end()); +} + +void ClassConfigInfo::getRelay(set &sel) const { + sel.insert(relay.begin(), relay.end()); +} + +void ClassConfigInfo::getTeamClass(set &sel) const { + sel.insert(relay.begin(), relay.end()); + sel.insert(patrol.begin(), patrol.end()); + if (!raceNStart.empty()) + sel.insert(raceNRes[0].begin(), raceNRes[0].end()); +} + + +bool ClassConfigInfo::hasTeamClass() const { + return !relay.empty() || !patrol.empty() || !raceNRes.empty(); +} + +void ClassConfigInfo::getPatrol(set &sel) const { + sel.insert(patrol.begin(), patrol.end()); +} + +void ClassConfigInfo::getRogaining(set &sel) const { + sel.insert(rogainingClasses.begin(), rogainingClasses.end()); +} + + +void ClassConfigInfo::getRaceNStart(int race, set &sel) const { + if (size_t(race) < raceNStart.size() && !raceNStart[race].empty()) + sel.insert(raceNStart[race].begin(), raceNStart[race].end()); + else + sel.clear(); +} + +void ClassConfigInfo::getLegNStart(int leg, set &sel) const { + if (size_t(leg) < legNStart.size() && !legNStart[leg].empty()) + sel.insert(legNStart[leg].begin(), legNStart[leg].end()); + else + sel.clear(); +} + +void ClassConfigInfo::getRaceNRes(int race, set &sel) const { + if (size_t(race) < raceNRes.size() && !raceNRes[race].empty()) + sel.insert(raceNRes[race].begin(), raceNRes[race].end()); + else + sel.clear(); +} + +void ClassConfigInfo::getLegNRes(int leg, set &sel) const { + map >::const_iterator res = legResult.find(leg); + if (res != legResult.end()) + sel.insert(res->second.begin(), res->second.end()); + else + sel.clear(); +} + +void oEvent::getClassConfigurationInfo(ClassConfigInfo &cnf) const +{ + oClassList::const_iterator it; + cnf.clear(); + + cnf.hasMultiEvent = hasPrevStage() || hasNextStage(); + + for (it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + cnf.maximumLegNumber = max(cnf.maximumLegNumber, it->getNumStages()); + ClassType ct = it->getClassType(); + + if (it->isRogaining()) + cnf.rogainingClasses.push_back(it->getId()); + + if (it->getCourse() == 0) + cnf.classWithoutCourse.push_back(it->getName()); //MultiCourse not analysed... + + if ( !it->hasCoursePool() ) { + for (size_t k = 0; k< it->MultiCourse.size(); k++) { + if (it->MultiCourse[k].size() > 1) + cnf.hasMultiCourse = true; + } + } + if (ct == oClassIndividual) { + cnf.individual.push_back(it->getId()); + if (cnf.timeStart.empty()) + cnf.timeStart.resize(1); + cnf.timeStart[0].push_back(it->getId()); + } + else if (ct == oClassPatrol) + cnf.patrol.push_back(it->getId()); + else if (ct == oClassRelay) { + cnf.relay.push_back(it->getId()); + + if (cnf.legNStart.size() < it->getNumStages()) + cnf.legNStart.resize(it->getNumStages()); + + for (size_t k = 0; k < it->getNumStages(); k++) { + StartTypes st = it->getStartType(k); + if (st == STDrawn || st == STHunting) { + cnf.legNStart[k].push_back(it->getId()); + if (cnf.timeStart.size() <= k) + cnf.timeStart.resize(k+1); + cnf.timeStart[k].push_back(it->getId()); + } + + LegTypes lt = it->getLegType(k); + if (!it->isOptional(k) && !it->isParallel(k) && lt != LTGroup) { + int trueN, order; + it->splitLegNumberParallel(k, trueN, order); + cnf.legResult[trueN].push_back(it->getId()); + } + } + } + else if (ct == oClassIndividRelay) { + if (cnf.raceNStart.size() < it->getNumStages()) + cnf.raceNStart.resize(it->getNumStages()); + if (cnf.raceNRes.size() < it->getNumStages()) + cnf.raceNRes.resize(it->getNumStages()); + + for (size_t k = 0; k < it->getNumStages(); k++) { + StartTypes st = it->getStartType(k); + if (st == STDrawn || st == STHunting) { + cnf.raceNStart[k].push_back(it->getId()); + if (cnf.timeStart.size() <= k) + cnf.timeStart.resize(k+1); + cnf.timeStart[k].push_back(it->getId()); + + } + LegTypes lt = it->getLegType(k); + if (lt != LTIgnore && lt != LTExtra && lt != LTGroup) + cnf.raceNRes[k].push_back(it->getId()); + } + } + } + + oRunnerList::const_iterator rit; + for (rit = Runners.begin(); rit != Runners.end(); ++rit) { + if (rit->isRemoved()) + continue; + + if (rit->getDCI().getInt("CardFee") != 0) { + cnf.hasRentedCard = true; + } + RunnerStatus st = rit->getStatus(); + if (st != StatusUnknown && st != StatusDNS && st != StatusNotCompetiting) + cnf.results = true; + + if (rit->getStartTime() > 0) + cnf.starttimes = true; + } +} + diff --git a/code/classconfiginfo.h b/code/classconfiginfo.h new file mode 100644 index 0000000..44cbb31 --- /dev/null +++ b/code/classconfiginfo.h @@ -0,0 +1,90 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include + +class ClassConfigInfo { + friend class oEvent; +private: + bool results; + bool starttimes; + int maximumLegNumber; +public: + vector < vector > timeStart; + vector individual; + vector relay; + vector patrol; + + vector< vector > legNStart; + vector< vector > raceNStart; + + map > legResult; // main leg number -> class selection + vector< vector > raceNRes; + + vector rogainingClasses; + + // True if predefined forking + bool hasMultiCourse; + + bool hasMultiEvent; + + // True if there are rented cards + bool hasRentedCard; + + vector classWithoutCourse; + + void clear(); + + bool hasIndividual() const {return individual.size()>0;} + bool hasRelay() const {return relay.size()>0;} + bool hasPatrol() const {return patrol.size()>0;} + bool hasRogaining() const {return rogainingClasses.size()>0;} + bool empty() const; + + // Return true of this is an event in a sequence of events. + bool isMultiStageEvent() const {return hasMultiEvent;} + void getIndividual(set &sel) const; + void getRelay(set &sel) const; + void getPatrol(set &sel) const; + void getTeamClass(set &sel) const; + void getRogaining(set &sel) const; + + bool hasTeamClass() const; + + void getRaceNStart(int race, set &sel) const; + void getLegNStart(int leg, set &sel) const; + + void getRaceNRes(int race, set &sel) const; + void getLegNRes(int leg, set &sel) const; + + void getTimeStart(int leg, set &sel) const; + + // Return true if the competiont has any results + bool hasResults() const {return results;} + + // Return true if the competition defines any start times; + bool hasStartTimes() const {return starttimes;} + + int getNumLegsTotal() const {return maximumLegNumber;} +}; diff --git a/code/cp1250.lng b/code/cp1250.lng new file mode 100644 index 0000000..65d075a --- /dev/null +++ b/code/cp1250.lng @@ -0,0 +1 @@ +encoding = EASTEUROPE diff --git a/code/cp1255.lng b/code/cp1255.lng new file mode 100644 index 0000000..e4f939e --- /dev/null +++ b/code/cp1255.lng @@ -0,0 +1 @@ +encoding = HEBREW diff --git a/code/csvparser.cpp b/code/csvparser.cpp new file mode 100644 index 0000000..6f12245 --- /dev/null +++ b/code/csvparser.cpp @@ -0,0 +1,1254 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// csvparser.cpp: implementation of the csvparser class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "meos.h" +#include "csvparser.h" +#include "oEvent.h" +#include "SportIdent.h" +#include "meos_util.h" +#include "localizer.h" +#include "importformats.h" + +#include "meosexception.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +#include + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +const int externalSourceId = 17000017; + +csvparser::csvparser() +{ + LineNumber=0; +} + +csvparser::~csvparser() +{ + +} + +int csvparser::iscsv(const char *file) +{ + fin.open(file); + + if (!fin.good()) + return false; + + char bf[2048]; + fin.getline(bf, 2048); + + while(fin.good() && strlen(bf)<3) + fin.getline(bf, 2048); + + fin.close(); + + vector sp; + split(bf, sp); + + if (sp.size()==1 && strcmp(sp[0], "RAIDDATA")==0) + return 3; + + if (sp.size()<5)//No csv + return 0; + + if (_stricmp(sp[1], "Descr")==0 || _stricmp(sp[1], "Namn")==0 + || _stricmp(sp[1], "Descr.")==0 || _stricmp(sp[1], "Navn")==0) //OS-fil (SWE/ENG)?? + return 2; + else return 1; //OE?! +} + +RunnerStatus ConvertOEStatus(int i) +{ + switch(i) + { + case 0: + return StatusOK; + case 1: // Ej start + return StatusDNS; + case 2: // Utg. + return StatusDNF; + case 3: // Felst. + return StatusMP; + case 4: //Disk + return StatusDQ; + case 5: //Maxtid + return StatusMAX; + } + return StatusUnknown; +} + + +//Stno;Descr;Block;nc;Start;Time;Classifier;Club no.;Cl.name;City;Nat;Cl. no.;Short;Long;Legs;Num1;Num2;Num3;Text1;Text2;Text3;Start fee;Paid;Surname;First name;YB;S;Start;Finish;Time;Classifier;Chip;Rented;Database Id;Surname;First name;YB;S;Start;Finish;Time;Classifier;Chip;Rented;Database Id;Surname;First name;YB;S;Start;Finish;Time;Classifier;Chip;Rented;Database Id;(may be more) ... + +bool csvparser::ImportOS_CSV(oEvent &event, const char *file) +{ + enum {OSstno=0, OSdesc=1, OSstart=4, OStime=5, OSstatus=6, OSclubno=7, OSclub=9, + OSnat=10, OSclassno=11, OSclass=12, OSlegs=14, OSfee=21, OSpaid=22}; + + const int Offset=23; + const int PostSize=11; + + enum {OSRsname=0, OSRfname=1, OSRyb=2, OSRsex=3, OSRstart=4, + OSRfinish=5, OSRstatus=7, OSRcard=8, OSRrentcard=9}; + + fin.open(file); + + if (!fin.good()) + return false; + + char bf[1024]; + fin.getline(bf, 1024); + + nimport=0; + + vector sp; + + while (!fin.eof()) { + fin.getline(bf, 1024); + split(bf, sp); + + if (sp.size()>20 && strlen(sp[OSclub])>0) + { + nimport++; + + //Create club with this club number... + int ClubId=atoi(sp[OSclubno]); + pClub pclub=event.getClubCreate(ClubId, sp[OSclub]); + + if (pclub){ + pclub->getDI().setString("Nationality", sp[OSnat]); + pclub->synchronize(true); + } + + //Create class with this class number... + int ClassId=atoi(sp[OSclassno]); + event.getClassCreate(ClassId, sp[OSclass]); + + //Club is autocreated... + pTeam team=event.addTeam(string(sp[OSclub])+" "+string(sp[OSdesc]), ClubId, ClassId); + team->setEntrySource(externalSourceId); + + team->setStartNo(atoi(sp[OSstno]), false); + + if (strlen(sp[12])>0) + team->setStatus( ConvertOEStatus( atoi(sp[OSstatus]) ), true, false); + + team->setStartTime(event.convertAbsoluteTime(sp[OSstart]), true, false); + + if (strlen(sp[OStime])>0) + team->setFinishTime( event.convertAbsoluteTime(sp[OSstart])+event.convertAbsoluteTime(sp[OStime])-event.getZeroTimeNum() ); + + if (team->getStatus()==StatusOK && team->getFinishTime()==0) + team->setStatus(StatusUnknown, true, false); + + unsigned rindex=Offset; + + oDataInterface teamDI=team->getDI(); + + teamDI.setInt("Fee", atoi(sp[OSfee])); + teamDI.setInt("Paid", atoi(sp[OSpaid])); + teamDI.setString("Nationality", sp[OSnat]); + + //Import runners! + int runner=0; + while( (rindex+OSRrentcard)0 ){ + int year = extendYear(atoi(sp[rindex+OSRyb])); + int cardNo = atoi(sp[rindex+OSRcard]); + pRunner r = event.addRunner(string(sp[rindex+OSRfname])+" "+string(sp[rindex+OSRsname]), ClubId, + ClassId, cardNo, year, false); + + r->setEntrySource(externalSourceId); + oDataInterface DI=r->getDI(); + //DI.setInt("BirthYear", extendYear(atoi(sp[rindex+OSRyb]))); + r->setSex(interpretSex(sp[rindex + OSRsex])); + DI.setString("Nationality", sp[OSnat]); + + if (strlen(sp[rindex+OSRrentcard])>0) + DI.setInt("CardFee", event.getDCI().getInt("CardFee")); + + //r->setCardNo(atoi(sp[rindex+OSRcard]), false); + r->setStartTime(event.convertAbsoluteTime(sp[rindex+OSRstart]), true, false); + r->setFinishTime( event.convertAbsoluteTime(sp[rindex+OSRfinish]) ); + + if (strlen(sp[rindex+OSRstatus])>0) + r->setStatus( ConvertOEStatus( atoi(sp[rindex+OSRstatus]) ), true, false); + + if (r->getStatus()==StatusOK && r->getRunningTime()==0) + r->setStatus(StatusUnknown, true, false); + + r->addClassDefaultFee(false); + + team->setRunner(runner++, r, true); + + rindex+=PostSize; + } + //int nrunners=team->GetNumRunners(); + pClass pc=event.getClass(ClassId); + + if (pc && runner>(int)pc->getNumStages()) + pc->setNumStages(runner); + + team->apply(true, 0, false); + } + } + fin.close(); + + return true; +} + + +bool csvparser::ImportOE_CSV(oEvent &event, const char *file) +{ + enum {OEstno=0, OEcard=1, OEid=2, OEsurname=3, OEfirstname=4, + OEbirth=5, OEsex=6, OEstart=9, OEfinish=10, OEstatus=12, + OEclubno=13, OEclub=14, OEclubcity=15, OEnat=16, OEclassno=17, OEclass=18, OEbib=23, + OErent=35, OEfee=36, OEpaid=37, OEcourseno=38, OEcourse=39, + OElength=40}; + + fin.open(file); + + if (!fin.good()) + return false; + + char bf[1024]; + fin.getline(bf, 1024); + + nimport=0; + vector sp; + while (!fin.eof()) { + fin.getline(bf, 1024); + split(bf, sp); + + if (sp.size()>20) { + nimport++; + + int clubId = atoi(sp[OEclubno]); + string clubName; + string shortClubName; + //string clubCity; + + clubName = sp[OEclubcity]; + shortClubName = sp[OEclub]; + + if (clubName.empty() && !shortClubName.empty()) + swap(clubName, shortClubName); + + pClub pclub = event.getClubCreate(clubId, clubName); + + if (pclub) { + if (strlen(sp[OEnat])>0) + pclub->getDI().setString("Nationality", sp[OEnat]); + + pclub->getDI().setString("ShortName", shortClubName.substr(0, 8)); + //pclub->getDI().setString("City", clubCity.substr(0, 23)); + pclub->setExtIdentifier(clubId); + pclub->synchronize(true); + } + + __int64 extId = oBase::converExtIdentifierString(sp[OEid]); + int id = oBase::idFromExtId(extId); + pRunner pr = 0; + + if (id>0) + pr = event.getRunner(id, 0); + + while (pr) { // Check that the exact match is OK + if (extId != pr->getExtIdentifier()) + break; + id++; + pr = event.getRunner(id, 0); + } + + if (pr) { + if (pr->getEntrySource() != externalSourceId) { + // If not same source, do not accept match (will not work with older versions of MeOS files) + pr = 0; + id = 0; + } + } + + const bool newEntry = (pr == 0); + + if (pr == 0) { + if (id==0) { + oRunner r(&event); + pr = event.addRunner(r, true); + } + else { + oRunner r(&event, id); + pr = event.addRunner(r, true); + } + } + + if (pr==0) + continue; + + pr->setExtIdentifier(extId); + pr->setEntrySource(externalSourceId); + + if (!pr->hasFlag(oAbstractRunner::FlagUpdateName)) { + string name = string(sp[OEsurname]) + ", " + string(sp[OEfirstname]); + pr->setName(name, false); + } + pr->setClubId(pclub ? pclub->getId():0); + pr->setCardNo( atoi(sp[OEcard]), false ); + + pr->setStartTime(event.convertAbsoluteTime(sp[OEstart]), true, false); + pr->setFinishTime(event.convertAbsoluteTime(sp[OEfinish])); + + if (strlen(sp[OEstatus])>0) + pr->setStatus( ConvertOEStatus( atoi(sp[OEstatus]) ), true, false); + + if (pr->getStatus()==StatusOK && pr->getRunningTime()==0) + pr->setStatus(StatusUnknown, true, false); + + //Autocreate class if it does not exist... + int classId=atoi(sp[OEclassno]); + if (classId>0 && !pr->hasFlag(oAbstractRunner::FlagUpdateClass)) { + pClass pc=event.getClassCreate(classId, sp[OEclass]); + + if (pc) { + pc->synchronize(); + if (pr->getClassId() == 0 || !pr->hasFlag(oAbstractRunner::FlagUpdateClass)) + pr->setClassId(pc->getId(), false); + } + } + int stno=atoi(sp[OEstno]); + bool needSno = pr->getStartNo() == 0 || newEntry; + bool needBib = pr->getBib().empty(); + + if (needSno || newEntry) { + if (stno>0) + pr->setStartNo(stno, false); + else + pr->setStartNo(nimport, false); + } + oDataInterface DI=pr->getDI(); + + pr->setSex(interpretSex(sp[OEsex])); + DI.setInt("BirthYear", extendYear(atoi(sp[OEbirth]))); + DI.setString("Nationality", sp[OEnat]); + + if (sp.size()>OEbib && needBib) + pr->setBib(sp[OEbib], 0, false, false); + + if (sp.size()>=38) {//ECO + DI.setInt("Fee", atoi(sp[OEfee])); + DI.setInt("CardFee", atoi(sp[OErent])); + DI.setInt("Paid", atoi(sp[OEpaid])); + } + + if (sp.size()>=40) {//Course + if (pr->getCourse(false) == 0) { + const char *cid=sp[OEcourseno]; + const int courseid=atoi(cid); + if (courseid>0) { + pCourse course=event.getCourse(courseid); + + if (!course) { + oCourse oc(&event, courseid); + oc.setLength(int(atof(sp[OElength])*1000)); + oc.setName(sp[OEcourse]); + course = event.addCourse(oc); + if (course) + course->synchronize(); + } + if (course) { + if (pr->getClassId() != 0) + event.getClass(pr->getClassId())->setCourse(course); + else + pr->setCourseId(course->getId()); + } + } + } + } + if (pr) + pr->synchronize(); + } + } + fin.close(); + + return true; +} + +bool csvparser::openOutput(const char *filename) +{ + //Startnr;Bricka;Databas nr.;Efternamn;Förnamn;År;K;Block;ut;Start;Mål;Tid;Status;Klubb nr.;Namn;Ort;Land;Klass nr.;Kort;Lång;Num1;Num2;Num3;Text1;Text2;Text3;Adr. namn;Gata;Rad 2;Post nr.;Ort;Tel;Fax;E-post;Id/Club;Hyrd;Startavgift;Betalt;Bana nr.;Bana;km;Hm;Bana kontroller + fout.open(filename); + + if (fout.bad()) + return false; + return true; +} + +bool csvparser::OutputRow(const string &row) +{ + fout << row << endl; + return true; +} +bool csvparser::OutputRow(vector &out) +{ + int size=out.size(); + + for(int i=0;i0) fout << ";"; + + if (p.find_first_of("; ,\t.")!=string::npos) + fout << "\"" << p << "\""; + else fout << p; + } + fout << endl; + fout.flush(); + return true; +} + +bool csvparser::closeOutput() +{ + fout.close(); + return true; +} + + +int csvparser::split(char *line, vector &split_vector) +{ + split_vector.clear(); + int len=strlen(line); + bool cite=false; + + for(int m=0;m sp; + while(!fin.eof()) { + fin.getline(bf, 1024); + split(bf, sp); + if (sp.size()>7) { + size_t firstIndex = 7; + bool hasLengths = true; + int offset = 0; + if (atoi(sp[firstIndex]) < 30) { + firstIndex = 6; + offset = -1; + } + + if (atoi(sp[firstIndex])<30 || atoi(sp[firstIndex])>1000) { + string str = "Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y'.#" + + itos(firstIndex+1) + "#" + sp[firstIndex]; + throw std::exception(str.c_str()); + } + + while (firstIndex > 0 && atoi(sp[firstIndex])>30 && atoi(sp[firstIndex])>1000) { + firstIndex--; + } + string Start = lang.tl("Start ") + "1"; + double Length = 0; + string Course = event.getAutoCourseName(); + string Class = ""; + + if (firstIndex>=6) { + Class = sp[0]; + Course = sp[1+offset]; + Start = sp[5+offset]; + Length = atof(sp[3+offset]); + + if (Start[0]=='S') { + int num = atoi(Start.substr(1).c_str()); + if (num>0) + Start = lang.tl("Start ") + Start.substr(1); + } + } + else + hasLengths = false; + + //Get controls + pCourse pc=event.getCourse(Course); + + if (!pc) { + pc = event.addCourse(Course, int(Length*1000)); + } + else { + // Reset control + pc->importControls("", false); + pc->setLength(int(Length*1000)); + } + + + vector legLengths; + + if (hasLengths) { + double legLen = atof(sp[firstIndex-1]); // Length in km + if (legLen > 0.001 && legLen < 30) + legLengths.push_back(int(legLen*1000)); + } + + if (pc) { + for (size_t k=firstIndex; k= 30 && ctrl < 1000) + pc->addControl(atoi(sp[k])); + else { + string str = "Oväntad kontroll 'X' i bana Y.#" + ctrlStr + "#" + pc->getName(); + throw std::exception(str.c_str()); + } + } + if (hasLengths) { + double legLen = atof(sp[k+1]); // Length in km + if (legLen > 0.001 && legLen < 30) + legLengths.push_back(int(legLen*1000)); + } + } + pc->setLength(int(Length*1000)); + pc->setStart(Start, true); + + if (legLengths.size() == pc->getNumControls()+1) + pc->setLegLengths(legLengths); + + if (!Class.empty() && addClasses) { + pClass cls = event.getBestClassMatch(Class); + if (!cls) + cls = event.addClass(Class); + + if (cls->getNumStages()==0) { + cls->setCourse(pc); + } + else { + for (size_t i = 0; igetNumStages(); i++) + cls->addStageCourse(i, pc->getId()); + } + + cls->synchronize(); + } + + pc->synchronize(); + } + } + } + return true; +} + + +bool csvparser::ImportRAID(oEvent &event, const char *file) +{ + enum {RAIDid=0, RAIDteam=1, RAIDcity=2, RAIDedate=3, RAIDclass=4, + RAIDclassid=5, RAIDrunner1=6, RAIDrunner2=7, RAIDcanoe=8}; + + fin.open(file); + + if (!fin.good()) + return false; + + char bf[1024]; + fin.getline(bf, 1024); + vector sp; + + nimport=0; + while (!fin.eof()) { + fin.getline(bf, 1024); + split(bf, sp); + + if (sp.size()>7) { + nimport++; + + int ClubId=0; + //Create class with this class number... + int ClassId=atoi(sp[RAIDclassid]); + pClass pc = event.getClassCreate(ClassId, sp[RAIDclass]); + ClassId = pc->getId(); + + //Club is autocreated... + pTeam team=event.addTeam(sp[RAIDteam], ClubId, ClassId); + + team->setStartNo(atoi(sp[RAIDid]), false); + if (sp.size()>8) + team->getDI().setInt("SortIndex", atoi(sp[RAIDcanoe])); + oDataInterface teamDI=team->getDI(); + teamDI.setDate("EntryDate", sp[RAIDedate]); + + if (pc) { + if (pc->getNumStages()<2) + pc->setNumStages(2); + + pc->setLegType(0, LTNormal); + pc->setLegType(1, LTIgnore); + } + + //Import runners! + pRunner r1=event.addRunner(sp[RAIDrunner1], ClubId, ClassId, 0, 0, false); + team->setRunner(0, r1, false); + + pRunner r2=event.addRunner(sp[RAIDrunner2], ClubId, ClassId, 0, 0, false); + team->setRunner(1, r2, false); + + team->apply(true, 0, false); + } + } + fin.close(); + + return true; +} + +int csvparser::selectPunchIndex(const string &competitionDate, const vector &sp, + int &cardIndex, int &timeIndex, int &dateIndex, + string &processedTime, string &processedDate) { + int ci = -1; + int ti = -1; + int di = -1; + string pt, date; + int maxCardNo = 0; + processedDate.clear(); + for (size_t k = 0; k < sp.size(); k++) { + processGeneralTime(sp[k], pt, date); + if (!pt.empty()) { + if (ti == -1) { + ti = k; + pt.swap(processedTime); + } + else { + return -1; // Not a unique time + } + if (!date.empty()) { + date.swap(processedDate); + di = k; + } + } + else if (k == 2 && strlen(sp[k]) == 2 && processedDate.empty()) { + processedDate = sp[k]; // Old weekday format + dateIndex = 2; + } + else { + int cno = atoi(sp[k]); + if (cno > maxCardNo) { + maxCardNo = cno; + ci = k; + } + } + + } + + if (ti == -1) + return 0; // No time found + if (ci == -1) + return 0; // No card number found + + if (timeIndex >= 0 && timeIndex != ti) + return -1; // Inconsistent + + if (cardIndex >= 0 && cardIndex != ci) + return -1; // Inconsistent + + timeIndex = ti; + cardIndex = ci; + dateIndex = di; + return 1; +} + +bool csvparser::importPunches(const oEvent &oe, const char *file, vector &punches) +{ + punches.clear(); + fin.clear(); + fin.open(file); + if (!fin.good()) + return false; + + //const size_t siz = 1024 * 1; + //char bf[siz]; + string bfs; + + //fin.getline(bf, siz); + std::getline(fin, bfs); + + nimport=0; + int cardIndex = -1; + int timeIndex = -1; + int dateIndex = -1; + + string processedTime, processedDate; + const string date = oe.getDate(); + vector sp; + while (!fin.eof()) { + if (fin.fail()) + throw meosException("Reading file failed."); + + //fin.getline(bf, siz); + std::getline(fin, bfs); + sp.clear(); + char *bf = (char *)bfs.c_str(); + split(bf, sp); + + int ret = selectPunchIndex(date, sp, cardIndex, timeIndex, dateIndex, + processedTime, processedDate); + if (ret == -1) + return false; // Invalid file + if (ret > 0) { + int card = atoi(sp[cardIndex]); + int time = oe.getRelativeTime(processedTime); + + if (card>0) { + PunchInfo pi; + pi.card = card; + pi.time = time; + strncpy_s(pi.date, sizeof(pi.date), processedDate.c_str(), 26); + pi.date[26] = 0; + punches.push_back(pi); + nimport++; + } + } + } + fin.close(); + + return true; +} + +int analyseSITime(const oEvent &oe, const char *dow, const char *time) +{ + int t=-1; + if (trim(dow).length()>0) + t = oe.getRelativeTime(time); + else + t = oe.getRelativeTimeFrom12Hour(time); + + if (t<0) + t=0; + + return t; +} + +void csvparser::checkSIConfigHeader(const vector &sp) { + siconfigmap.clear(); + if (sp.size() < 200) + return; + + //No;Read on;SIID;Start no;Clear CN;Clear DOW;Clear time;Clear_r CN;Clear_r DOW;Clear_r time;Check CN;Check DOW;Check time;Start CN;Start DOW;Start time;Start_r CN;Start_r DOW;Start_r time;Finish CN;Finish DOW;Finish time;Finish_r CN;Finish_r DOW;Finish_r time;Class;First name;Last name;Club;Country;Email;Date of birth;Sex;Phone;Street;ZIP;City;Hardware version;Software version;Battery date;Battery voltage;Clear count;Character set;SEL_FEEDBACK;No. of records;Record 1 CN;Record 1 DOW;Record 1 time;Record 2 CN;Record 2 DOW;Record 2 time;Record 3 CN;Record 3 DOW;Record 3 time;Record 4 CN;Record 4 DOW;Record 4 time;Record 5 CN;Record 5 DOW;Record 5 time;Record 6 CN;Record 6 DOW;Record 6 time;Record 7 CN;Record 7 DOW;Record 7 time;Record 8 CN;Record 8 DOW;Record 8 time;Record 9 CN;Record 9 DOW;Record 9 time;Record 10 CN;Record 10 DOW;Record 10 time;Record 11 CN;Record 11 DOW;Record 11 time;Record 12 CN;Record 12 DOW;Record 12 time;Record 13 CN;Record 13 DOW;Record 13 time;Record 14 CN;Record 14 DOW;Record 14 time;Record 15 CN;Record 15 DOW;Record 15 time;Record 16 CN;Record 16 DOW;Record 16 time;Record 17 CN;Record 17 DOW;Record 17 time;Record 18 CN;Record 18 DOW;Record 18 time;Record 19 CN;Record 19 DOW;Record 19 time;Record 20 CN;Record 20 DOW;Record 20 time;Record 21 CN;Record 21 DOW;Record 21 time;Record 22 CN;Record 22 DOW;Record 22 time;Record 23 CN;Record 23 DOW;Record 23 time;Record 24 CN;Record 24 DOW;Record 24 time;Record 25 CN;Record 25 DOW;Record 25 time;Record 26 CN;Record 26 DOW;Record 26 time;Record 27 CN;Record 27 DOW;Record 27 time;Record 28 CN;Record 28 DOW;Record 28 time;Record 29 CN;Record 29 DOW;Record 29 time;Record 30 CN;Record 30 DOW;Record 30 time;Record 31 CN;Record 31 DOW;Record 31 time;Record 32 CN;Record 32 DOW;Record 32 time;Record 33 CN;Record 33 DOW;Record 33 time;Record 34 CN;Record 34 DOW;Record 34 time;Record 35 CN;Record 35 DOW;Record 35 time;Record 36 CN;Record 36 DOW;Record 36 time;Record 37 CN;Record 37 DOW;Record 37 time;Record 38 CN;Record 38 DOW;Record 38 time;Record 39 CN;Record 39 DOW;Record 39 time;Record 40 CN;Record 40 DOW;Record 40 time;Record 41 CN;Record 41 DOW;Record 41 time;Record 42 CN;Record 42 DOW;Record 42 time;Record 43 CN;Record 43 DOW;Record 43 time;Record 44 CN;Record 44 DOW;Record 44 time;Record 45 CN;Record 45 DOW;Record 45 time;Record 46 CN;Record 46 DOW;Record 46 time;Record 47 CN;Record 47 DOW;Record 47 time;Record 48 CN;Record 48 DOW;Record 48 time;Record 49 CN;Record 49 DOW;Record 49 time;Record 50 CN;Record 50 DOW;Record 50 time;Record 51 CN;Record 51 DOW;Record 51 time;Record 52 CN;Record 52 DOW;Record 52 time;Record 53 CN;Record 53 DOW;Record 53 time;Record 54 CN;Record 54 DOW;Record 54 time;Record 55 CN;Record 55 DOW;Record 55 time;Record 56 CN;Record 56 DOW;Record 56 time;Record 57 CN;Record 57 DOW;Record 57 time;Record 58 CN;Record 58 DOW;Record 58 time;Record 59 CN;Record 59 DOW;Record 59 time;Record 60 CN;Record 60 DOW;Record 60 time;Record 61 CN;Record 61 DOW;Record 61 time;Record 62 CN;Record 62 DOW;Record 62 time;Record 63 CN;Record 63 DOW;Record 63 time;Record 64 CN;Record 64 DOW;Record 64 time;Record 65 CN;Record 65 DOW;Record 65 time;Record 66 CN;Record 66 DOW;Record 66 time;Record 67 CN;Record 67 DOW;Record 67 time;Record 68 CN;Record 68 DOW;Record 68 time;Record 69 CN;Record 69 DOW;Record 69 time;Record 70 CN;Record 70 DOW;Record 70 time;Record 71 CN;Record 71 DOW;Record 71 time;Record 72 CN;Record 72 DOW;Record 72 time;Record 73 CN;Record 73 DOW;Record 73 time;Record 74 CN;Record 74 DOW;Record 74 time;Record 75 CN;Record 75 DOW;Record 75 time;Record 76 CN;Record 76 DOW;Record 76 time;Record 77 CN;Record 77 DOW;Record 77 time;Record 78 CN;Record 78 DOW;Record 78 time;Record 79 CN;Record 79 DOW;Record 79 time;Record 80 CN;Record 80 DOW;Record 80 time;Record 81 CN;Record 81 DOW;Record 81 time;Record 82 CN;Record 82 DOW;Record 82 time;Record 83 CN;Record 83 DOW;Record 83 time;Record 84 CN;Record 84 DOW;Record 84 time;Record 85 CN;Record 85 DOW;Record 85 time;Record 86 CN;Record 86 DOW;Record 86 time;Record 87 CN;Record 87 DOW;Record 87 time;Record 88 CN;Record 88 DOW;Record 88 time;Record 89 CN;Record 89 DOW;Record 89 time;Record 90 CN;Record 90 DOW;Record 90 time;Record 91 CN;Record 91 DOW;Record 91 time;Record 92 CN;Record 92 DOW;Record 92 time;Record 93 CN;Record 93 DOW;Record 93 time;Record 94 CN;Record 94 DOW;Record 94 time;Record 95 CN;Record 95 DOW;Record 95 time;Record 96 CN;Record 96 DOW;Record 96 time;Record 97 CN;Record 97 DOW;Record 97 time;Record 98 CN;Record 98 DOW;Record 98 time;Record 99 CN;Record 99 DOW;Record 99 time;Record 100 CN;Record 100 DOW;Record 100 time;Record 101 CN;Record 101 DOW;Record 101 time;Record 102 CN;Record 102 DOW;Record 102 time;Record 103 CN;Record 103 DOW;Record 103 time;Record 104 CN;Record 104 DOW;Record 104 time;Record 105 CN;Record 105 DOW;Record 105 time;Record 106 CN;Record 106 DOW;Record 106 time;Record 107 CN;Record 107 DOW;Record 107 time;Record 108 CN;Record 108 DOW;Record 108 time;Record 109 CN;Record 109 DOW;Record 109 time;Record 110 CN;Record 110 DOW;Record 110 time;Record 111 CN;Record 111 DOW;Record 111 time;Record 112 CN;Record 112 DOW;Record 112 time;Record 113 CN;Record 113 DOW;Record 113 time;Record 114 CN;Record 114 DOW;Record 114 time;Record 115 CN;Record 115 DOW;Record 115 time;Record 116 CN;Record 116 DOW;Record 116 time;Record 117 CN;Record 117 DOW;Record 117 time;Record 118 CN;Record 118 DOW;Record 118 time;Record 119 CN;Record 119 DOW;Record 119 time;Record 120 CN;Record 120 DOW;Record 120 time;Record 121 CN;Record 121 DOW;Record 121 time;Record 122 CN;Record 122 DOW;Record 122 time;Record 123 CN;Record 123 DOW;Record 123 time;Record 124 CN;Record 124 DOW;Record 124 time;Record 125 CN;Record 125 DOW;Record 125 time;Record 126 CN;Record 126 DOW;Record 126 time;Record 127 CN;Record 127 DOW;Record 127 time;Record 128 CN;Record 128 DOW;Record 128 time;Record 129 CN;Record 129 DOW;Record 129 time;Record 130 CN;Record 130 DOW;Record 130 time;Record 131 CN;Record 131 DOW;Record 131 time;Record 132 CN;Record 132 DOW;Record 132 time;Record 133 CN;Record 133 DOW;Record 133 time;Record 134 CN;Record 134 DOW;Record 134 time;Record 135 CN;Record 135 DOW;Record 135 time;Record 136 CN;Record 136 DOW;Record 136 time;Record 137 CN;Record 137 DOW;Record 137 time;Record 138 CN;Record 138 DOW;Record 138 time;Record 139 CN;Record 139 DOW;Record 139 time;Record 140 CN;Record 140 DOW;Record 140 time;Record 141 CN;Record 141 DOW;Record 141 time;Record 142 CN;Record 142 DOW;Record 142 time;Record 143 CN;Record 143 DOW;Record 143 time;Record 144 CN;Record 144 DOW;Record 144 time;Record 145 CN;Record 145 DOW;Record 145 time;Record 146 CN;Record 146 DOW;Record 146 time;Record 147 CN;Record 147 DOW;Record 147 time;Record 148 CN;Record 148 DOW;Record 148 time;Record 149 CN;Record 149 DOW;Record 149 time;Record 150 CN;Record 150 DOW;Record 150 time;Record 151 CN;Record 151 DOW;Record 151 time;Record 152 CN;Record 152 DOW;Record 152 time;Record 153 CN;Record 153 DOW;Record 153 time;Record 154 CN;Record 154 DOW;Record 154 time;Record 155 CN;Record 155 DOW;Record 155 time;Record 156 CN;Record 156 DOW;Record 156 time;Record 157 CN;Record 157 DOW;Record 157 time;Record 158 CN;Record 158 DOW;Record 158 time;Record 159 CN;Record 159 DOW;Record 159 time;Record 160 CN;Record 160 DOW;Record 160 time;Record 161 CN;Record 161 DOW;Record 161 time;Record 162 CN;Record 162 DOW;Record 162 time;Record 163 CN;Record 163 DOW;Record 163 time;Record 164 CN;Record 164 DOW;Record 164 time;Record 165 CN;Record 165 DOW;Record 165 time;Record 166 CN;Record 166 DOW;Record 166 time;Record 167 CN;Record 167 DOW;Record 167 time;Record 168 CN;Record 168 DOW;Record 168 time;Record 169 CN;Record 169 DOW;Record 169 time;Record 170 CN;Record 170 DOW;Record 170 time;Record 171 CN;Record 171 DOW;Record 171 time;Record 172 CN;Record 172 DOW;Record 172 time;Record 173 CN;Record 173 DOW;Record 173 time;Record 174 CN;Record 174 DOW;Record 174 time;Record 175 CN;Record 175 DOW;Record 175 time;Record 176 CN;Record 176 DOW;Record 176 time;Record 177 CN;Record 177 DOW;Record 177 time;Record 178 CN;Record 178 DOW;Record 178 time;Record 179 CN;Record 179 DOW;Record 179 time;Record 180 CN;Record 180 DOW;Record 180 time;Record 181 CN;Record 181 DOW;Record 181 time;Record 182 CN;Record 182 DOW;Record 182 time;Record 183 CN;Record 183 DOW;Record 183 time;Record 184 CN;Record 184 DOW;Record 184 time;Record 185 CN;Record 185 DOW;Record 185 time;Record 186 CN;Record 186 DOW;Record 186 time;Record 187 CN;Record 187 DOW;Record 187 time;Record 188 CN;Record 188 DOW;Record 188 time;Record 189 CN;Record 189 DOW;Record 189 time;Record 190 CN;Record 190 DOW;Record 190 time;Record 191 CN;Record 191 DOW;Record 191 time;Record 192 CN;Record 192 DOW;Record 192 time; + string key; + for (size_t k = 0; k < sp.size(); k++) { + key = sp[k]; + if (key == "SIID" || key == "SI-Card") + siconfigmap[sicSIID] = k; + else if (key == "Check CN" || key == "CHK_CN") { + siconfigmap[sicCheck] = k; + siconfigmap[sicCheckDOW] = k + 1; + siconfigmap[sicCheckTime] = k + 2; + } + else if (key == "Check time") { + siconfigmap[sicCheckTime] = k; + } + else if (key == "Start CN" || key == "ST_CN") { + siconfigmap[sicStart] = k; + siconfigmap[sicStartDOW] = k + 1; + siconfigmap[sicStartTime] = k + 2; + } + else if (key == "Start time") { + siconfigmap[sicStartTime] = k; + } + else if (key == "Finish CN" || key == "FI_CN") { + siconfigmap[sicFinish] = k; + siconfigmap[sicFinishDOW] = k + 1; + siconfigmap[sicFinishTime] = k + 2; + } + else if (key == "Finish time") { + siconfigmap[sicFinishTime] = k; + } + else if (key == "First name") { + siconfigmap[sicFirstName] = k; + } + else if (key == "Last name") { + siconfigmap[sicLastName] = k; + } + else if (key == "No. of records" || key == "No. of punches") { + siconfigmap[sicNumPunch] = k; + } + else if (siconfigmap.count(sicRecordStart) == 0) { + size_t pos = key.find("Record 1"); + if (pos == string::npos) { + pos = key.find("1.CN"); + } + if (pos != string::npos) { + siconfigmap[sicRecordStart] = k; + if (siconfigmap.count(sicRecordStart) == 0 && k > 0) + siconfigmap[sicNumPunch] = k-1; + } + } + } + + if (!siconfigmap.empty()) { + + } +} + +const char *csvparser::getSIC(SIConfigFields sic, const vector &sp) const { + map::const_iterator res = siconfigmap.find(sic); + if (res == siconfigmap.end() || size_t(res->second) >= sp.size()) + return ""; + + return sp[res->second]; +} + +bool csvparser::checkSIConfigLine(const oEvent &oe, const vector &sp, SICard &card) { + if (siconfigmap.empty()) + return false; + + int startIx = siconfigmap[sicRecordStart]; + if (startIx == 0) + return false; + + int cardNo = atoi(getSIC(sicSIID, sp)); + + if (cardNo < 1000 || cardNo > 99999999) + return false; + + int check = analyseSITime(oe, getSIC(sicCheckDOW, sp), getSIC(sicCheckTime, sp)); + int start = analyseSITime(oe, getSIC(sicStartDOW, sp), getSIC(sicStartTime, sp)); + int finish = analyseSITime(oe, getSIC(sicFinishDOW, sp), getSIC(sicFinishTime, sp)); + int startCode = atoi(getSIC(sicStart, sp)); + int finishCode = atoi(getSIC(sicFinish, sp)); + int checkCode = atoi(getSIC(sicCheck, sp)); + string fname = getSIC(sicFirstName, sp); + string lname = getSIC(sicLastName, sp); + + vector< pair > punches; + int np = atoi(getSIC(sicNumPunch, sp)); + + + for (int k=0; k < np; k++) { + size_t ix = startIx + k*3; + if (ix+2 >= sp.size()) + return false; + int code = atoi(sp[ix]); + int time = analyseSITime(oe, sp[ix+1], sp[ix+2]); + if (code > 0) { + punches.push_back(make_pair(code, time)); + } + else { + return false; + } + } + + if ( (finish > 0 && finish != NOTIME) || punches.size() > 2) { + card.clear(0); + card.CardNumber = cardNo; + if (start > 0 && start != NOTIME) { + card.StartPunch.Code = startCode; + card.StartPunch.Time = start; + } + else { + card.StartPunch.Time = 0; + card.StartPunch.Code = -1; + } + + if (finish > 0 && finish != NOTIME) { + card.FinishPunch.Code = finishCode; + card.FinishPunch.Time = finish; + } + else { + card.FinishPunch.Time = 0; + card.FinishPunch.Code = -1; + } + + if (check > 0 && check != NOTIME) { + card.CheckPunch.Code = checkCode; + card.CheckPunch.Time = check; + } + else { + card.CheckPunch.Time = 0; + card.CheckPunch.Code = -1; + } + + for (size_t k = 0; k &sp, SICard &card) { + if (sp.size() <= 11) + return false; + + int cardNo = atoi(sp[1]); + + if (strchr(sp[1], '-') != 0) + cardNo = 0; // Ensure not a date 2017-02-14 + + if (cardNo < 1000 || cardNo > 99999999) + return false; + + int start = convertAbsoluteTimeMS(sp[5]); + int finish = convertAbsoluteTimeMS(sp[6]); + vector< pair > punches; + for (size_t k=10; k + 1 0) { + punches.push_back(make_pair(code, time)); + } + else { + return false; + } + } + + if (punches.size() > 2) { + card.clear(0); + card.CardNumber = cardNo; + if (start > 0) { + card.StartPunch.Code = 0; + card.StartPunch.Time = start; + } + else { + card.StartPunch.Code = -1; + } + + if (finish > 0) { + card.FinishPunch.Code = 0; + card.FinishPunch.Time = finish; + } + else { + card.FinishPunch.Code = -1; + } + + for (size_t k = 0; k &cards) +{ + cards.clear(); + fin.clear(); + fin.open(file); + + if (!fin.good()) + return false; + + //[1024*16]; + int s = 1024*256; + vector bbf(s); + char *bf = &bbf[0]; + fin.getline(bf, s); + vector sp; + split(bf, sp); + checkSIConfigHeader(sp); + nimport=0; + + while (!fin.eof()) { + fin.getline(bf, s); + split(bf, sp); + SICard card; + + if (checkSimanLine(oe, sp, card)) { + cards.push_back(card); + nimport++; + } + else if (checkSIConfigLine(oe,sp, card)) { + cards.push_back(card); + nimport++; + } + else if (sp.size()>28) { + int no = atoi(sp[0]); + card.CardNumber = atoi(sp[2]); + strncpy_s(card.FirstName, sp[5], 20); + strncpy_s(card.LastName, sp[6], 20); + strncpy_s(card.Club, sp[7], 40); + + if (trim(sp[21]).length()>1) { + card.CheckPunch.Code = atoi(sp[19]); + card.CheckPunch.Time = analyseSITime(oe, sp[20], sp[21]); + } + else { + card.CheckPunch.Code = -1; + card.CheckPunch.Time = 0; + } + + if (trim(sp[24]).length()>1) { + card.StartPunch.Code = atoi(sp[22]); + card.StartPunch.Time = analyseSITime(oe, sp[23], sp[24]); + } + else { + card.StartPunch.Code = -1; + card.StartPunch.Time = 0; + } + + if (trim(sp[27]).length()>1) { + card.FinishPunch.Code = atoi(sp[25]); + card.FinishPunch.Time = analyseSITime(oe, sp[26], sp[27]); + } + else { + card.FinishPunch.Code = -1; + card.FinishPunch.Time = 0; + } + + card.nPunch = atoi(sp[28]); + if (no>0 && card.CardNumber>0 && card.nPunch>0 && card.nPunch < 200) { + if (sp.size()>28+3*card.nPunch) { + for (unsigned k=0;k > &data) { + data.clear(); + + fin.open(file.c_str()); + const size_t bf_size = 4096; + char bf[4096]; + if (!fin.good()) + throw meosException("Failed to read file"); + + bool isUTF8 = false; + bool isUnicode = false; + bool firstLine = true; + wstring wideString; + vector sp; + + while(!fin.eof()) { + memset(bf, 0, bf_size); + fin.getline(bf, bf_size); + if (firstLine) { + if (bf[0] == -17 && bf[1] == -69 && bf[2] == -65) { + isUTF8 = true; + for (int k = 0; k 0) { + int untranslated; + WideCharToMultiByte(CP_ACP, 0, wideString.c_str(), wideString.length(), bf, bf_size-2, "?", &untranslated); + bf[wideString.length()-1] = 0; + } + else { + bf[0] = 0; + } + } + + firstLine = false; + split(bf, sp); + + if (!sp.empty()) { + data.push_back(vector()); + data.back().resize(sp.size()); + for (size_t k = 0; k < sp.size(); k++) { + data.back()[k] = sp[k]; + } + } + } + + if (isUTF8) { + list< vector > dataCopy; + for (list< vector >::iterator it = data.begin(); it != data.end(); ++it) { + vector &de = *it; + dataCopy.push_back(vector()); + vector &out = dataCopy.back(); + + wchar_t buff[buff_pre_alloc]; + char outstr[buff_pre_alloc]; + for (size_t k = 0; k < de.size(); k++) { + if (de[k].empty()) { + out.push_back(""); + continue; + } + int len = de[k].size(); + len = min(min(len+1, 1024), buff_pre_alloc-10); + + int wlen = MultiByteToWideChar(CP_UTF8, 0, de[k].c_str(), len, buff, buff_pre_alloc); + buff[wlen-1] = 0; + + BOOL untranslated = false; + WideCharToMultiByte(CP_ACP, 0, buff, wlen, outstr, buff_pre_alloc, "?", &untranslated); + outstr[wlen-1] = 0; + out.push_back(outstr); + } + } + data.swap(dataCopy); + } + + fin.close(); +} + +void csvparser::importTeamLineup(const string &file, + const map &classNameToNumber, + vector &teams) { + list< vector > data; + parse(file, data); + teams.clear(); + teams.reserve(data.size()/3); + int membersToRead = 0; + int lineNo = 1; + while (!data.empty()) { + vector &line = data.front(); + if (!line.empty()) { + if (membersToRead == 0) { + if (line.size() < 2 || line.size() > 3) + throw meosException("Ogiltigt lag på rad X.#" + itos(lineNo) + ": " + line[0]); + const string cls = trim(line[0]); + map::const_iterator res = classNameToNumber.find(cls); + if (res == classNameToNumber.end()) + throw meosException("Okänd klass på rad X.#" + itos(lineNo) + ": " + cls); + if (res->second <= 1) + throw meosException("Klassen X är individuell.#" + cls); + + membersToRead = res->second; + teams.push_back(TeamLineup()); + teams.back().teamClass = cls; + teams.back().teamName = trim(line[1]); + if (line.size() >= 3) + teams.back().teamClub = trim(line[2]); + } + else { + membersToRead--; + teams.back().members.push_back(TeamLineup::TeamMember()); + TeamLineup::TeamMember &member = teams.back().members.back(); + member.name = trim(line[0]); + if (line.size()>1) + member.cardNo = atoi(line[1].c_str()); + else + member.cardNo = 0; + + if (line.size()>2) + member.club = trim(line[2]); + + if (line.size() > 3) + member.course = trim(line[3]); + + if (line.size() > 4) + member.cls = trim(line[4]); + } + } + else if (membersToRead>0) { + membersToRead--; + teams.back().members.push_back(TeamLineup::TeamMember()); + } + lineNo++; + data.pop_front(); + } +} diff --git a/code/csvparser.h b/code/csvparser.h new file mode 100644 index 0000000..e8310ae --- /dev/null +++ b/code/csvparser.h @@ -0,0 +1,139 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// csvparser.h: interface for the csvparser class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_CSVPARSER_H__FD04656A_1D2A_4E6C_BE23_BD66052E276E__INCLUDED_) +#define AFX_CSVPARSER_H__FD04656A_1D2A_4E6C_BE23_BD66052E276E__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include + +class oEvent; +struct SICard; +class ImportFormats; + +struct PunchInfo { + int code; + int card; + int time; + char date[28]; +}; + + +struct TeamLineup { + struct TeamMember { + string name; + string club; + int cardNo; + string course; + string cls; + }; + + string teamName; + string teamClass; + string teamClub; + vector members; +}; + +class csvparser +{ +protected: + ofstream fout; + ifstream fin; + + int LineNumber; + string ErrorMessage; + + // Returns true if a SI-manager line is identified + bool checkSimanLine(const oEvent &oe, const vector &sp, SICard &cards); + + // Check and setup header for SIConfig import + void checkSIConfigHeader(const vector &sp); + + // Return true if SIConfig line was detected + bool checkSIConfigLine(const oEvent &oe, const vector &sp, SICard &card); + + enum SIConfigFields { + sicSIID, + sicCheck, + sicCheckTime, + sicCheckDOW, + sicStart, + sicStartTime, + sicStartDOW, + sicFinish, + sicFinishTime, + sicFinishDOW, + sicNumPunch, + sicRecordStart, + sicFirstName, + sicLastName, + }; + + map siconfigmap; + const char *getSIC(SIConfigFields sic, const vector &sp) const; + + // Check and process a punch line + static int selectPunchIndex(const string &competitionDate, const vector &sp, + int &cardIndex, int &timeIndex, int &dateIndex, + string &processedTime, string &date); + +public: + void parse(const string &file, list< vector > &dataOutput); + + void importTeamLineup(const string &file, + const map &classNameToNumber, + vector &teams); + + bool openOutput(const char *file); + bool closeOutput(); + bool OutputRow(vector &out); + bool OutputRow(const string &row); + + int nimport; + bool ImportOCAD_CSV(oEvent &event, const char *file, bool addClasses); + bool ImportOS_CSV(oEvent &event, const char *file); + bool ImportRAID(oEvent &event, const char *file); + + bool importPunches(const oEvent &oe, const char *file, + vector &punches); + + bool importCards(const oEvent &oe, const char *file, + vector &punches); + + int split(char *line, vector &split); + + bool ImportOE_CSV(oEvent &event, const char *file); + int iscsv(const char *file); + csvparser(); + virtual ~csvparser(); + +}; + +#endif // !defined(AFX_CSVPARSER_H__FD04656A_1D2A_4E6C_BE23_BD66052E276E__INCLUDED_) diff --git a/code/danish.lng b/code/danish.lng new file mode 100644 index 0000000..3feca23 --- /dev/null +++ b/code/danish.lng @@ -0,0 +1,2237 @@ +%s m = %s m +%s meter = %s meter +%s, block: %d = %s, blok: %d +(har stämplat) = (har stemplet) +(ledare) = (leder) +(lokalt) = (lokalt) +(okänd) stämplade vid = (ukendt) stemplede ved +(på server) = (på server) +(sekunder) = (sekunder) +(sträckseger) = (strækvinder) +ALLA( = Alle( +API-nyckel = API-nøgle +Accepterade elektroniska fakturor = Godkendte elektroniske fakturaer +Adress = Adresse +Adress och kontakt = Adresse og kontakt +Aktivera = Aktivér +Aktuell tid = Aktuel tid +Alla = Alle +Alla banfiler = Alle banefiler +Alla deltagare måste ha ett namn = Alle deltagere skal have et navn +Alla fakturor = Alle fakturaer +Alla funktioner = Alle funktioner linjenumre +Alla händelser = Alle begivenheder +Alla lag måste ha ett namn = Alle hold skal have et navn +Alla listor = Alle lister +Alla lopp = Alle løb +Alla lopp som individuella = Alle løb som individuelle +Alla sträckor = Alle ture +Alla sträckor/lopp i separata filer = Alle ture/løb i separate filer +Alla typer = Alle typer +Allmänna resultat = Generelle resultater +Andel vakanser = Andel vakante +Ange en gruppstorlek (som repeteras) eller flera kommaseparerade gruppstorlekar = Angiv en gruppestørrelse (der gentages) eller flere gruppestørrelser separeret med komma +Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar = Angiv første nummer for brystnumre eller efterlad blank for ingen brystnumre +Ange löpande numrering eller första nummer i klassen = Angiv løbende nummerering eller angiv første nummer for klassen +Ange om kontrollen fungerar och hur den ska användas = Angiv om postenheden virker og hvordan den skal bruges +Ange relation mellan lagets och deltagarnas nummerlappar = Angiv relationen mellem holdets og deltagernes brystnumre +Ange startintervall för minutstart = Angiv startinterval for minutstart +Ange tiden relativt klassens första start = Angiv tid i forhold til klassens først startende +Anm. avg. = Startafg. +Anm. avgift = Startafgift +Anm. datum = Tilmeldingsfrist +Anmäl = Tilmeld +Anmäl X = Tilmeld X +Anmäl inga deltagare nu = Opret uden tilmelding af deltagere +Anmäl till efterföljande etapper = Tilmeld til efterfølgende etapper +Anmälda = Tilmeldte +Anmälda per distrikt = Tilmeldte pr. kreds +Anmälningar = Tilmeldinger +Anmälningar (IOF (xml) eller OE-CSV) = Tilmeldinger (IOF,XML) eller OE,CSV) +Anmälningsavgift = Startafgift +Anmälningsläge = Hurtig tilmelding +Anonymt namn = Anonymt navn +Anslut = Forbind +Anslut till en server = Forbind til en server +Ansluten till = Forbundet til +Ansluter till Internet = Forbinder til Internettet +Anslutna klienter = Forbundne klienter +Anslutningar = Forbindelser +Anslutningsinställningar = Opsætning af forbindelser +Antal = Antal +Antal besökare X, genomsnittlig bomtid Y, största bomtid Z = Antal løbere X, gennemsnitligt tidstab Y, største tidstab Z +Antal deltagare = Antal deltagere +Antal deltagare: X = Antal deltagere: X +Antal hämtade uppdateringar X (Y kb) = Antal hentede opdateringer X (Y kb) +Antal ignorerade: X = Antal ikke importerede: X +Antal importerade = Antal importerede +Antal kartor = Antal kort +Antal klasser = Antal klasser +Antal löpare = Antal løbere +Antal löpare på vanligaste banan X = Antal løbere på den mest valgte bane X +Antal misslyckade: X = Antal mislykkede tilmeldinger: X +Antal reserverade nummerlappsnummer mellan klasser = Antal reserverede brystnumre mellem klasser +Antal skickade uppdateringar X (Y kb) = Antal sendte opdateringer X (Y kb) +Antal startande per block = Antal startende i hver blok +Antal startande per intervall (inklusive redan lottade) = Antal startende i hvert interval (inklusive allerede lodtrukne) +Antal sträckor = Antal ture +Antal vakanser = Antal vakante +Antal: %d = Antal: %d +Antal: X = Antal: X +Antalet rader i urklipp får inte plats i selektionen = Antallet af rækker i udklipsholder passer ikke med det valgte +Använd Eventor = Brug Eventor +Använd ROC-protokoll = Brug ROC-protokollen +Använd banpool = Brug frit banevalg +Använd befintliga deltagare = Brug de eksisterende deltagere +Använd endast en bana i klassen = Brug kun en bane i klassen +Använd enhets-id istället för tävlings-id = Brug enheds ID i stedet for løbs ID +Använd funktioner för fleretappsklass = Brug funktioner for klasser med flere etaper +Använd första kontrollen som start = Brug første post som startpost +Använd löpardatabasen = Brug løberdatabase +Använd sista kontrollen som mål = Brug sidste post som målpost +Använd speakerstöd = Brug speakerfunktion +Använd stor font = Brug stor skrifttype +Använd symbolen X där MeOS ska fylla i typens data = Brug symbolet X hvor MeOS skal indsætte data +Användarnamn = Brugernavn +Applicera för specifik sträcka = Tilføj for specifikt stræk +Applying rules to the current competition = Anvend reglerne i det aktuelle løb +Arrangör = Arrangør +Assign courses and apply forking to X = Tildel baner og anvend gafling på X +Assign selected courses to selected legs = Tildel udvalgte baner til udvalgte ture +Att betala = At betale +Att betala: X = At betale: X +Automater = Autofunktioner +Automatic rogaining point reduction = Automatisk pointfradrag +Automatisera = Udfør automatisk +Automatisk = Automatisk +Automatisk lottning = Automatisk lodtrækning +Automatisk skroll = Automatisk rulning +Automatisk utskrift = Automatisk udskrift +Automatisk utskrift / export = Automatisk udskrift / eksport +Av MeOS: www.melin.nu/meos = Af MeOS: www.melin.nu/meos +Available symbols = Tilgængelige symboler +Avancerat = Avanceret +Avbryt = Afbryd +Avdrag = Fradrag +Avgift = Afgift +Avgifter = Afgifter +Avgifter och valuta ställer du in under = Startafgifter og valuta sættes fra +Avgiftshöjning (procent) = Afgiftsstigning (procent) +Avgjorda klasser (prisutdelningslista) = Afgjorte klasser (prisuddelingsliste) +Avgjorda placeringar - %s = Afgjorte placeringer - %s +Avgörande händelser = Afgørende begivenheder +Avgörs X = Afgøres X +Avgörs kl = Afgøres klokken +Avkortad banvariant = Afkortet variant af bane +Avkortar: X = Afkorter: X +Avkortning = Afkortning +Avläsning/radiotider = Aflæsning/radiotider +Avmarkera 'X' för att hantera alla bricktildelningar samtidigt = Fjern 'X' for at tildele alle brikker på en gang +Avmarkera allt = Afmarkér alt +Avrundad tävlingsavgift = Afrundet løbsafgift +Avsluta = Afslut +Avstånd = Afstand +Bad file format = Forkert filformat +Bakåt = Tilbage +Bana = Bane +Bana %d = Bane %d +Bana med slingor = Bane med sløjfer +Banan används och kan inte tas bort = Banen er i brug og kan ikke fjernes +Banan måste ha ett namn = Banen skal have et navn +Banan saknar rogainingkontroller = Banen har ingen pointløbsposter +Banan saknas = Banen mangler +Banans kontroller ger för få poäng för att täcka poängkravet = Banens poster giver ikke tilstrækkeligt med points til at dække pointkravet +Bananvändning = Brug af bane +Banmall = Baneskabelon +Banor = Baner +Banor (antal kontroller) = Baner (antal poster) +Banor för %s, sträcka %d = Baner for %s, tur %d +Banor, IOF (xml) = Baner, IOF (XML) +Banor, OCAD semikolonseparerat = Baner, OCAD semikolonsepareret +Banpool = Frit banevalg +Banpool, gemensam start = Frit banevalg, samlet start +Banpool, lottad startlista = Frit banevalg, lodtrukken startliste +Bantilldelning = Banetildeling +Bantilldelning, individuell = Banetildeling, individuel +Bantilldelning, stafett = Banetildeling, stafet +Bantilldelningslista - %s = Banetildelingsliste - %s +Basintervall (min) = Basisinterval (min) +Begränsa antal per klass = Begræns antal pr. klasse +Begränsa per klass = Begræns pr. klasse +Begränsning, antal visade per klass = Begræns antal viste pr. klasse +Behandlar löpardatabasen = Bearbejder løberdatabasen +Behandlar tävlingsdata = Bearbejder løbsdata +Behandlar: X = Bearbejder: X +Bekräfta att %s byter klass till %s = Bekræft at %s skifter klasse til %s +Bekräfta att deltagaren har lämnat återbud = Bekræft at deltageren har meldt afbud +Besökare = Besøgende +Betalat = Betalt +Betalningsinformation = Betalingsinformation +Bevakar händelser i X = Overvåger begivenheder i X +Bevakningsprioritering = Overvågningsprioritering +Bibs = Brystnumre +Block = Blok +Blockbredd = Blokkens bredde +Bläddra = Gennemse +Bold = Fed +BoldHuge = Fed, enorm +BoldLarge = Fed, stor +BoldSmall = Fed, lille +Bomfritt lopp / underlag saknas = Fejlfrit løb / mangler data +Bomkvot = Bom kvotient +Bommade kontroller = Poster med tidstab +Bomtid = Tidstab +Bomtid (max) = Tidstab (max) +Bomtid (medel) = Tidstab (gennemsnit) +Bomtid (median) = Tidstab (median) +Bomtid: X = Tidstab: X +Bricka = Brik +Bricka %d används redan av %s och kan inte tilldelas = Brik %d bruges af %s og kan ikke tildeles +Bricka X = Brik X +Brickan används av X = Brikken bruges af X +Brickan redan inläst = Brikken er allerede aflæst +Brickhantering = Brikhåndtering +Brickhyra = Leje af brik +Bricknr = Brik nummer +Bricknummret är upptaget (X) = Briknummeret er optaget (X) +Brickor = Brikker +Bygg databaser = Dan databaser +Byt till rätt klass (behåll eventuell starttid) = Skift til korrekt klasse (behold eventuel starttid) +Byt till vakansplats i rätt klass (om möjligt) = Skift til vakant plads i korrekt klasse (om muligt) +COM-Port = COM-Port +Calculate and apply forking = Beregn og brug gafling +Cancel = Annuller +Centrera = Centrer +Check = Check +Check: X = Check: X +Choose result module = Vælg resultatmodul +ClassCourseResult = Klasse, bane, resultat +ClassFinishTime = Klasse, måltid +ClassLength = Banelængde for klasse +ClassName = Klasse +ClassPoints = Klasse, points +ClassResult = Klasse, resultat +ClassResultFraction = Andel af klasse klar +ClassStartName = Startnavn +ClassStartTime = Klasse, starttid, navn +ClassStartTimeClub = Klasse, starttid, klub +ClassTeamLeg = Klasse, Hold, Tur +ClassTotalResult = Klasse, totalresultat +Clear Memory = Slet hukommelse +Clear selections = Slet valg +Club = Klub +Club and runner database = Klub og løber database +Club id number = Klub id nummer +ClubName = Klub +ClubRunner = Klub / løber +Clubs = Klubber +CmpDate = Løbsdato +CmpName = Løbsnavn +Control = Post +Control Overview = Post oversigt +Control Statistics = Post statistik +Control Statistics - X = Post statistik - X +ControlClasses = Klasser for post +ControlCodes = koder for post +ControlCourses = Baner for post +ControlMaxLostTime = Post, tidstab, maks. +ControlMedianLostTime = Post, tidstab, gennemsnit +ControlMistakeQuotient = Post, brøkdel af løbere med tidstab +ControlName = Postnavn +ControlPunches = Antal løbere der har stemplet post +ControlRunnersLeft = Antal løbere der mangler at stemple post +ControlVisitors = Forventet antal løbere til post +Country = Land +Course = Bane +CourseClasses = Banen klasser +CourseClimb = Banens stigning +CourseLength = Banelængde, specifik bane +CourseName = Banenavn +CourseResult = Bane, resultat +CourseShortening = Afkortning af banen +CourseUsage = Antal nødvendige kort for banen +CourseUsageNoVacant = Antal løbere på banen, uden vakantpladser +Create Competition = Opret løb +Created X distinct forkings using Y courses = Dannede X gaflinger ved brug af Y baner +CurrentTime = Aktuel tid +CustomSort = Tilpasset sortering +DATABASE ERROR = DATABASEFEJL +Data from result module (X) = Data fra resultatmodul (X) +Databasanslutning = Databaseforbindelse +Databasvarning: X = Database advarsel: X +Datorröst som läser upp förvarningar = Computerstemme der læser forvarslinger op +Datum = Dato +Datum (för första start) = Dato (for første start) +Debug = Debug +Debug Output = Debug Output +Debug X for Y = Debug X for Y +Decimalseparator = Decimal separator +DefaultFont = Standard skrifttype +Define forking = Definer gaflinger +Definierade mappningar = Definerede mappninger +Dela = Opdel +Dela efter placering = Fordel efter placering +Dela efter ranking = Opdel efter ranking +Dela efter tid = Fordel efter tid +Dela klass: X = Opdel klasse: X +Dela klassen = Opdel klasse +Dela klubbvis = Opdel efter klub +Dela slumpmässigt = Tilfældig fordeling +Dela upp = Fordel +Deltagare = Deltagere +Deltagare %d = Deltager %d +Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltageren 'X' deltager i patruljeklassen 'Y' men mangler en patrulje. Klassens start- och resultatlister kan dermed blive fejlbehæftede +Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltageren 'X' deltager i stafetklassen 'Y' men mangler et hold. Klassens start- och resultatlister kan dermed blive fejlbehæftede +Deltagaren 'X' saknar klass = Der er ikke angivet klasse for deltageren 'X' +Deltagarens klass styrs av laget = Deltagerens klasse bestemmes af hold +Deltar ej = Delt. ej +Denna etapps nummer = Denne etapes nummer +Description = Beskrivelse +Destinationskatalog = Mappe at gemme i +Det går endast att sätta in vakanser på sträcka 1 = Der kan kun indsættes vakante pladser på første tur +Det här programmet levereras utan någon som helst garanti. Programmet är = Dette program leveres uden nogen som helst garanti. Programmet er +Deviation +/- from expected time on course leg = Afvigelse +/- fra forventet tid på strækket +Direktanmälan = Tilmelding på stævnepladsen +Disk. = Diskv. +District id number = Kreds id nummer +Distriktskod = Kredskode +Do you want to clear the card memory? = Vil du slette indlæste brikdata? +Don't know how to align with 'X' = Kan ikke justeres i forhold til 'X' +Du kan importera banor och klasser från OCADs exportformat = Du kan importere baner og klasser fra OCAD's eksportformat +Du måste välja en klass = Du skal vælge en plads +Duplicera = Dupliker +Döp om = Omdøb +Döp om X = Omdøb X +E-post = Email +Economy and fees = Økonomi og afgifter +Edit Clubs = Rediger klubber +Edit Result Modules = Rediger resultatmoduler +Edit rule for = Rediger regel for +Efter = Efter +Efteranm. avg. = Eftertilm. afg. +Efteranmälda (efter ordinarie) = Eftertilmeldte (Efter ordinære) +Efteranmälda (före ordinarie) = Eftertilmeldte (Før ordinære) +Efteranmälda före ordinarie = Eftertilmeldte først +Efteranmälningar = Eftertilmeldte +Egen listrubrik = Egen listeoverskrift +Egen text = Egen tekst +Egenskaper = Egenskaber +Eget fönster = Nyt vindue +Egna listor = Egne lister +Egna textrader = Egne tekstlinjer +Ej accepterade elektroniska fakturor = Afviste elektroniske fakturaer +Ej elektronisk = Ikke elektronisk +Ej lottade = Ikke lodtrukne +Ej lottade, efter = Ikke lodtrukne, sidst +Ej lottade, före = Ikke lodtrukne, først +Ej start = Ej startet +Ej tidtagning = Ingen tidtagning +Ekonomi = Økonomi +Ekonomisk sammanställning = Økonomisk sammentælling +Elektronisk = Elektronisk +Elektronisk godkänd = Electronisk godkendt +Elit = Elite +Elitavgift = Eliteafgift +Elitklasser = Eliteklasser +En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning = En bane med sløjfer tillader løberen at ta sløjferne i valgfri rækkefølge. +En gafflad sträcka = En gaflet tur +En klass kan inte slås ihop med sig själv = En klasse kan ikke slås sammen med sig selv +En klubb kan inte slås ihop med sig själv = En klub kan ikke slås sammen med sig selv +Endast en bana = Kun en bane +Endast grundläggande = Grundfunktioner +Endast på obligatoriska sträckor = Håndter kun obligatoriske stræk. +Enhetens ID-nummer (MAC) = Enhedens ID (MAC) +Enhetstyp = Enhedstype +Error in result module X, method Y (Z) = Fejl i resultatmodul 'X', metode 'Y'\n\nZ +Etapp = Etape +Etapp X = Etape X +Etappresultat = Etaperesultater +Ett startblock spänner över flera starter: X/Y = En startblok skænder over flere starter: X/Y +Ett startintervall måste vara en multipel av basintervallet = Et startinterval skal være et multiplum af basisinterval +Ett värde vars tolkning beror på listan = En værdi hvis der fortolkning er afhængig af listen +Eventor server = Eventor server +Eventorkoppling = Eventor forbindelse +Eventors tider i UTC (koordinerad universell tid) = Eventor tider som UTC (Universal Coordinated Time) +Export av resultat/sträcktider = Eksport af resultater / stræktider +Exportera = Eksporter +Exportera / Säkerhetskopiera = Eksporter / Sikkerhedskopi +Exportera alla till HTML = Eksporter alle til HTML +Exportera alla till PDF = Exporter alt til PDF +Exportera datafil = Eksporter datafil +Exportera elektroniska fakturor = Eksporter elektroniske fakturaer +Exportera individuella lopp istället för lag = Eksporter individuelle løb istedet for hold +Exportera inställningar och löpardatabaser = Eksporter opsætning og løberdatabaser +Exportera klubbar (IOF-XML) = Eksporter klubber (IOF-XML) +Exportera löpardatabas = Eksporter løberdatabase +Exportera nu = Eksporter nu +Exportera personer (IOF-XML) = Eksporter personer (IOF-XML) +Exportera på fil = Eksporter til fil +Exportera resultat på fil = Eksporter resultater til fil +Exportera startlista = Exporter startliste +Exportera startlista på fil = Eksporter startliste til fil +Exportera sträcktider = Eksporter stræktider +Exportera tider i UTC = Exporter tider som UTC +Exportera till fil = Exporter til fil +Exportera tävlingsdata = Eksporter løbsdata +Exporterar om = Exporterer om +Exportformat = Exportformat +Exporttyp = Eksporttype +Exportval, IOF-XML = Eksportindst, IOF-XML +Externt Id = Eksternt Id +Extra = Ekstra +Extra avstånd ovanför textblock = Ekstra plads over tekstblok +Extra stämplingar = Ekstra stemplinger +Extralöparstafett = Ekstraløberstafet +FAKTURA = FAKTURA +FEL, inget svar = FEJL, intet svar +FEL: Porten kunde inte öppnas = FEJL: Porten kunne ikke åbnes +Failed to generate card = FEJL: Kunne ikke indlæse +Failed to open 'X' for reading = FEJL: Kunne ikke læse 'X' +Failed to read file = Kunne ikke læse fil +Faktiskt startdjup: X minuter = Faktisk startdybde: X minutter +Faktura = Faktura +Faktura nr = Faktura nr. +Fakturainställningar = Faktura indstillinger +Fakturanummer = Faktura nummer +Faktureras = Faktureres +Fakturor = Fakturaer +Fel: X = Fejl: X +Fel: hittar inte filen X = Fejl: Kan ikke finde filen 'X' +Felaktig kontroll = Forkert post +Felaktig nyckel = Forkert nøgle +Felaktig sträcka = Forkert tur +Felaktigt filformat = Forkert filformat +Felst. = Fejlklip +Fil att exportera till = Fil at eksportere til +Fil: X = Filnavn: X +Filen finns redan: X = Filen findes allerede: X +Filnamn = Filnavn +Filnamn (OCAD banfil) = Filnavn (OCAD banefil) +Filnamn IOF (xml) med klubbar = Filnavn IOF (XML) med klubber +Filnamn IOF (xml) med löpare = Filnavn IOF (XML) med løbere +Filnamnet får inte vara tomt = Filnavnet må ikke være tomt +Filnamnsprefix = Prefix for filnavn +Filter = Filter +FilterHasCard = Med brik +FilterNoCard = Uden brik +FilterNotVacant = Ikke vakant +FilterOnlyVacant = Kun vakant +FilterPrelResult = Foreløbigt resultat +FilterRentCard = Lejebrik +FilterResult = Med resultat +FilterSameParallel = Samlede parallelle stræk +FilterSameParallelNotFirst = Paralelle efterfølgende stræk +FilterStarted = Er startet +Filtrering = Filtrerer +Finish time for each team member = Måltid for hvert holdmedlem +FinishTime = Måltid, navn +FinishTimeReverse = Omvendt måltid (sidste først) +Flera banor = Flere baner +Flera banor / stafett / patrull / banpool = Flere baner / Stafet / Patrulje / Frit banevalg +Flera banor/stafett = Flere baner / Stafet +Flytta höger = Flyt til højre +Flytta vänster = Flyt til venstre +Forked individual courses = Gaflede individuelle baner +Forking setup = Opsætning af gaflinger +Forkings = Gaflinger +Forkings for X = Gaflinger til X +Format = Format +Formaterat webbdokument (html) = Formateret webdokument (html) +Formatering = Formattering +Formateringsregler = Formateringsregler +Formulärläge = Formularindstilling +Fortsätt = Fortsæt +Fri anmälningsimport = Tilmeldinger i frit format +Fri starttid = Fri starttid +Fria starttider = Frie starttider +Från klassen = Fra klassen +Från klubben = Fra klubben +Från kontroll = Fra post +Från laget = Fra holdet +Fullskärm = Fuldskærm +Funktion = Funktion +Funktioner = Funktioner +Funktioner i MeOS = Funktioner i MeOS +Fyll obesatta sträckor i alla lag med anonyma tillfälliga lagmedlemmar (N.N.) = Udfyld ubesatte ture på alle hold med anonyme midlertidige deltager (X) +Färg = Farve +Födelseår = Fødselsår +Följande deltagare deltar ej = Følgende deltagere deltager ikke +Följande deltagare har bytt klass = Følgende deltagere har skiftet klasse +Följande deltagare har bytt klass (inget totalresultat) = Følgende deltagere har skiftet klasse (intet samlet resultat) +Följande deltagare har tilldelats en vakant plats = Følgende deltagere er tildelt en vakant plads +Följande deltagare är anmälda till nästa etapp men inte denna = Følgende deltagere er tilmeldt næste etape, men ikke denne +Följande deltagare är nyanmälda = Følgende deltagere er nytilmeldte +Följande deltagare överfördes ej = Følgende deltagere blev ikke overført +För att delta i en lagklass måste deltagaren ingå i ett lag = En deltager skal være på et hold for at kunne deltage i en holdklasse. +För att ändra måltiden måste löparens målstämplingstid ändras = For at ændre måltid, skal løberens målstemplingstid ændres +För muspekaren över en markering för att få mer information = Før cursoren hen over en markering for at få mere information +För många kontroller = For mange poster +Förbered lottning = Forbered lodtrækning +Fördefinierade tävlingsformer = Foruddefinerede løbsformer +Fördela starttider = Fordel starttider +Föregående = Forrige +Föregående etapp = Forrige etape +Föregående kontroll = Foregående postenhed +Förekomst = Forekomst +Förhandsgranskning, import = Forhåndsvisning, import +Förhöjd avgift = Forhøjet afgift +Först-i-mål, gemensam = Først i mål, fælles +Först-i-mål, klassvis = Først i mål, klassevis +Första (ordinarie) start = Første (ordinære) start +Första fakturanummer = Første fakturanummer +Första kontrollen = Første post +Första omstartstid = Første efterstartstid +Första ordinarie starttid = Første ordinære starttid +Första start = Første start +Första starttid = Første starttid +Första sträckan kan inte vara parallell = Første stræk kan ikke være parallelt +Första tillåtna starttid = Først start tidligst +Försöket misslyckades = Forsøget mislykkedes +Förvarning på (SI-kod): alla stämplingar = Forvarsel (SI kode): alle stemplinger +Förvarningsröst = Forvarselsstemme +Förväntad andel efteranmälda = Forventet andel eftertilmeldte +Gafflade banor = Gaflede baner +Gafflingsnyckel X = Gafflingsnøgle X +Gata = Gade +Gemensam start = Fælles start +General = Generelt +Generera = Generer +Generera testtävling = Generer testløb +Genererad = Genereret +Geografisk fördelning = Geografisk fordeling +Global sorteringsordning = Global sorteringsorden +Godkänd = Godkendt +Godkänd API-nyckel = API-nøgle godkendt +Granska inmatning = Forhåndsvisning +Grund avg. = Grundafg. +Grundavgift = Grundafgift +Grundinställningar = Grundindstillinger +Gruppera = Grupper +Gräns för maxtid = Indstilling af maksimal løbstid +HTML med AutoRefresh = HTML med AutoRefresh +Hantera brickor = Håndter brikker +Hantera deltagare som bytt klass = Håndtering af deltagere der har skiftet klasse +Hantera egna listor = Håndter egne lister +Hantera flera etapper = Håndter flere etaper +Hantera jaktstart = Håndter jagtstart +Hantera klubbar = Håndter klubber +Hantera klubbar och ekonomi = Håndter klubber og økonomi +Hantera kvar-i-skogen = Håndter løbere-i-skoven +Hantera laget = Håndter holdet +Hantera löparbrickor = Håndter løberbrikker +Hela banan = Hele banen +Hemsida = Hjemmeside +Hindra att deltagare från samma klubb startar på angränsande tider = Sørg for at løbere fra samme klub ikke har starttider efter hinanden. +Hittar inte hjälpfilen, X = Kan ikke finde hjælpefilen, X +Hjälp = Hjælp +Hoppar över stafettklass: X = Spring stafetklasse over: X +Huvudlista = Hovedliste +Hyravgift = Lejeafgift +Hyrbricka = Lejebrik +Hyrbricksrapport = Lejebriksrapport +Hyrbricksrapport - %s = Lejebriksrapport - %s +Hyrd = Lejet +Hämta (efter)anmälningar från Eventor = Hent (efter)tilmeldinger fra Eventor +Hämta data från Eventor = Hent data fra Eventor +Hämta efteranmälningar = Hent eftertilmeldinger +Hämta löpardatabasen = Hent løberdatabasen +Hämta stämplingar m.m. från nätet = Hent stemplinger m.m. fra nettet. +Hämta svar om elektroniska fakturor = Hens svar om elektroniske fakturaer +Hämta tävlingsdata = Hent løbsdata +Hämta tävlingsdata för X = Hent løbsdata for X +Hämtar anmälda = Henter tilmeldte +Hämtar information om = Henter information om +Hämtar klasser = Henter klasser +Hämtar klubbar = Henter klubber +Hämtar löpardatabasen = Henter løberdatabasen +Hämtar tävling = Henter løb +Händelser = Begivenheder +Händelser - tidslinje = Begivenheder - tidslinje +Hög avgift = Forhøjet afgift +Höger = Højre +IOF (xml) = IOF (XML) +IOF Klubbdatabas, version 3.0 (xml) = IOF Klubdatabase, version 3.0 (xml) +IOF Löpardatabas, version 3.0 (xml) = IOF Løberdatabase, version 3.0 (xml) +IOF Resultat (xml) = IOF Resultater (XML) +IOF Resultat, version 2.0.3 (xml) = IOF Resultater, version 2.0.3 (XML) +IOF Resultat, version 3.0 (xml) = IOF Resultater, version 3.0 (XML) +IOF Startlista (xml) = IOF Startliste (XML) +IOF Startlista, version 2.0.3 (xml) = IOF Startliste, version 2.0.3 (xml) +IOF Startlista, version 3.0 (xml) = IOF Startliste, version 3.0 (xml) +IP-adress eller namn på en MySQL-server = IP addresse eller navn på en MySQL server +Id = Id +Identifierar X unika inledningar på banorna = Identificerer X unikke indledninger på banerne +Importera = Importer +Importera IOF (xml) = Importer IOF (XML) +Importera anmälda = Importer tilmeldte +Importera anmälningar = Importer tilmeldinger +Importera banor = Importer baner +Importera banor/klasser = Importer baner/klasser +Importera en tävling från fil = Importer løb fra fil +Importera fil = Importer fil +Importera från OCAD = Importer fra OCAD +Importera från fil = Importer fra fil +Importera laguppställningar = Importer holdopstillinger +Importera löpardatabas = Importer løberdatabase +Importera löpare = Importer løbere +Importera löpare och klubbar / distriktsregister = Importer løbere og klubber +Importera stämplingar = Importer stemplinger +Importera tävling = Importer løb +Importera tävlingsdata = Importer løbsdata +Importerar = Importerer +Importerar OCAD csv-fil = Importerer OCAD csv-fil +Importerar OE2003 csv-fil = Importerer OE2003 csv-fil +Importerar OS2003 csv-fil = Importerer OS2003 csv-fil +Importerar anmälningar (IOF, xml) = Importerer tilmeldinger (IOF, XML) +Importerar banor (IOF, xml) = Importerer baner (IOF, XML) +Importerar klasser (IOF, xml) = Importerer klasser (IOF, XML) +Importerar klubbar (IOF, xml) = Importerer klubber (IOF, XML) +Importerar tävlingsdata (IOF, xml) = Importerer løbsdata (IOF, XML) +Importerbara = Importerbare formater +Index = Index +Index in X[index] = Indeks i X[index] +Individual Example = Eksempel på individuelt resultat +Individual results in a club = Individuelle resultater for i klub. +Individuell = Individuel +Individuell resultatlista, alla lopp = Individuel resultatliste, alle løb +Individuell resultatlista, sammanställning av flera lopp = Individuel resultatliste, sammentælling af flere løb +Individuell resultatlista, visst lopp = Individuel resultatliste, bestemt løb +Individuell resultatlista, visst lopp (STOR) = Individuel resultatliste, bestemt løb (STOR) +Individuell startlista, visst lopp = Individuel startliste, bestemt løb +Individuell tävling = Individuelt løb +Individuella deltagare = Individuelle deltagere +Individuella resultat = Individuelle resultater +Individuella slutresultat = Individuelle slutresultater +Individuella totalresultat = Individuelle totalresultater +Individuellt, gafflat = Individuelt, gaflet +Info = Information +Inga = Ingen +Inga bommar registrerade = +Inga deltagare = Ingen deltagere +Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning = Ingen vakante. Vakante pladser oprettes normalt ved lodtrækning +Ingen = Ingen +Ingen / okänd = Ingen / ukendt +Ingen bana = Ingen bane +Ingen deltagare matchar sökkriteriet = Ingen deltagere matcher søgekriteriet +Ingen deltagare vald = Ingen deltagere valgt +Ingen klass = Ingen klasse +Ingen klass vald = Ingen klasse valgt +Ingen löpare saknar bricka = Ingen løbere mangler SI-brik +Ingen matchar 'X' = Ingen matcher 'X' +Ingen rogaining = Ingen pointløb +Inget nummer = Intet nummer +Inkommande = Indkommende +Inläst bricka ställd i kö = Aflæst brik sat i kø +Inlästa brickor = Aflæste brikker +Inmatning av mellantider = Indtastning af mellemtider +Inmatning online = Online indlæsning +Input Results = Input resultater +Input Results - X = Input resultater - X +Inspekterar klasser = Undersøger klasser +Installera = Installer +Installerbara listor = Installerbare lister +Inställningar = Indstillinger +Inställningar MeOS = MeOS, Opsætning +Inställningar startbevis = Instilliger for udskrift af startkvittering +Inställningar sträcktidsutskrift = Indstilling af stræktidsudskrifter +Interaktiv inläsning = Interaktiv indlæsning +Intervall = Interval +Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras = Interval (sekunder). Efterlad blank for at opdatere når løbsdata ændres +Intervallet måste anges på formen MM:SS = Intervallet skal angives som MM:SS +Invalid operator X = Ugyldig operator X +Italic = Kursiv +ItalicMediumPlus = Kursiv, større +Ja = Ja +Jag sköter lottning själv = Jeg foretager lodtrækning manuelt +Jaktstart = Jagtstart +Justera blockvis = Blokvis justering +Justera mot = Juster i forhold til +Jämna klasser (placering) = Udjævn klasser (placering) +Jämna klasser (ranking) = Udjævn klasser (ranking) +Jämna klasser (tid) = Udjævn klasser (tid) +Klart = Færdig +Klart. Antal importerade: X = Færdig. Antal importerede: X +Klart. X deltagare importerade = Færdig. X deltagere importeret +Klart. X lag importerade = Færdig. X hold importeret +Klart. X patruller importerade = Færdig. X patruljer importeret +Klart: alla klasser lottade = Færdig. Alle klasser er lodtrukne. +Klart: inga klasser behövde lottas = Færdig: Ingen klasser behøvede lodtrækning +Klass = Klasse +Klass %d = Klasse %d +Klass / klasstyp = Klasse / Klassetype +Klass X = Klasse X +Klass att slå ihop = Klasser der slås sammen +Klass saknad = Manglende klasse +Klassbyte = Skift af klasse +Klassen 'X' har jaktstart/växling på första sträckan = Klassen 'X' har jagtstart/skifte på første tur +Klassen X är individuell = Klassen X er individuel +Klassen används och kan inte tas bort = Klassen er i brug og kan ikke fjernes +Klassen lottas inte, startstämpling = Der foretages ikke lodtrækning i klassen, brug startstempling +Klassen måste ha ett namn = Klassen skal have et navn +Klassen saknas = Klassen mangler +Klassens bana = Klassens bane +Klasser = Klasser +Klasser (IOF, xml) = Klasser (IOF, XML) +Klasser där nyanmälningar ska överföras = Klasser hvortil nytilmeldinger skal overføres +Klassinställningar = Klasseindstillinger +Klassnamn = Klassenavn +Klasstyp = Klassetype +Klassval = Valg af klasse +Klientnamn = Klientnavn +Klistra in = Indsæt +Klistra in data från urklipp (X) = Indsæt fra udklipsholder (X) +Klocktid: X = Urtid: X +Klubb = Klub +Klubb att ta bort = Klub der fjernes +Klubb: X = Klub: X +KlubbId = Klub Id +Klubbar = Klubber +Klubbar (IOF, xml) = Klubber (IOF, XML) +Klubbar som inte svarat = Klubber som ikke har svaret +Klubbdatabasen = Klubdatabasen +Klubblös = Uden klub +Klubbresultat = Klubresultater +Klubbresultatlista = Klubresultatliste +Klubbresultatlista - %s = Klubresultatliste - %s +Klubbstartlista = Klubstartliste +Klubbstartlista - %s = Klubstartliste - %s +Klungstart = Gruppevis start +Knyt automatiskt efter inläsning = Knyt automatisk sammen efter aflæsning +Knyt bricka / deltagare = Knyt brik til løber +Knyt löpare till sträckan = Knyt løbere til turen +Knyt löparna till banor från en pool vid målgång = Knyt løbere til valgfrie baner ved målgang +Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka) = Tilknyt tilmeldte deltagere til holdet (identificeres ved navn og/eller brik) +Kod = Kode +Kom ihåg listan = Husk listen +Kommentar / version = Kommentar / Version +Kommunikation = Kommunikation +Kontant = Kontant +Kontant betalning = Kontant betaling +Konto = Konto +Kontroll = Post +Kontroll %s = Post %s +Kontroll X = Post X +Kontroll inför tävlingen = Kontrol før løbet +Kontrollen används och kan inte tas bort = Posten er i brug og kan ikke fjernes +Kontrollens ID-nummer = Postens ID-nummer +Kontroller = Poster +Kontrollmappning = Mappning af postenheder +Kontrollnamn = Postnavn +Kontrollrapport - X = Postrapport - X +Koordinater (mm) för adressfält = Koordinater (mm) for adressefelt +Kopia (X) = Kopi (X) +Kopia X = Kopi X +Kopiera länken till urklipp = Kopier link til udklipsholder +Kopiera selektionen till urklipp (X) = Kopier det valgte til udklipsholder (X) +Koppla ifrån = Afbryd +Koppla ner databas = Luk database +Kopplar ifrån SportIdent på = Afbryder SPORTident på +Kortast teoretiska startdjup utan krockar är X minuter = Korteste teoretiske startdybde uden sammenfald er X minutter +Kortnamn = Forkortet navn +Kunde inte ansluta till Eventor = Kunne ikke forbinde til Eventor +Kunde inte ladda X\n\n(Y) = Kunne ikke indlæse X\n\n(Y) +Kunde inte ladda upp tävlingen (X) = Kunne ikke uploade løbet (X) +Kunde inte öppna tävlingen = Kan ikke åbne løbet +Kvar-i-skogen = Løbere i skoven +Kvinna = Kvinde +Kvinnor = Kvinder +Källa = Kilde(fra) +Källkatalog = Mappe at hente fra +Kön = Køn +Kör kontroll inför tävlingen = Foretag kontrol før løbet +Ladda upp öppnad tävling på server = Upload åbnet løb til server +Lag = Hold +Lag %d = Hold %d +Lag(flera) = Hold +Laget 'X' saknar klass = Der er ikke angivet klasse for holdet 'X' +Laget hittades inte = Holdet blev ikke fundet +Lagmedlem = holddeltager +Lagnamn = Holdnavn +Lagrade säkerhetskopior = Gemte sikkerhedskopier +Laguppställning = Holdopstilling +Laguppställningen hade fel, som har rättats = Der var fejl i holdopsætningen som er blevet rettet +Land = Land +LargeFont = Stor tekst +Latest Results = Seneste resultarter +Latitud = Breddegrad +Leg X = Stræk X +Leg X: Do not modify = Stræk X: Ingen ændring +Leg X: Use Y = Stræk X: Brug Y +Leg number in team, zero indexed = Stræk nummer på hold, nul indekseret +Legs = Stræk +Length of course = Banelængde +List Error: X = Fejlliste: X +Lista = Liste +Lista av typ 'X' = Liste af type 'X' +Lista med mellantider = Liste med mellemtider +Lista med sträcktider = Liste med stræktider +Listan kan inte visas = Listen kan ikke vises +Listan togs bort från tävlingen = Listen blev fjernet fra løbet +Listegenskaper = Egenskaber for liste +Listnamn = Listenavn +Listor = Lister +Listor i tävlingen = Lister brugt i løb +Listor och sammanställningar = Lister og sammentællinger +Listparameter = Liste parameter +Listpost = Listepost +Listredigerare = Liste editor +Listredigerare – X = Liste editor – X +Listrubrik = Listeoverskrift +Listtyp = Listetype +Listval = Listevalg +Liveresultat, deltagare = Live resultater, individuelt +Ljudfiler, baskatalog = Lydfiler, hovedmappe +Lokalt = Lokalt +Long = Lang +Longitud = Længdegrad +Lopp %d = Løb %d +Lopp %s = Løb %s +Lopp X = Løb X +Lopp-id = Løbs ID +Lotta = Træk lod +Lotta / starttider = Lodtrækning / starttider +Lotta flera klasser = Lodtrækning flere klasser +Lotta klassen = Lodtrækning, klasse +Lotta klassen X = Lodtrækning, klasse 'X' +Lotta löpare som saknar starttid = Lodtrækning blandt løbere der mangler starttid +Lotta om hela klassen = Ny lodtrækning for hele klassen +Lottad = Lodtrukken +Lottad startlista = Lodtrukken startliste +Lottar efteranmälda = Trækker lod blandt eftertilmeldte +Lottar: X = Trækker lod: X +Lottning = Lodtrækning +Lyssna = Lyt +Lyssnar på X = Lytter på X +Lägg till = Tilføj +Lägg till alla = Tilføj alle +Lägg till en ny rad i tabellen (X) = Tilføj række i tabellen (X) +Lägg till klasser = Tilføj klasser +Lägg till ny = Tilføj ny +Lägg till ny etapp = Tilføj ny etape +Lägg till rad = Tilføj række +Lägg till stämpling = Tilføj stempling +Lägger till klubbar = Tilføjer klubber +Lägger till löpare = Tilføjer løbere +Längd = Længde +Längd (m) = Længde (m) +Länk till resultatlistan = Link til resultatlisten +Länk till startlistan = Link til startlisten +Läs brickor = Læs brikker +Läser klubbar = Læser klubber +Läser löpare = Læser løbere +Långt namn = Langt navn +Låt de bästa start först = Lad de bedste starte først +Låt klassen ha mer än en bana eller sträcka = Lad klassen have mere end en bane eller en tur +Löpande = Løbende +Löpande information om viktiga händelser i tävlingen = Løbende information om vigtige begivenheder i løbet +Löparbricka %d = Løberbrik %d +Löpardatabasen = Løberdatabase +Löpare = Løber +Löpare per klass = Løbere pr. klasse +Löpare saknar klass eller bana = Løbere uden klasse eller brik +Löpare som förekommer i mer än ett lag = Løbere som forekommer på mere end et hold +Löpare utan SI-bricka: %d = Løbere uden SI-brik: %d +Löpare utan bana: %d = Løbere uden bane: %d +Löpare utan klass: %d = Løbere uden klasse: %d +Löpare utan klubb: %d = Løbere uden klub: %d +Löpare utan starttid: %d = Løbere uden starttid: %d +Löpare, Ej Start, med registrering (kvar-i-skogen!?) = Løbere, ikke startet, registreret (i skoven!?) +Löpare, Status Okänd, med registrering (kvar-i-skogen) = Løbere, Status ukendt, registreret (i skoven) +Löpare, Status Okänd, som saknar registrering = Løbere, Status ukendt, mangler registrering +Löpare: = Løber: +Löpare: X, kontroll: Y, kl Z = Løber: X, post: Y, kl: Z +Löparen hittades inte = Løber ikke fundet +Löptid = Løbstid +Lösenord = Password +Man = Mand +Manual point reductions and adjustments = Manuel pointreduktion og justering +Manual time penalties and adjustments = Manuelle tidsstraf og justeringer +Manuell = Manuel +Manuell inmatning = Manuel indtastning +Manuell lottning = Manuel lodtrækning +Manuella avgifter = Manuelle afgifter +Mapp = Mappe +Mappnamnet får inte vara tomt = Mappenavnet må ikke være tomt +Markera 'X' för att hantera deltagarna en och en = Marker med 'X' for at håndtere deltagerne enkeltvis +Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar = Indtast første nummer for brystnumre, eller lad stå blank for at fjerne brystnumre +Mata in radiotider manuellt = Indtast radiotider manuelt +Matched control ids (-1 for unmatched) for each team member = Matchende kontrol id'er (-1 for umatchet) for hvert holdmedlem +Max antal gemensamma kontroller = Maks. antal fælles poster +Max parallellt startande = Maks. antal samtidigt startende +Max. vakanser (per klass) = Maks. vakante (pr klasse) +Maxbom = Maks. bom +Maximal tid efter ledaren för att delta i jaktstart = Maks. tid efter førende løber for at deltage i jagtstart +Maximum allowed running time = Maksimal løbstid +Maxtid = Maks.tid +Maxtid efter = Maks. tid efter +MeOS = MeOS +MeOS Features = MeOS Specialfunktioner +MeOS Funktioner = MeOS Funktioner +MeOS Three Days Race X = MeOS Tredages Løb X +MeOS lokala datakatalog är = MeOS lokale datamappe er +MeOS – Funktioner = MeOS – Funktioner +MeOS – Resultatkiosk = MeOS – Resultatformidling +Med anmälningsavgift (lagets klubb) = Med tilmeldingsafgift (holdets klub) +Med avkortning = Med afkortning +Med km-tid = Med km-tid +Med stafettklasser = Med stafetklasser +Med sträcktidsanalys = Med stræktidsanalyse +Medianbom = Median bom +Medium = Mellem +MediumFont = Medium tekst +MediumPlus = Noget større tekst +Medlöpare = Medløber +Mellantider visas för namngivna kontroller = Mellemtider vises for navngivne poster +Metod = Metode +Min. vakanser (per klass) = Min. vakante (pr klasse) +Minitid = Min. tid +Minst MySQL X krävs. Du använder version Y = MeOS kræver MySQL X eller nyere. Du bruger version Y +Minsta intabbning = Mindste indrykning +Minsta intervall i klass = Korteste interval i klasse +Minsta startintervall = Korteste startinterval +Minsta sträcktid = Korteste stræktid +Minutstartlista = Minutstartliste +Misslyckades med att ladda upp onlineresultat = Kunne ikke flytte resultater op online +Motion = Motion +Multipel = Multiple +MySQL Server / IP-adress = MySQL Server / IP-addresse +Män = Mænd +Mål = Mål +Målfil = Destinationsfil +Målstämpling saknas = Manglende målstempling +Måltid = Måltid +Måltid saknas = Måltid mangler +Måltid: X = Måltid: X +N.N. = N.N. +Name of result module = Navn på resultatmodul +Namn = Navn +Namn och tidpunkt = Navn og løbsperiode +Namnet kan inte vara tomt = Navn må ikke være tomt +Narrow Results = Smal resultatliste +Nationalitet = Nationalitet +Nationality = Nationalitet +Nej = Nej +New Result Module = Nyt resultatmodul +New Set of Result Rules = Nyt sæt resultatregler +Nollställ avgifter = Nulstil afgifter +Nollställ databaser = Nulstil databaser +Nollställde avgift för X deltagare = Nulstillede afgifter for X deltager(e) +Nolltid = Nultid +None = Ingen +Normal = Normal +NormalFont = Normal tekst +Normalavgift = Normal afgift +Not implemented = Ikke implementeret +Not yet implemented = Endnu ikke tilgægelig +Nr = Nummer +Number of shortenings = Antal afkortninger +Nummerlapp = Brystnummer +Nummerlapp, SI eller Namn = Brystnummer, SI-brik eller Navn +Nummerlapp, lopp-id eller namn = Brystnummer, løbsnummer eller navn +Nummerlappar = Brystnumre +Nummerlappar i X = Brystnumre i X +Nuvarande innehavare: X = Nuværende indehaver: X +Ny bana = Ny bane +Ny deltagare = Ny deltager +Ny klass = Ny klasse +Ny klubb = Ny klub +Ny kontroll = Ny post +Ny lista = Ny liste +Ny tävling = Nyt løb +Nyckel för Eventor = Eventor nøgle +Nytt fönster = Nyt vindue +Nytt lag = Nyt hold +Nästa = Næste +Nästa etapp = Næste etape +Nästa försök = Næste forsøg +OE Semikolonseparerad (csv) = OE semikolonsepareret (csv) +OK = OK +OL-Skytte med tidstillägg = Biatlon med tidstillæg +OL-Skytte stafettresultat = Biatlon, stafetresultat +OL-Skytte utan tidstillägg = Biatlon uden tidstillæg +Oberoende = Uafhængig +Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y' = Ugyldig banefil. Post forventet på position X, men fandt 'Y' +Ogiltig funktion = Ugyldig funktion +Ogiltig föregående/efterföljande etapp = Ugyldig foregående / efterfølgende etape +Ogiltig första starttid. Måste vara efter nolltid = Ugyldig første starttid. Skal være efter nultid. +Ogiltig kontrollkod = Ugyldigt nummer på postenhed +Ogiltig omstartstid = Ugyldig efterstartstid +Ogiltig repdragningstid = Ugyldig tid for sidste skift +Ogiltig starttid i 'X' på sträcka Y = Ugyldig starttid i 'X' på tur Y +Ogiltig starttid: X = Ugyldig starttid: X +Ogiltig storlek på seedningsgrupper X = Ugyldig størrelse på seeding gruppe: X +Ogiltig tid = Ugyldig tid +Ogiltigt basintervall = Ugyldigt basis interval +Ogiltigt bricknummer = Ugyldigt briknummer +Ogiltigt bricknummer X = Ugyldigt briknummer X +Ogiltigt filformat = Ugyldigt filformat +Ogiltigt lag på rad X = Ugyldigt hold i linje X +Ogiltigt maximalt intervall = Ikke tilladt maksimalt interval +Ogiltigt minimalt intervall = Ikke tilladt minimalt interval +Okänd = Ukendt +Okänd bricka = Ukendt brik +Okänd funktion = Ukendt funktion +Okänd klass = Ukendt klasse +Okänd klass på rad X = Ukendt klasse i linje X +Okänd klubb med id X = Ukendt klub med id X +Om MeOS = Om MeOS +Om MeOS – ett Mycket Enkelt OrienteringsSystem = Om MeOS – et Meget Enklere Orienterings System +Omstart = Efterstart +Omstart i stafettklasser = Efterstart i stafetklasser +Omstartstid = Efterstartstid +Omvänd jaktstart = Omvendt jagtstart +Online Input Error X = Online inddata fejl X +Online Results Error X = Onlineresultatsfejl X +Onlineinput = Online inddata +Onlineresultat = Onlineresultat +Onlineservern svarade felaktigt = Online server gav uventet svar (Forkert konfiguration?) +Onlineservern svarade: Felaktigt lösenord = Online server svarede: Forkert password +Onlineservern svarade: Felaktigt tävlings-id = Online server svarede: forkert konkurrence-id +Onlineservern svarade: Serverfel = Online server svarede: server fejl +Onlineservern svarade: ZIP stöds ej = Online server svarede: Zip-formet understøttes ikke. +Oordnade parallella sträckor = Ikke sorterede parallelle stræk +Oparad = Uparret +Open = Åben +Open X = Åben X +Open a Copy = Åbn som kopi +Operationen misslyckades = Handlingen mislykkedes +Operationen stöds ej = Handlingen understøttes ikke +Optimerar startfördelning = Optimerer startfordeling +Ordinarie anmälningsdatum = Ordinær tilmeldingsdato +Ordinarie avgift = Ordinær afgift +Ordnat = Ordnede +Organisation = Organisation +Organisatör = Arrangør +Oväntad kontroll 'X' i bana Y = Uventet post 'X' på bane Y +PDF = PDF +Packa stora filer (zip) = Komprimer store filer (zip) +Packar upp löpardatabas = Pakker løberdatabase ud +Par- eller singelklass = Par- eller singleklasse +Para ihop = Dan par +Para ihop bricka X med en deltagare = Par brik X med en deltager +Parallell = Parallel +PatrolClubNameNames = Deltagers (eller patruljes) klub(ber) +PatrolNameNames = Deltagers (eller patruljes) navn(e) +Patrols = Patruljer +Patrull = Patrulje +Patrull, 1 SI-pinne = Patrulje, 1 SI-brik +Patrull, 2 SI-pinnar = Patrulje, 2 SI-brikker +Personer = Personer +Plac. = Plac. +Place on course leg = Placering på strækket +Placering = Placering +Placering in = Placering i +Plats = Plads +Point calculation for runner = Pointberegning for løber +Point calculation for team = Pointberegning for hold +Points as computed by your point method = Point udregnet efter din beregningsmetode +Port = Port +Port för TCP = Port for TCP +Portable Document Format (PDF) = Portable Document Format (PDF) +Postadress = Postadresse +Postkod = Postnummer +Poäng = Points +Poäng in = Points i +Poängavdrag = Pointfradrag +Poängavdrag (per minut) = Pointfradrag (pr minut) +Poängavdrag per påbörjad minut = Pointfradrag for hvert påbegyndt minut +Poänggräns = Pointgrænse +Poängjustering = Pointjustering +Prel. bomtid = Forel. tidstab +Prel. placering = Forel. placering +Prepare start lists = Forbered startliste +Press Enter to continue = Tast for at fortsætte +Print Card Data = Udskriv brikdata +Print card data = Udskriv brikdata +Prioritering = Prioritering +Prisutdelningslista = Prisuddelingsliste +Programinställningar = Programindstillinger +Prolog + jaktstart = Prolog + jagtstart +Prologue + Pursuit = Prolog + Jagtstart +Publicera resultat = Offentliggør resultat +Publicera resultat direkt på nätet = Publicer resultater på nettet med løbende +Publicera resultat och sträcktider på Eventor och WinSplits online = Offentligør resultat og stræktider på Eventor og WinSplits online +Publicera startlista = Offentliggør startliste +Publicera startlistan på Eventor = Offentliggør startliste på Eventor +Publicerar resultat = Offentliggør resultat +Publicerar startlistan = Offentliggører startlisten +Punch codes for each team member = Stempelkoder for hvert holdmedlem +Punch times for each team member = Stempeltider for hvert holdmedlem +PunchControlCode = Postenheds kode +PunchControlNumber = Post nummer +PunchControlPlace = Placering, tur, ved post +PunchControlPlaceAcc = Samlet placering, ved post +PunchLostTime = Tidstab ved post +PunchNamedTime = Navngivet mellemtid +PunchTime = Stemplingstid +Punches = Stemplinger +På banan = På banen +Rader markerade med (*) kommer från en lista i tävlingen = Rækker mærket med (*) kommer fra en liste tilknyttet løbet +Radera = Slet +Radera alla klubbar = Slet alle klubber +Radera alla klubbar och ta bort klubbtillhörighet = Slet alle klubber og klubmedlemsskaber +Radera listan från aktuell tävling = Slet listen fra dette løb +Radera permanent = Slet permanent +Radera starttider = Slet starttider +Radera tävlingen = Slet løbet +Radera vakanser = Slet vakante +Radiotider, kontroll = Radiotider, post +Ranking = Rangliste +Ranking (IOF, xml) = Rangliste (IOF, XML) +Rapport inför = Rapport før +Rapporter = Rapporter +Rapportläge = Rapportindstilling +Red. avg. efteranm = Red.efteranm.afg. +Red. avgift = Red. afgift +Redigera = Ret +Redigera deltagaren = Rediger løberen +Redigera lista = Rediger liste +Redigera listpost = Rediger listepost +Redigera sträcklängder = Rediger længde af stræk +Redigera sträcklängder för X = Rediger længder af stræk for 'X' +Reducerad avg = Reduceret afgift +Reduktionsmetod = Reduktionsmetode +Region = Region +Regler för resultatuträkning = Regler for resultatberegning +Regler för resultatuträkning - X = Regler for resultatberegning - X +Relativ skalfaktor för typsnittets storlek i procent = Relativ faktor for skalering af font (procent) +Relay Example = Stafet eksempel +Relays = Stafetter +Rep = Sidste veksling +Reparera vald tävling = Reparer valgte løb +Reparerar tävlingsdatabasen = Reparerer løbsdatabasen +Repdragningstid = Tidspunkt for sidste skift +Repdragningstiden måste ligga före omstartstiden = Tidspunkt for sidste skift skal ligge før efterstarttidspunktet +Reserverade = Reserveret +Result Calculation = Resultatberegning +Result Module – X = Resultatmodul – X +Result Modules = Resultatmoduler +Result module identifier = Resultatmodul ID +Result score calculation for runner = Resultatberegning for løber +Result score calculation for team = Resultatberegning for hold +ResultDescription = Navn på resultattype +ResultModuleNumber = Resultatmodul: Nummer +ResultModuleNumberTeam = Resultat Modul: Placering (for hold) +ResultModuleTime = Resultmodul: Tid +ResultModuleTimeTeam = Resultat Modul: Samlet tid (for hold) +Resultat = Resultater +Resultat && sträcktider = Resultater && stræktider +Resultat (STOR) = Resultater (STOR) +Resultat - %s = Resultater - %s +Resultat - X = Resultater - X +Resultat banvis per klass = Resultater banevis pr klasse +Resultat efter klass och bana - X = Resultat efter klasse og bane - X +Resultat efter sträcka X = Resultat efter tur X +Resultat efter sträckan = Resultat efter turen +Resultat från tidigare etapper = Resultater fra tidligere etaper +Resultat för ett visst lopp = Resultater for et bestemt løb +Resultat lopp X - Y = Resultater løb X - Y +Resultat online = Resultater online +Resultat per bana = Resultater pr bane +Resultat per bana - X = Resultater pr bane - X +Resultat vid målstämpling = Resultater efter målstempling +Resultat, generell = Resultater, generelt +Resultat, individuell = Resultater, individuelle +Resultat, patrull = Resultater, patrulje +Resultatkiosk = Resultatformidling +Resultatlista - %s = Resultatliste - %s +Resultatlista – inställningar = Resultatliste – indstillinger +Resultatlistor = Resultatlister +Resultatmodulen används i X = Resultatmodulet bruges i X +Resultatuträkning = Resultatberegning +Resultatutskrift = Udskriv resultater +Resultatutskrift / export = Udskriv resultater / eksport +Rogaining = Pointløb +Rogaining points for each team member = Pointløbs points for hvert holdmedlem +Rogaining, individuell = Pointløb, individuelt +Rogaining-poäng = Points +RogainingPunch = Stempling, pointløb +Rogainingresultat - %s = Rogaining resultater - %s +Rubrik = Overskrift +Rulla upp och ner automatiskt = Rul op og ned automatisk +Runner = Løber +Runner's card, matched control ids (-1 for unmatched punches) = Løbers SI-brik, matchende kontrol id'er (-1 for ikke matchende stemplinger) +Runner's card, punch codes = Løbers SI-brik, stempelkoder +Runner's card, punch times = Løbers SI-brik, stempeltider +Runner's course = Løbers bane +Runner's method output numbers = Løber metode - output numre +Runner's method output times = Løber metode, output tider +Runner's split times = Løbers mellemtider +Runner's total running time to control = Løbers samlede løbstid til post +Runner/team fee = Løber/hold afgift +Runner/team finish time = Løber/hold sluttid +Runner/team input place = Løber/hold indgående placering +Runner/team input points = Løber/hold indgående points +Runner/team input running time = Løber/hold indgående løbstid +Runner/team input status = Løber/hold indgående status +Runner/team place = Løber/hold placering +Runner/team rogaining overtime = Løber/hold pointløbs tidsoverskridelse +Runner/team rogaining points = Løber/hold pointløbs point +Runner/team rogaining points adjustment = Løber/hold pointløbs points justering +Runner/team running time = Løber/hold løbstid +Runner/team start time = Løber/hold starttid +Runner/team status = Løber/hold status +Runner/team time adjustment = Løber/hold tidsjustering +Runner/team total place = Løber/hold samlet placering +Runner/team total running time = Løber/hold samlet løbstid +Runner/team total status = Løber/hold samlet status +RunnerAge = Løbers alder +RunnerBib = Løbers brystnummer +RunnerBirthYear = Løbers fødselsår +RunnerCard = Briknummer +RunnerClassCoursePlace = Placering på bane indenfor klasse +RunnerClassCourseTimeAfter = Tid efter på bane indenfor klasse +RunnerClub = Løbers klub +RunnerCompleteName = Fulde navn +RunnerCourse = Løbers bane +RunnerFamilyName = Efternavn +RunnerFee = Startafgift +RunnerFinish = Løbers måltid +RunnerGeneralPlace = Hold eller individuel løbers placering +RunnerGeneralTimeAfter = Hold eller individuel løbers tid efter +RunnerGeneralTimeStatus = Hold eller individuel løbers tid /status +RunnerGivenName = Fornavn +RunnerGlobal = Løber (klasser sammenlagt) +RunnerLeg = Løber (specifik tur) +RunnerLegNumberAlpha = Formateret turnummer +RunnerName = Løbers navn +RunnerNationality = Løbers nationalitet +RunnerPhone = Løbers telefonnummer +RunnerPlace = Løbers placering +RunnerPlaceDiff = Løbers placering, forskel +RunnerPointAdjustment = Løbers pointjustering +RunnerRank = Rangliste +RunnerRogainingOvertime = Løbers tidsoverskridelse(pointløb) +RunnerRogainingPoint = Points +RunnerRogainingPointTotal = Løbers total points +RunnerRogainingReduction = Løbers pointsfradrag +RunnerSex = Løbers køn +RunnerStart = Løbers starttid +RunnerStartNo = Løbers startnummer +RunnerTempTimeAfter = Løbers tid efter ved udvalgt post +RunnerTempTimeStatus = Løbers tid / status ved udvalgt post +RunnerTime = Løbers tid +RunnerTimeAdjustment = Løbers tidsjustering +RunnerTimeAfter = Løbers tid efter +RunnerTimeAfterDiff = Løbers tid efter, forskel +RunnerTimeLost = Løbers mistede tid +RunnerTimePerKM = Tempo min/km +RunnerTimePlaceFixed = Tidspunkt hvor løbers placering er endelig +RunnerTimeStatus = Løbers tid / status +RunnerTotalPlace = Løbers totalplacering +RunnerTotalTime = Løbers totaltid +RunnerTotalTimeAfter = Løbers totaltid efter +RunnerTotalTimeStatus = Løbers totaltid / status +RunnerUMMasterPoint = Uppsala möte, mesterskabspoints +Running time for each team member = Løbstid for hvert holdmedlem +SI X inläst. Brickan tillhör Y som saknar klass = SI X blev aflæst. Brikken tilhører Y, der mangler klasse +SI X inläst. Brickan är inte knuten till någon löpare (i skogen) = SI X blev aflæst. Brikken er ikke tilknyttet nogen løber (i skoven) +SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen = SI X er allerede aflæst. Brug interaktiv aflæsning for at aflæse igen. +SI X är redan inläst. Ska den läsas in igen? = SI X er allerede aflæst. Læs den igen? +SI på = SI på +SI-dubbletter: %d = SI-dubletter: %d +SOFT-avgift = DO-F afgift +SOFT-lottning = Svensk lodtrækning +Saknad starttid = Manglende starttid +Samma = Samme +Sammanställning = Sammenfatning +Sammanställning, ekonomi = Sammenfatning, økonomi +Sammanställning, klasser = Sammenfatning, klasser +Samtliga deltagare tilldelades resultat = Samtlige deltagere blev tildelt et resultat +Save = Gem +Save changes = Gem ændringer +Save changes in rule code? = Gem ændringer i regelkode? +Seedad lottning = Seedet lodtrækning +Seedningsgrupper = Seedningsgrupper +Seedningskälla = Kilde til seedning +Sekundär typ = Sekundær type +Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? = Det valgte områdes størrelse matcher ikke udklippets størrelse. Sæt ind alligevel? +Semikolonseparerad (csv) = Semikolon separeret (csv) +Sen avgift = Eftertilm. +Sen red. avgift = Red.eftertilm. +Server = Server +Server: [X] Y = Server: [X] Y +Several MeOS Clients in a network = Flere MeOS-klienter i et netværk +Several races for a runner = Flere løb for en løber +Several stages = Flere etaper +Short = Kort +Shortest time in class = Korteste tid i klassen +Show forking = Vis gaflinger +Sidbrytning mellan klasser = Sideskift mellem klasser +Sidbrytning mellan klasser / klubbar = Sideskift mellem klasser / klubber +Simulera inläsning av stämplar = Simuler aflæsning af stemplinger +Sista betalningsdatum = Sidste betalingsdato +Sista ordinarie anmälningsdatum = Sidste ordinære tilmeldingsdato +Sista start (nu tilldelad) = Sidste start (nu tildelt) +Sista start (nu tilldelad): X = Sidste start (nu tildelt): X +Sista sträckan = Sidste tur +Ska X raderas från tävlingen? = Skal X fjernes fra løbet? +Skalfaktor = Skaleringsfaktor +Skapa = Opret +Skapa anonyma lagmedlemmar = Opret anonyme deltagere på hold +Skapa en ny tävling med data från Eventor = Dan et nyt løb med data fra Eventor +Skapa en ny, tom, tävling = Opret et nyt, tomt, løb +Skapa fakturor = Dan fakturaer +Skapa generell lista = Opret generel liste +Skapa listan = Opret listen +Skapa ny klass = Opret ny klasse +Skapa tävlingen = Opret løb +Skapad av = Oprettet af +Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) = Oprettede en bane for klassen %s med %d poster ud fra SI-%d +Skapade en lokal kopia av tävlingen = Oprettede en lokal kopi af løbet +Skapar ny etapp = Opretter ny etape +Skapar ny tävling = Opretter nyt løb +Skapar saknad klass = Opretter manglende klasse +Skapar tävling = Opretter løb +Skattad avgift = Beskattet afgift +Skicka och ta emot snabb förhandsinformation om stämplingar och resultat = Send og modtag hurtig forhåndsinformation om stemplinger og resultater +Skicka till webben = Overfør til Web'en +Skippar lottning = Springer over lodtrækning +Skript = Script +Skript att köra efter export = Script til at køre efter eksport +Skriv endast ut ändade sidor = Udskriv kun ændrede sider +Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben = Skriv første bogstav i klubbens navn og tryk pil-ned for at finde klubben +Skriv första starttid på formen HH:MM:SS = Skriv første starttid på formen HH:MM:SS +Skriv ut = Udskriv +Skriv ut alla = Udskriv alle +Skriv ut dem utan e-post = Udskriv dem uden e-post +Skriv ut ej accepterade elektroniska = Udskriv ikke accepterede elektroniske +Skriv ut eller exportera listan automatiskt = Udskriv eller eksporter listen automatisk +Skriv ut fakturan = Udskriv fakturaen +Skriv ut listan = Udskriv listen +Skriv ut nu = Udskriv nu +Skriv ut rapporten = Udskriv rapporten +Skriv ut startbevis = Udskriv Startkvittering +Skriv ut startbevis för deltagaren = Udskrive startkvittering for løberen +Skriv ut sträcktider = Udskriv stræktider +Skriv ut tabellen = Udskriv tabellen +Skriv ut tabellen (X) = Udskriv tabellen (X) +Skriv över existerande bricknummer? = Overskriv eksisterende briknummer? +Skrivare = Printer +Skrivarinställningar = Printer indstilling +Skrivarinställningar för sträcktider = Printerindstillinger for stræktider +Skrivarinställningar för sträcktider och startbevis = Printerinstillinger for stræktider og startkvittering +Skriver sträcktider när tävlingsdata ändras = Skriver stræktider så snart løbsdata ændrer sig +Skriver sträcktider om = Udskriver stræktider om +Slutresultat = Endelige resultater +Sluttid = Sluttid +Slå ihop = Slå sammen +Slå ihop klass: X = Slå klasse X sammen +Slå ihop klass: X (denna klass behålls) = Slå klasse X sammen: (behold denne klasse) +Slå ihop klasser = Slå klasser sammen +Slå ihop klubb = Slå klub sammen +Slå ihop text med föregående = Slå tekst sammen med foregående +SmallFont = Lille skrifttype +SmallItalic = Lille, kursiv skrifttype +Snabbinställningar = Hurtigindstillinger +SortNameOnly = navn +Sortering = Sorterer +Sortering: %s, antal rader: %d = Sorterer: %s, antal rækker: %d +Source code = Kildekode +Spara = Gem +Spara anmälningar = Gem tilmeldinger +Spara den här listan som en favoritlista = Gem denne liste som en foretrukken liste +Spara fil = Gem fil +Spara för webben = Gem web dokument +Spara i aktuell tävling = Gem i aktuelt løb +Spara laguppställningar = Gem holdopstillinger +Spara på disk = Gem på disk +Spara som = Gem som +Spara som PDF = Gem som PDF +Spara som fil = Gem som fil +Spara sträcktider till en fil för automatisk synkronisering med WinSplits = Gem stræktider i en fil for automatisk synkronisering med WinSplits +Spara tid = Gem tid +Sparade listval = Gemte listevalg +Speaker = Speaker +Speakerstöd = Speaker funktion +SportIdent = SPORTident +Språk = Sprog +Stad = By +Stafett = Stafet +Stafett (sammanställning) = Stafet (sammenfatning) +Stafett - sammanställning = Stafet - sammenfatning +Stafett - sträcka = Stafet - tur +Stafett - total = Stafet - total +Stafettklasser = Stafetklasser +Stafettresultat = Stafet Resultater +Stafettresultat, delsträckor = Stafetresultater, delstræk +Stafettresultat, lag = Stafetresulater, hold +Stafettresultat, sträcka = Stafetresultater, tur +Stafettresultat, sträcka (STOR) = Stafetresultater, tur (STOR) +Standard = Standard +Start = Start +Start nr = Start nr +Start time for each team member = Starttid for hvert holdmedlem +Start: X = Start: X +StartTime = Starttid, navn +StartTimeForClass = Fælles starttid, klasse +Starta = Start +Starta automaten = Start autofunktion +Starta en guide som hjälper dig göra klassinställningar = Start en guide som hjælper dig med at foretage klasseindstillinger +Startade automater = Startede autofunktioner +Startande = Startende +Startar SI på = Starter SI på +Startbevis = Startkvittering +Startbevis X = Startkvittering X +Startblock = Startblok +Startblock: %d = Startblok: %d +Startintervall = Startinterval +Startintervall (min) = Startinterval (min) +Startintervallet får inte vara kortare än basintervallet = Startinterval må ikke være kortere end basisintervallet +Startlista = Startliste +Startlista %%s - sträcka %d = Startliste %%s - tur %d +Startlista - %s = Startliste - %s +Startlista - X = Startliste - X +Startlista ett visst lopp = Startliste for et bestemt løb +Startlista lopp X - Y = Startliste løb X - Y +Startlista, individuell = Startliste, individuel +Startlista, patrull = Startliste, patruljer +Startlista, stafett (lag) = Startliste, stafet (hold) +Startlista, stafett (sträcka) = Startliste, stafet (tur) +Startlistor = Startlister +Startmetod = Startmetode +Startnamn = Start navn +Startnummer = Startnummer +Starttid = Starttid +Starttid (HH:MM:SS) = Starttid (HH:MM:SS) +Starttid: X = Starttid: X +Starttiden är upptagen = Starttiden er optaget +Starttyp = Start type +Status = Status +Status OK = Status OK +Status as computed by your status method = Status som udregnet efter din statusmetode +Status calculation for runner = Statusberegning for løber +Status calculation for team = Statusberegning for hold +Status code for a missing punch = Statuskode for manglende stempling +Status code for a time over the maximum = Statuskode for tid over maksimumtid +Status code for a valid result = Statuskode for et gyldigt resultat +Status code for an unknown result = Statuskode for et ukendt resultat +Status code for disqualification = Statuskode for diskvalifikation +Status code for not competing = Statuskode for ikke deltaget +Status code for not finishing = Statuskode for udgået +Status code for not starting = Statuskode for ikke startet +Status for each team member = Status for hvert holdmedlem +Status in = Status ind +Status matchar inte data i löparbrickan = Status matcher ikke data i SI-brikken. +Status matchar inte deltagarnas status = Status matcher ikke deltagerens status. +Stoppa automaten = Stop autofunktionen +Stor = Stor +Str. = Str. +Str. %d = Str. %d +Str. X = Tur X +String = Tekst +Struken = Afbud +Struken med återbetalning = Afbud med tilbagebetaling +Struken utan återbetalning = Afbud uden tilbagebetaling +Strukturerat exportformat = Struktureret eksportformat +Strukturerat webbdokument (html) = Struktureret webdokument (html) +Sträcka = Tur +Sträcka %d = Tur %d +Sträcka X = Tur X +Sträcka att lotta = Ture til lodtrækning +Sträckans banor = Strækkets baner +Sträcktider = Stræktider +Sträcktider (WinSplits) = Stræktider (WinSplits) +Sträcktider / WinSplits = Stræktider / WinSplits +Sträcktider/WinSplits = Stræktider/WinSplits +Sträcktidsfil = Stræktidsfil +Sträcktidsutskrift = Udskriv stræktider +Sträcktidsutskrift[check] = Udskriv stræktider automatisk +Sträcktilldelning, stafett = Turtildeling, stafet +Sträcktyp = Stræktype +Stämpelkod = stempelkode +Stämpelkod(er) = Stempelkode(r) +Stämpelkoder = Stempelkoder +Stämplar om = Stempler om +Stämpling = Stempling +Stämplingar = Stemplinger +Stämplingar saknas: X = Stemplinger mangler: X +Stämplingsautomat = Kontrolenhed +Stämplingsintervall (MM:SS) = Stemplingsinterval (MM:SS) +Stämplingstest = Stemplingstest +Stämplingstest [!] = Stemplingstest [!] +Stämplingstid = Stemplingstid +Stäng = Luk +Stäng tävlingen = Luk løbet +Större = Større +Störst = Meget stor +Största gruppen med samma inledning har X platser = Største gruppe med samme indledning har X pladser +Största intervall i klass = Største interval i klasse +SubCounter = Sekundær tæller +SubSubCounter = Tertiær tæller +Summera = Tæl sammen +Support time from control = Understøt tid fra post +Support time to control = Understøt tid til post +Symboler = Symboler +Synkronisera med Eventor = Synkroniser med Eventor +Säkerhetskopiera = Lav sikkerhedskopi +Sätt okända löpare utan registrering till = Sæt ukendte løbere uden registrering til +Sätt som oparad = Sæt som uparret +Sätter reptid (X) och omstartstid (Y) för = Sætter sidste skiftetid (X) og omstarttid (Y) for +Sök = Søg +Sök (X) = Søg (X) +Sök deltagare = Søg deltagere +Sök och starta automatiskt = Søg og start automatisk +Sök på namn, bricka eller startnummer = Søg efter et navn, en brik eller et startnummer +Söker efter SI-enheter = Søger efter SI-enheder +TCP: Port %d, Nolltid: %s = TCP: Port %d, Nultid: %s +TRASIG( = DEFEKT( +Ta bort = Fjern +Ta bort / slå ihop = Fjern / slå sammen +Ta bort eventuella avanmälda deltagare = Fjern evt. afmeldte deltagere +Ta bort listposten = Fjern listeposten +Ta bort markerad = Fjern valgte +Ta bort stämpling = Fjern stempling +Ta bort valda rader från tabellen (X) = Fjern valgte rækker fra tabellen (X) +Tabell = Tabel +Tabellverktyg = Tabelværktøj +Tabelläge = Tabelindstilling +Tar bort X = Fjerner X +Team = Hold +Team Rogaining = Hold pointløb +TeamBib = Holdets startnummer +TeamClub = Holdets klub +TeamFee = Holdafgift +TeamGlobal = Hold (klasser sammen) +TeamLegTimeAfter = Holdets tid efter på tur +TeamLegTimeStatus = Holdets tid / status på tur +TeamName = Holdets navn +TeamPlace = Holdets placering +TeamPlaceDiff = Ændring af holdets placering (denne etape) +TeamPointAdjustment = Holdets pointjustering +TeamRogainingOvertime = Holdets tidsoverskridelse (pointløb) +TeamRogainingPoint = Holdets pointløbspoints +TeamRogainingPointTotal = Holdets samlede points +TeamRogainingReduction = Holdets pointfradrag +TeamRunner = Navn på holdmedlem +TeamRunnerCard = Briknumre for holdmedlem +TeamStart = Holdets starttid +TeamStartNo = Holdets startnummer +TeamStatus = Holdets status +TeamTime = Holdets tid +TeamTimeAdjustment = Holdets tidsjustering +TeamTimeAfter = Holdets tid efter +TeamTimeStatus = Holdets tid / status +TeamTotalPlace = Holdets sammenlagte placering (samtlige etaper) +TeamTotalTime = Holdets samlede tid (samtlige etaper) +TeamTotalTimeAfter = Holdet efter førende (samtlige etaper) +TeamTotalTimeDiff = Ændring i holdets tid efter førende (denne etape) +TeamTotalTimeStatus = Holdets samlede tid eller status (samtlige etaper) +Teams and forking = Hold og gaflinger +Telefon = Telefon +Test = Test +Test Result Module = Test resultatmodul +Test av stämplingsinläsningar = Test af stemplingsindlæsninger +Testa rösten = Afprøv stemme +Text = Tekst +Text: X = Tekst: X +Texten ska innehålla tecknet X, som byts ut mot tävlingsspecifik data = Teksten skal indeholde tegnet X der erstattes med løbsspecifikke data +Textfiler = Tekstfiler +Textjustering = Tekstjustering +Textstorlek = Tekst størrelse +The forking is fair = Gaflingen er retfærdig +The forking is not fair = Gaflingen er uretfærdig +Tid = Tid +Tid efter: X = Tid efter: X +Tid efter: X; har tagit in Y = Tid efter: X; har hentet Y +Tid efter: X; har tappat Y = Tid efter: X; har tabt Y +Tid in = Tid ind +Tid: X, nuvarande placering Y/Z = Tid: X, nuværende placering Y/Z +Tidpunkt = Tidspunkt +Tidsavdrag: X poäng = Tidsfradrag: X points +Tidsförluster (kontroll-tid) = Tidstab (post/tid) +Tidsgräns = Tidsgrænse +Tidsinmatning = Tidsindtastning +Tidsintervall (MM:SS) = Tidsinterval (MM:SS) +Tidsintervall (sekunder) = Tidsinterval (sekunder) +Tidsjustering = Tidsjustering +Tidslinje – X = Tidslinje – X +Tidsskalning = Tidsskalering +Tidstillägg = Tidstillæg +Tidszon = Tidszone +Till exempel X = For eksempel X +Till huvudsidan = Til hovedside +Till kontroll = Til post +Tilldela = Tildel +Tilldela avgifter = Tildel afgifter +Tilldela endast avgift till deltagare utan avgift = Tildel kun afgift til deltagere uden afgift +Tilldela hyrbrickor = Tildel lejebrikker +Tilldela nummerlappar = Tildel brystnumre +Tilldela nya fakturanummer till alla klubbar? = Tildel nye fakturanumre til alle klubber? +Tilldela starttider = Tildel starttider +Tilldelad = Tildelt +Tilldelning av hyrbrickor = Tildel lejebrikker +Tillgängliga automater = Tilgængelige autofunktioner +Tillgängliga filer installerades. Starta om MeOS. = Opsætning er installeret. Genstart MeOS. +Tillgängliga listor = Tilgængelige lister +Tillsatte vakans = Besatte vakant +Tillsätt = Tilføj +Tillsätt tillfälliga anonyma lagmedlemmar = Tilføj annyme holddeltager +Tillsätt vakans = Besæt vakant +Tillsätt ytterligare vakans = Tilføj yderligere vakante +Tillämpa parstart = Anvend parstart +Tillåt decimaler = Tillad decimaler +Tillåt direktanmälan = Tillad tilmelding på stævnepladsen +Tillåt löpare inom en parallell grupp att springa gruppens banor i godtycklig ordning = Tillad løbere i en parallel gruppe at løbe gruppens baner i en vilkårlig rækkefølge +Tillåt ny klass, behåll resultat från annan klass = Tillad ny klasse, behold resultatet fra tidligere klasse +Tillåt ny klass, inget totalresultat = Tillad ny klasse, uden totalresultat +Tillåt samma bana inom basintervall = Tillad samme bane indenfor basisinterval +Tillåt valutauttryck med decimaler = Tillad valutaangivelse med decimaler +Time after leg winner = Tid efter strækvinder +Time as computed by your time method = Tiden er udregnet efter din startmetode +Time calculation for runner = Tidsberegning for løber +Time calculation for team = Tidsberegning for hold +Time: X = Tid: X +TimingFrom = Navn på startpunkt +TimingTo = Navn på målpunkt +Topplista, N bästa = Topliste, N bedste +Total = Total +Total tävlingsavgift = Total løbsafgift +TotalCounter = Primær tæller +Totalresultat = Totalresultat +Totalresultat - X = Totalresultat - X +Totalt = Total +Totalt antal etapper = Totalt antal etapper +Totalt faktureras = Totalt faktureres +Totalt kontant = Totalt kontant +Totaltid = Totaltid +Track runners in forest = Følg løbere i skoven +Trasig = Defekt +Träning = Træning +Tvåmannastafett = Tomandsstafet +Typ = Type +Typ av delning = Type af opdeling +Typ av export = Type af eksport +Typ av lista = Type af liste +Typsnitt = Skrifttype +Tävling = Løb +Tävling från Eventor = Løb fra Eventor +Tävling med lag = Løb med hold +Tävlingen innehåller inga resultat = Løbet indeholder ingen resultater +Tävlingen måste avgöras mellan X och Y = Løbet afvikles mellem X og Y. Stemplinger udenfor denne periode registreres ikke. +Tävlingen måste ha ett namn = Løbet skal have et navn +Tävlingens ID-nummer = Konkurrencens ID nummer +Tävlingens namn = Løbsnavn +Tävlingens namn: X = Løbets navn: X +Tävlingsdata har sparats = Løbsdata er gemt +Tävlingsinställningar = Løbsopsætninger +Tävlingsinställningar (IOF, xml) = Løbsindstillinger (IOF, XML) +Tävlingsnamn = Løbsnavn +Tävlingsrapport = Løbsrapport +Tävlingsregler = Løbsreglement +Tävlingsstatistik = Løbsstatistik +Töm = Clear +Töm databasen = Ryd database +URL = URL +URL måste anges = URL mangler +Ultra Long = Ultralang +Underfilter = Underfilter +Underlag för tävlingsavgift = Grundlag for løbsafgift +Underlag saknas för bomanalys = Intet grundlag for analyse af tidstab +Underlista = Underliste +Underrubrik = Underoverskrift +Undre datumgräns = Nedre datogrænse +Undre gräns (år) = Nedre grænse (år) +Undre ålder = Laveste alder +Unfair control legs = Uretfærdige stræk +Ungdom = Ungdom +Ungdomsavgift = Ungdomsafgift +Ungdomsklasser = Ungdomsklasser +Unknown symbol X = Ukendt symbol X +Unroll split times for loop courses = Udjævn splittider for loops +Uppdatera = Opdater +Uppdatera alla klubbar = Opdater alle klubber +Uppdatera alla värden i tabellen = Opdater alle værdier i tabellen +Uppdatera alla värden i tabellen (X) = Opdater alle værdier i tabellen (X) +Uppdatera från Eventor = Opdater fra Eventor +Uppdatera fördelning = Opdater fordeling +Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan = Opdater fordelingen af starttider med hensyn til manuelle ændringer ovenfor +Uppdatera klubbar && löpare = Opdater klubber && løbere +Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret = Opdater oplysninger om klubber og løbere med data fra løberdatabasen +Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret = Opdater oplysninger om klubber med data fra løberdatabasen +Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret = Opdater oplysninger om klub med data fra løberdatabasen +Uppdatera löpardatabasen = Opdater løberdatabasen +Urval = Sorter efter +Urval %c%s = Udvælg %c%s +Use initials in names = Brug initialer i navne +User input number = Bruger defineret input parameter +Utan inställningar = Uden indstillinger +Utan tidtagning = Uden tidtagning +Utbyt tävlingsdata med Eventor = Udveksl løbsdata med Eventor +Utför lottning = Foretag lodtrækning +Utfört = Færdig +Utg. = Udgået +Utgått = Udgået +Utskrift = Udskrift +Utskrift / export = Udskrift / Eksport +Utskriftsintervall (MM:SS) = Udskriftsinterval (MM:SS) +Utökat protokoll = Udvidet protokol +VALFRI( = VALGFRI( +Vacancies and entry cancellations = Vakante og sletning af tilmeldinger +Vak. ranking = Vak. rangliste +Vakanser = Vakante +Vakanser / klassbyte = Vakante / skift klasse +Vakanser och efteranmälda = Vakante og eftertilmeldte +Vakanser stöds ej i stafett = Vakante understøttes ikke i stafet +Vakant = Vakant +Val av export = Valg af eksport +Valbar = Valgbar +Vald bricka = Valgt brik +Valfri = Valgfri +Valuta = Valuta +Valutakod = Valutakode +Valutasymbol = Valutasymbol +Valutasymbol före = Valutasymbol før beløb +Variabler = Variable +Varning: Banan 'X' finns inte = Advarsel: Banen 'X' findes ikke +Varning: Banan 'X' förekommer flera gånger = Advarsel: Banen 'X' forekommer flere gange +Varning: Deltagaren 'X' finns inte = Advarsel: Deltageren 'X' findes ikke +Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) = Advarsel: Ingen arrangør/afsender af fakturaen angivet (Se løbsindstillinger) +Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Advarsel: Intet kontonummer angivet (Se løbsindstillinger) +Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) = Advarsel: Ingen sidste betalingsdato angivet (Se løbsindstillinger) +Varning: Laget 'X' finns inte = Advarsel: Holdet 'X' findes ikke +Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Advarsel: Deltager uden navn forekommer. MeOS kræver et navn og har tildelt navnet 'N.N.' +Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Advarsel: Et hold uden navn forekommer. MeOS kræver et navn og har tildelt navnet 'N.N.' +Varning: ändringar i X blev överskrivna = Advarsel: ændringerne i X blev overskrevet +Varvningskontroll = Sløjfepost +Verkställ = Anvend +Verktyg = Værktøjer +Version X = Version X +Vi stöder MeOS = Vi støtter MeOS +Viktiga händelser = Vigtige begivenheder +Vill du använda den nya brickan till alla etapper? = Ønsker du at bruge den nye brik på alle etapper? +Vill du att X går in i laget? = Ønsker du at X er en del af holdet? +Vill du att X och Y byter sträcka? = Ønsker du at X og Y skifter ture? +Vill du att X tar sträckan istället för Y? = Ønsker du at X løber turen i stedet for Y? +Vill du dumpa aktuellt tävling och skapa en testtävling? = Ønsker du at glemme den nuværende løb og danne en testløb? +Vill du flytta löpare från X till Y och ta bort Z? = Vil du flytte løbere fra X to Y og fjerne Z? +Vill du klistra in X nya rader i tabellen? = Vil du sætte X nye rækker ind i tabellen? +Vill du lägga till banan 'X' (Y)? = Vil du tilføje banen 'X' (Y)? +Vill du lägga till deltagaren 'X'? = Vil du tilføje deltageren 'X'? +Vill du lägga till klassen 'X'? = Vil du tilføje klassen 'X'? +Vill du lägga till laget 'X'? = Vil du tilføje holdet 'X'? +Vill du nollställa alla manuellt tilldelade banor? = Ønsker du at nulstille alle manuelt tildelte baner? +Vill du radera X rader från tabellen? = Vil du slette X rækker fra tabellen? +Vill du radera alla vakanser från tävlingen? = Vil du fjerne alle vakante fra løbet? +Vill du skapa en ny klass? = Vil du oprette en ny klasse? +Vill du spara ändringar? = Vil du gemme ændringer? +Vill du sätta resultatet från tidigare etapper till ? = Vil du sætte resultatet fra tidligere etaper til ? +Vill du ta bort 'X'? = Vil du fjerne 'X'? +Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa = Vil du fjerne alle klubber fra løbet. Alle deltager bliver så uden klub. +Vill du uppdatera alla nummerlappar? = Ønsker du at opdatere alle brystnumre? +Vill du verkligen radera alla starttider i X? = Vil du virkelig slette alle starttider i X? +Vill du verkligen radera starttider i X klasser? = Vil du virkelig slette starttider i X klasser? +Vill du verkligen radera tävlingen? = Vil du virkelig slette løbet? +Vill du verkligen stänga MeOS? = Vil du virkelig lukke MeOS? +Vill du verkligen ta bort laget? = Vil du virkelig slette holdet +Vill du verkligen ta bort löparen? = Vil du virkelig slette løberen? +Visa = Vis +Visa alla = Vis alle +Visa avancerade funktioner = Vis avancerede funktioner +Visa en tabell över alla stämplingar = Vis en tabel over alle stemplinger +Visa klubbdatabasen = Vis klubdatabasen +Visa listan i fullskärm = Vis listen i fuldskærm +Visa löpardatabasen = Vis løberdatabasen +Visa mellantider = Vis mellemtider +Visa och hantera löpardatabasen = Vis og håndter løberdatabasen +Visa senast inlästa deltagare = Vis senest indlæste deltager +Visa startlistan = Vis startliste +Visa tillgängliga säkerhetskopior = Vis tilgængelige sikkerhedskopier +Visa valda deltagare = Vis valgte deltagere +Visar de X bästa = Vis de X bedste +Visualisera startfältet = Visualiser startfeltet +Vuxen = Voksen +Vuxenklasser = Voksenklasser +Vuxna = Voksne +Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad = Vælge Gem for at gemme brikker. Interaktiv indlæsning er IKKE aktiveret +Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad = Vælg Gem for at gemme brikker. Interaktiv indlæsning er aktiveret +Välj X = Vælg X +Välj alla = Vælg alle +Välj alla klasser = Vælg alle klasser +Välj allt = Vælg alle +Välj automatiskt = Vælg automatisk +Välj den etapp som föregår denna tävling = Vælg den etape der går forud for dette løb +Välj den etapp som kommer efter denna tävling = Vælg den etape som følger efter dette løb +Välj en vakant plats nedan = Vælg en vakant plads nedenfor +Välj från lista = Vælg fra liste +Välj ingen = Vælg ingen +Välj inget = Vælg intet +Välj klass = Vælg klasse +Välj klass och starttid nedan = Vælg klasse og starttid nedenfor +Välj klasser = Vælg klasser +Välj klasser där alla löpare saknar starttid = Vælg klasser hvor alle løbere mangler starttid +Välj klasser där någon löpare saknar starttid = Vælg klasser hvor nogle løbere mangler starttid +Välj klasser med nya anmälningar = Vælg klasser hvor nye tilmeldinger er tilladt +Välj kolumner = Vælg kolonner +Välj kolumner att visa = Vælg kolonner der skal vises +Välj kolumner för tabellen X = Vælg kolonner til tabellen X +Välj lista = Vælg liste +Välj lopp = Vælg løb +Välj löpare = Vælg løber +Välj löpare att prioritera bevakning för = Vælg løbere hvor overvågning prioriteres +Välj löpare för sträcka X = Vælg løbere til tur X +Välj skrivare = Vælg printer +Välj tävling = Vælg løb +Välj vilka funktioner du vill använda = Vælg hvilke funktioner du vil bruge +Välj vilka klasser och kontroller du vill bevaka = Vælg hvilke klasser og poster du vil overvåge +Välj vilka klasser och kontroller som bevakas = Vælg hvilke klasser og poster der overvåges +Välj vilka kolumner du vill visa = Vælg hvilke kolonner du vil vise +Välj vy = Vælg visning +Välkommen till MeOS = Velkommen til MeOS +Vänligen betala senast = Vær venlig at betale senest +Vänligen återlämna hyrbrickan = Vær venlig at aflevere din lejebrik +Vänster = Venstre +Växel = Skifte +Växling = Veksling +Webb = Web +Webbdokument = Webdokument +Webbdokument (html) = Webdokument (html) +Webben (html) = Webben (html) +X (Saknar e-post) = X (Mangler email) +X (Y deltagare, grupp Z, W) = X (Y deltagere, gruppe Z, W) +X (press Ctrl+Space to confirm) = X (tast + for at bekræfte) +X har redan bricknummer Y. Vill du ändra det? = X har allerede brik nr. Y. Vil du ændre det? +X har redan ett resultat. Vi du fortsätta? = X har allerede et resultat. Vil du fortsætte? +X har startat = X er startet +X kontroller = X poster +X meter = X meter +X poäng fattas = X points mangler +X rader kunde inte raderas = X rækker kunne ikke slettes +X senaste = X seneste +X är inget giltigt index = X er ikke et gyldigt indeks +X är inget giltigt sträcknummer = X er ikke et gyldigt turnummer +X: Y. Tryck för att spara = X: Y. Tryk for at gemme +X:e = X'e +Zooma in (Ctrl + '+') = Zoom ind (Ctrl + '+') +Zooma ut (Ctrl + '-') = Zoom ud (Ctrl + '-') +[Bevaka] = [Overvåg] +[Bort] = [Fjern] +[Flytta ner] = [Flyt ned] +[Klassens bana] = [Klassens bane] +[Uppdaterad anmälan] = [Opdateret tilmelding] +[VARNING] ingen/okänd = [ADVARSEL] ingen/ukendt +[Återställ] = [Reset] +andra = anden +ask:addpunches = Ingen brik er aflæst for denne løber. Vil du tilføje stemplinger manuelt? +ask:changedclassfee = Løbsafgiften er ændret i visse klasser. Vil du tilføje nye gebyrer til eksistende løbere i disse klasser?\n\nAdvarsel: Manuelt tildelte gebyrer bliver overskrevet. +ask:changedcmpfee = Løbsafgiften er ændret. Vil du tilføje nye gebyrer til eksisterende løbere og klasser?\n\nAdvarsel: Manuelt tildelte gebyrer bliver overskrevet. +ask:cleardb = Vil du slette løber og klubdatabase? +ask:firstasstart = Banen har allerede deltagere med resultat. Hvis du anvender første post til start vil eksisterende starttider blive overskrevet.\n\nVil du fortsætte? +ask:kiosk = Hvis du starter resultatformidling havner MeOS i en tilstand hvor det kun er muligt at vise resultatrapporter. Ingen andre funktioner er tilgængelige før programmet genstartes. Hvis du har en aktiveret SI-enhed koblet til computeren viser MeOS automatisk resultater for sidste aflæste brik.\n\nDu bør overveje at beskytte databasen med et password hvis stiller em PC med resultatformidling frit tilgængeligt.\n\nVil du starte resultatformidling? +ask:missingcourse = Nogle klasser (X) har ingen bane.\n\nMeOS bruger banerne til lodtrækning for at undgå at løbere med samme førsteposter starter samtidigt.\n\nVil du trække lod alligevel? +ask:overwrite_server = Løbet er allerede på serveren. Vil du overskrive løbet på serveren? +ask:overwriteconfirm = Du har valgt at overskrive løbet. Kontroller at der ikke er andre tilsluttet.\n\nVil du fortsætte? +ask:overwriteresult = X har allerede et resultat. Skal det overskrives? +ask:repair = Reparer kun databasen hvis du har problemer med den.\n\nVigtigt:\n- Kontroller at der ikke er andre tilsluttet databasen.\n- Hvis serveren crasher eller lukkes mens den repareres, skal du som det første genstarte den og omgående forsøge en ny reparation. Hvis du gør noget andet inden går alle data tabt.\n\nVil du fortsætte? +ask:updatelegs = Rettelsen kan kræve at længden af de enkelte stræk opdateres.\n\ Ønsker du at rette det nu? +backup = backup +c/o = c/o +check (X) = check (X) +classcourseresult = Klasse of baneresultater +documentation = meos_doc_eng.html +edit_in_forest = Håndter\nLøbere i skoven +edit_inforest = Håndter løbere\ni skoven +ej aktiv = ikke aktiv +elfte = elvte +elva = elleve +encoding = ANSI +error:invalidmethod = Den valgte metode gav ikke nogen fordeling. Kildedata utilstrækkelige. +ett Mycket Enkelt OrienteringsSystem = et Meget Enklere OrienteringsSystem +eventor:help = Hvis du bruger MeOS i Sverige, anbefaler vi at du bruger MeOs's Eventor opkobling +eventor:question = X\n\nVil du bruge Eventor opkobling? +femma = fem +femte = femte +fjärde = fjerde +fritt att använda och du är välkommen att distribuera det under vissa villkor = gratis at bruge og du er velkommen til at distribuere det på visse betingelser +fyra = fire +går i mål på X plats med tiden Y = går i mål på X plads med tiden Y +går i mål på X plats, efter Y, på tiden Z = går i mål på X plads, efter Y, med tiden Z +går upp i delad ledning med tiden X = tager en delt førsteplads med tiden X +går upp i delad ledning vid X med tiden Y = deler føringen ved X med tiden Y +handskakning = handshaking +har startat = er startet +help:10000 = En autofunktion i MeOS er et lille program som automatisk gør noget med jævne mellemrum eller når løbsdata ændres. +help:12138 = Vælg den klasse der skal slås sammen med den valgte klasse. Hvis der er trukket lod i klassen skal du trække lod igen, idet løberne ellers beholder deres starttid. +help:12290 = Det valgte løb er oprettet i en anden version af MeOS og kan ikke åbnes fra serveren. Du kan imidlertid importere løbet fra en fil. +help:12352 = Denne handling sletter den klub du har valgt (%s, id=%d) og flytter alle løbere fra denne klub til den nye klub du vælger nedenfor. Dette kan ikke fortrydes. +help:12662 = Tilføj poster ved at tilføje en sekvens med postnumre. Det er ikke nødvendigt at angive målposten. Eksempel: 31, 50, 36, 50, 37, 100. +help:14070 = TCP-porten bruges til at importere stemplinger over netværk med TCP fra andre systemer. Angiv hvilken port der skal bruges. Protokollens nultid er 00:00:00. +help:14343 = Her vises en liste med aflæste løberbrikker. For at ændre en løbers brik, dobbeltklik på den brik eller løber du vil flytte. +help:146122 = Du kan udvide MeOS's kendskab til løbere, klubber og klasser ved at gennemsøge databaser i MeOS-format eller IOF XML-format.\n\nVil du fortsætte? +help:14692 = Indtast post (SI-nummer), løber (startnummer eller briknummer) og urtid (HH:MM:SS). Du kan efterlade tiden blank, hvorved computerens tid anvendes. Tryk på for at gemme. +help:15491 = Du kan eksportere din lokale opsætning samt klub- og løberdatabaser til en mappe du angiver. Derefter kan du importere denne opsætning på anden computer. +help:21576 = Tip: Hvis du gør noget forkert, klik på løberens navn for at ændre tilmelding. På faneblad deltagere kan du fjerne tilmeldinger. De klasser du kan tilmelde i er dem, hvor der er krydset af i tilmelding på stævnepladsen (se faneblad klasser). +help:25041 = Her definerer du de baner du har brug for. En bane knyttes til en eller flere klasser (eller løbere). Det er også muligt at importere baner direkte fra OCAD, Condes eller andre banelægningsprogrammer. Hvis du angiver antallet af tilgængelige kort, holder MeOS styr på hvor mange kort der er til rådighed for tilmelding på stævnepladsen. +help:26963 = Valgfrie baner anvendes for at skabe valgmuligheder for hvert delstræk. Banen knyttes til løberen ved målgang gennem matchning. Definer banerne ved at tilføje dem under flere baner/stafet. Et [S] efter klassen betyder att alle deltagere er tildelt en starttid. +help:29191 = Du kan hente opsætning af MeOS samt klub- och løberdatabaser fra den mappe du angiver. De lokale opsætning bliver herved overskrevet. Efter installationen skal MeOS måske genstartes.\n\nKnappen fører til en side, hvorfra du kan kan eksportere din nuværende lokale opsætning. +help:29758 = Her håndterer du klubber, genererer og udskriver fakturaer. Du kan efterfølgende tildele løbsafgifter, baseret på klassetype og tilmeldingsdato. Dobbeltoprettede (fejlstavede) klubber kan slås sammen med den rigtige klub og fjernes. Du kan også opdatere klubberne med data fra evt. eksternt register. +help:30750 = Her kan du oprette forskellige slags lister og rapporter. Du kan vise dem på skærmen, udskrive dem eller gemme dem til webben. Når løbsdata ændres opdateres listen automatisk. Automatiske udskrifter finder du under faneblad autofunktioner. Eksport af løbsdata f.eks. stræktider, sker under faneblad løb. +help:31661 = En efterstart defineres af en sidste skiftetidtid og en efterstarttid. Ved sidste skiftetid lukkes skiftezonen, og ingen startende slippes ud i skoven. Ved efterstartstiden går efterstarten. Det er muligt at angive forskellig efterstartstartstid på forskellige ture, men med hjælp af denne funktion sætter du hurtigt efterstartstid for hele klasser. +help:33940 = Importer tilmeldingsdata i fritekstformat. Angiv Navn, Klub, Klasse og SI (og eventuel starttid) gerne adskilte med et komma; en person (et hold) pr linje. Det er også muligt at tilmelde flere personer i samme klub/klasse ved at (delvis) udelade felterne klub/klasse. Det er også muligt at importere tilmeldinger formateret på andre måder.\n\nKlasser oprettes automatisk, men hvis du importerer hold til stafet eller patrulje skal du selv oprette klasserne inden du importerer tilmeldingerne. Ellers kan der opstå fejl i tildeling af tur. +help:41072 = Marker i listen af stemplinger for at slette eller ændre tiden. Manglende stemplinger kan tilføjes fra baneskabelon. Mangler måltid får løberen status udgået. Mangler stempling får løberen status fejlstempling. Det er ikke muligt at sætte en status på en løber som ikke passer med løberens stemplingsdata. Hvis der er en målstempling skal tiden for denne ændres for at ændre måltiden; det samme gælder for startstempling. +help:41641 = Udfyld første starttid og startinterval. Lodtrækning indebærer tilfældig lodtrækning, SOFT-lodtrækning en lodtrækning i overensstemmelse med SOFT:s klubfordelingsregler. Klyngestart indebærer at hele klassen starter i småklynger med det interval du angiver ("forlænget" fællesstart). \n\nAngiv interval 0 for samlet start.\n\nStartnumre: Angiv første nummer eller efterlad blankt for ingen startnumre. I feltet ture (Tur) angiver du hvilken tur der skal lodtrækkes (hvis klassen har flere ture). +help:425188 = Du kan automatisk håndtere ved at indlæse fra SI-enhed(er) (Clear, Check eller Start post) i SI-Config (Read out Station), gemme indlæsningen som en semikolonsepareret tekstfil og importere denne i MeOS. De løbere som forekommer i denne import får en registrering. Derefter kan du sætte på løbere uden registrering. Indlæser du senere flere løbere kan du ændre de løbere som tidligere har fået men nu har fået registrering.\n\nDu kan også løbende få indlæst status af løberne ved at lade dine Check enheder i starten være radioposter. Det kommer så løbende ind i programmet. Husk postnummer for Check skal være '3'. +help:471101 = Aktivér SI-enheden ved at vælge den rette COM-port, eller ved at søge efter installerede SI-enheder. Info giver dig information om den valgte enhed/port. For at aflæse brikker skal enheden være programmeret uden autosend (for radioposter bruges dog autosend). Udvidet protokol anbefales, da det giver en mere stabil forbindelse. Enheden programmeres med SPORTidents program SI-Config.\n\nHvis du bruger SPORTident SRR radioposter gælder der følgende reggler for postnumre:\nNormale poster skal have et nummer fra 31 til 255.\nStartpost(er) skal have postnummer=1.\nPostenhed med Check skal have postnummer =3\nPoster med numrene 2 samt 4-30 håndteres som Mål.\n\nInteraktiv aflæsning anvendes hvis du vil håndtere eventuelle problemer med forkerte briknumre ved aflæsningen; afmarker hvis det i stedet skal foregå f.eks. ved 'Klagemuren' eller på på stævnekontoret.\n\nLøberdatabasen bruges hvis du automatisk vil tilføje indkomne løbere ved hjælp af løberdatabasen. Løberens stemplinger bruges til at vælge den rigtige klasse. +help:50431 = Du er nu koblet op mod en server. For at åbne et løb fra serveren, marker det i listen og vælg åbn. For at tilføje et løb til serveren, åbn først løbet lokalt, og brug derefter knappen upload løb. Når du har åbnet et løb på på serveren ser du hvilke andre MeOS-klienter som er tilsluttet til serveren.\n\nHvis der efter løbet står (på server) er løbet åbnet på en server og kan deles af andre MeOS-klienter. Står der (lokalt) kan man kun tilgå løbet fra den aktuelle computer. +help:52726 = Tilslut til en server nedenfor. \n\nInstallation:\nHent og installer MySQL 5 (Community Edition) fra www.mysql.com, standardindstillinger anbefales. MySQL behøver kun at være kun installeret på den computer der skal være server. Start derefter et MySQL Administrationsprogram som phpMyAdmin og opret en brugerkonto for MeOS. Hvis du bruger MySQL Command Line Client og vil oprette en brugerkonto for MeOS er kommandoerne:\n\n> CREATE USER meos;\n> GRANT ALL ON *.* TO meos;\n\nDu har nu oprettet en bruger meos (med blankt password). Angiv serverens navn nedenfor (hvis du ikke kan få forbindelse så kontroller evt. firewall).\n\nEt alternativ er at bruge MySQL's indbyggede rodkonto, det vil sige, brugernavn 'root' og det password du angav ved installationen af MySQL. +help:5422 = Fandt ingen SI-enhed(er). Er de(n) tilsluttet og startet? +help:59395 = I denne formular kan du hurtigt lave de grundlæggende indstillinger for alle klasser i en arbejdsgang. \n\nStart angiver navnet på starten, som det skrives på startlisten. \n\nBlok er et tal mellem 0 og 100 som angiver en mere finkornet opdeling af de startende. Klasser som tillhører same blok udskrives på samme minutstartliste. \n\nIndeks angiver en sorteringsnøgle. Alle lister sorterer klasserne stigende efter denne nøgle. \n\nBane kan angives for de klasser som kun har én bane; har klassen flere baner eller gaflinger skal det indstilles klassevist. \n\nTilmelding på stævnepladsen angiver om klassen tillader tilmelding på stævnepladsen. +help:59395_more = Startafgifter, der vises hvis du har aktiveret økonomifunktioner, bruges for nye tilmeldinger. Hvis du ændrer afgifterne vil du blive spurgt om du ønsker at ændre afgifterne for eksistrende tilmeldinger. \n\nFor brystnumre er mulighederne ingen, løbende eller manuelt. Der kan også indtastes det første nummer i klassen f.eks. A100 eller 50. Løbende betyder at det sidste nummer i den forudgående klasse bruges som grundlag i denne klasse. Reserverede brystnumre betyder at der kommer det specificerede spring i numrene mellem de forskellige klasser. \n\nMeOS opdaterer brystnumrene når der foretages lodtrækning eller når indstilningerne for løbet ændres. Manuelt betyder at MeOS aldrig vil opdatere brystnumrene af sig selv.\n\nFor klasser med hold er det opsætningen Hold deltager der styrer relationen mellem hold og brystnummer. Her er mulighederne stigende (100, 101, 102), tur baseret (100-1, 100-2, etc.) eller uafhængigt. +help:7618 = Antallet af løbere på holdet indstilles på siden klasser. +help:7620 = Interval (sekunder). Efterlad blank for at opdatere når løbsdata ændres +help:89064 = Til hver post angiver man et eller flere kodecifre (SI-kode). Under banelægningen refererer man til postens ID-nummer. Man behøver normalt ikke selv at tilføje poster, idet MeOS automatisk tilføjer de poster der anvendes. \n\nFlere kodeciffre er brugbare for at erstatte poster der er defekte eller for at skabe enkle gaflinger. For en almindelig post kræves at løberen har besøgt en af de angivne poster. Sættes status til multipel skal løberen besøge listede poster i valgfri rækkefølge.\n\nHvis man sætter postens status til 'Defekt', anvendes den ikke i stemplingskontrollen. \n\nEn post kan tildeles et navn, f.eks. 'Skift'. Det er muligt at udskrive resultatlister som indeholder mellemtider for navngivne poster.\n\nTidsjustering bruges hvis en uret i en postenhed går forkert:formatet er +/-MM:SS eller +/-HH:MM:SS.\n\nKorteste stræktid kan anvendes eksempelvis ved vejpassage. Ingen løber kan få en bedre stræktid ind mod posten end den angivne tid. Overskrider løberen den angivne tid bruges løberens faktiske tid. +help:9373 = Angiv et eller flere kodecifrer (SI-kode) som bruges på denne post, f.eks. 31, 250. Feltet point bruges til pointløbsposter. +help:9615 = Fik intet svar. Skal porten åbnes i passiv indstilling; skal MeOS lytte efter indkommende stemplinger? +help:DirectResult = - Hvis der ikke er nogen bane sættes status til OK ved målstempling.\n\n- Hvis der er en bane med radioposter over det hele er det ikke nødvendigt at aflæse brikken. +help:analyzecard = Denne funktion tillader at udskrive data fra brikken, uden at oprette et løb - som på en stræktidsprinter. Vælg "Udskriv Stræktider" for at vælge og konfigurere printeren.\n\nBrikkens data gemmes i hukommelsen(men ikke i løbet). Du kan rette navn og klub ved at klikke på navn (eller 'Ukendt'). Du kan også gemme brikdata i en fil "Gem" eller oprette et løb udfra brikkens/brikkernes data. Bemærk at der ikke må være noget løb åbent for at funktionen bliver tilgængelig. +help:anonymous_team = Opret og tildel (midlertidige) deltagere for alle hold hvor der kan tildeles SI-brik, bane o.s.v. +help:assignfee = MeOS håndterer i de fleste tilfælde afgifter automatisk. Deltagarne tildeles en løbssafgift ud fra alder og tilmeldingsdato (grænser angiver du under løbsindstillingar). Hver klasse definerer hvilke afgifter der gælder. Standardværdien for forskellige klassetyper definerer du under løbsindstillinger, men du kan også foretage manuelle ændringer på siden klasser, under hurtigindstillinger.\n\nMed funktionerne her kan du tildele og manuelt filtrere forskellige aldre og tilmeldingsfrister, samt tildele forskellige afgifter. På siden deltagere kan du også manuelt justere de enkelte deltageres afgift. +help:assignforking = Denne funktion udregner et optimalt gaflingsmønster fra udvalgte baner. +help:baudrate = Overføringshastighed/Baudrate: brug 4800 eller 38400. +help:bibs = Startnumre kan håndteres automatisk eller manuelt. Startnumre for en klasse kan tildeles manuelt ved at specificere Manuelt og angive det første nummer i klassen.\n\nVed automatisk opdaterer MeOS alle startnumre i alle klasser på en gang. Selv om det er muligt at foretage instillingerne her, er det bedre at bruge Hurtiginstillinger for klasser da det giver et overblik over alle klasser.\n\nAutomatisk er lavet til at bruges sammen med ingen og løbende, så bruges sidste nummer i den foregående klasse som start for den næste klasse. Antallet reserverede brystnumre angiver springet i numre mellem klasser. \n\nFor holdklasser kan der specificeres hvordan løberens brystnummer forholder sig til holdets brystnummer. Det kan være samme, uafhængigt, stigende (Hold 1: 101, 102, 103, 104, Hold 2: 111, 112, 113, 114 etc) or tur (100-1, 100-2, 100-3 etc). +help:computer_voice = De briknumre der indsendes til systemet matches mod startnummer og filen , hvor N är startnummeret, afspilles. Filerne hentes fra nedennævnte mappe. Hvis løberens/holdets nationalitet er NAT, afspilles i første omgang filen . For svenske løbere afspilles f.eks. i første omgang filen +help:dbage = Løberdatabasen er ældre end 2 måneder. Vil du hente en opdateret database fra Eventor? +help:duplicate = Lav en lokal kopi af det aktuelle løb. +help:eventorkey = Indtast klubbens API-nøgle for Eventor, den er nødvendig for at kunne tilslutte til Eventor og hente tilmeldinger og løberregister. Nøglen får du af klubbens Eventor-administrator. +help:fullscreen = Du kan justere hastigheden med Ctrl+M (hurtigere) respektive Ctrl+N (langsommere) på tastaturet. For at forlade fuldskærm, tryk på Esc. +help:import_entry_data = Du kan importere løbere, klasser, klubber og tilmeldinger i et antal forskellige tekst- og XML-formater. Det er ikke nødvendigt at angive samtlige filer. F.eks. indeholder OE-CSV format for tilmeldinger såvel klasser som klubber. I det tilfælde behøver felterne for klasser og klubber ikke at indlæses separat\n\nHvis information om samme løber importeres flere gange, bliver løberens information opdateret de efterfølgende gange. Der dannes ikke flere kopier af løberen i databasen. Det gør at man kan importere eftertilmeldinger ved at importere en opdateret fil med samtlige tilmeldinger. +help:importcourse = Du kan importere baner og klasser fra (eksempelvis) OCAD's eller Condes i IOF XML format. +help:ocad13091 = Hvis du har adgang til banerne på fil (f.eks. fra OCAD eller Condes) kan du angive filens navn her. Ellers kan du lægge banerne ind senere. +help:onlineinput = Denne funktion bruges for at modtage data fra radioposter der er forbundet til Internettet, f.eks. en radiopost der er forbundet til en mobiltelefon. Det er også muligt at lave et simpelt web-skema hvori løberens brystnummer indtastes når de passerer. \n\nFunktionen understøtter også andre typer af data indtastning så som hold opstilling, direkte tilmelding og ændring af briknummer. Hvis du ønsker at udvikle din egen funktion kan yderligere dokumentation og eksempler findes på MeOS hjemmeside: www.melin.nu/meos.\n\nMapning gør det muligt at tilknytte en speciel posttype (Check, Start og Mål) til et specifikt postnummer, da dette overføres på anden vis. +help:onlineresult = Denne funktion bruges til at øjeblikkelig automatisk udgivelse af resultater og startlister på Internettet. Instillingerne du bruger skal passe til den tjeneste du vil udnytte. Tjenesteudbyderen kan give dig yderligere information.\n\n Hvis du ønsker at udvikle din egen funktion kan yderligere dokumentation og eksempler findes på MeOS hjemmeside: www.melin.nu/meos. +help:relaysetup = Anvend guiden nedenfor til at vælge mellem et antal foruddefinerede løbsformer. Når du trykker på anvend gemmes indstillingerne. Derefter er det muligt manuelt at tilpasse indtillinger for hver tur og vælge baner.\n\nNogle forklaringer:\n- Stafet bruges for stafet i forskellige former.\n- Tomandsstafet indebærer at to løbere udgør et hold og løber hveranden tur.\n- Ekstraløberstafet anvendes indimellem i ungdomsklasser og tillader flere løbere på mellemturene (først i mål skifter).\n- Patrulje kan løbes med to SI-brikker (begge løbere stempler) eller en SI-brik pr.patrulje.\n- Prolog + jagtstart indebærer at en løber først løber en prolog, derefter en jagtstart baseret på resultatet.\n- Valgfrie baner indebær gafling, hvor man ikke i forvejen behøver at bestemme, hvem som løber hvilken bane. ved målgang afgøres, hvilken bane løberen har løbet. +help:restore_backup = Vælg en sikkerhedskopi at gendanne ud fra, ved at klikke på det tidspunkt, hvor sikkerhedskopien blev oprettet. +help:runnerdatabase = Ved at importere løberregister og klubregister får du MeOS til automatisk at tilknytte briknummer med løbere ved brikaflæsning og du får hentet adresser og kontaktoplysninger for klubber.\n\nMeOS kan importere IOF (xml)-format fra f.eks. Eventor. +help:save = MeOS gemmer alle ændringer automatisk når det er nødvendigt. +help:seeding_info = Seeded lodtrækning betyder at tidligere resultater eller ranking er med til at styre lodtrækningen. I feltet seeding grupper kan der enten angives en værdi, eller en række værdier. Hvis der angives en værdi opdeles klassen i grupper af denne størrelse. En værdi på "1" betyder at der ikke foretages loktræning eller at ranking bruges direkte. Hvis der angives en række numre, f.eks. "15,1000" betyder det at de 15 bedste løbere kommer i en gruppe og at de efterfølgen (maksimalt 1000) løbere placeres i en ikke seeded gruppe. +help:simulate = Denne funktion tillader dig at simulere aflæsningen af SI-brikker. Der genereres tider og stemplinger for alle løbere. Radioposter kan også simuleres\n\nADVARSEL: Brug kunne denne funktion ved test. Hvis den bruges på et rigtigt løb bliver løbsdata ødelagt. +help:speaker_setup = Vælg hvilke klasser og poster du vil overvåge. +help:speakerprio = Sæt et kryds ved de løbere/hold der skal overvåges fra starten og så længe det går godt for løberen/holdet. Sæt to krydser for at overvåge også når det går dårligt. Intet kryds betyder overvågning kun hvis det går godt (ikke fra start). +help:splitexport = Vælg om du vil eksportere totalresultater eller individuelle resultater for hver tur. Hvis du vælger at eksportere alle ture bliver flere nummererede filer gemt. +help:startmethod = MeOS vælger automatisk startmetode. Uanset hvad du vælger kan du altid ændre startmetode eller foretage ny lodtrækning senere. +help:teamlineup = Her kan du importere holdsammensætning fra et struktureret tekstformat - f.eks. fra et regnearksprogram. Filen skal have følgende format:\n\nKlasse;Holdnavn;[Klub]\nLøber 1;[SI];[Klub];[Bane];[Løbers klasse]\nLøber 2;[SI];[Klub];[Bane];[Løbers klasse]\n...\nKlasse;Holdnavn;[Klub]\n...\n\nFelter markeret med [] kan udelades. Bemærk at de angivne klasser og baner skal findes, og antallet af ture i klassen skal svare til antallet af løbere. Tomme rækker kan bruges hvis der ingen løber er. Valget betyder at kun løbere der allerede er med i løbet kan flyttes til holdet; andre løbere kan ikke angives. +help:teamwork = Løberne skifter plads. Der kan foretages flere skift for at opnå den ønskede holdopstilling. +help:winsplits_auto = Denne autofunktion gemmer stræktider i en IOF-format fil med jævne mellemrum. Hvis du åbner filen med WinSplits, vil stræktiderne der blive opdateret med samme mellemrum +help:zero_time = Nultid bør sættes til før udløbere af poster sendes ud. +help_autodraw = Indtast første (ordinære) starttid, mindste startinterval (indenfor en klasse) og andel vakante. Du kan også vælge lodtrækningsmetode og om eftertilmeldte skal starte først eller sidst. Første starttid skal være efter løbets nultid.\n\nHvis du vælger automatisk lodtrækning, vil MeOS gennemgå samtlige klasser. Der trækkes lod i klasser der ikke er lodtrukne. MeOS lodtrækker hver start for sig og sørger for en jævn strøm af startende. MeOS sørger også for at klasser med samme bane ikke starter samtidigt og om muligt at løbere med samme førstepost ikke starter samtidigt. Desuden efterlades plads til senere at lodtrække eftertilmeldte på samme vilkår.\n\nI de klasser som allerede er lodtrukne bliver eftertilmeldte sat ind før eller efter de ordinært tilmeldte. De løbere som allerede er lodtrukne beholder altså deres starttid. Det er også muligt først at lodtrække visse klasser manuelt og derefter lade MeOS lodtrække resterende klasser automatisk.\n\nHvis du istedet vælger manuel lodtrækning kommer du til en side, med flere indstillingsmuligheder, hvor du skal vælge hvilke klasser der skal lodtrækkes. +help_draw = Lodtrækning udføres i to trin. Først angiver du hvilke klasser du vil lodtrække og foretager de grundlæggende indstillinger. Når du trykker på anvender MeOS indstillingerne til at fordele starttiderne mellem klasserne. MeOS sørger for at klasser med baner der ligner hinanden ikke starter samtidigt og tager hensyn til allerede lodtrukne klasser. Målet er et jævnt flow af startende.\n\nFordelingen præsenteres i en tabel, hvor du kan tilføje dine egne ændringer og eventuelt lade MeOS foretage en ny fordeling i fohold til dine ændringer. Når du er tilfreds med fordelingen lader du MeOS trække lod blandt de valgte klasser.\n\nDe grundlæggende indstillinger som skal foretages er første starttid og mindste startinterval. Indstillingen maks. samtidigt startende angiver hvormange løbere som må starte samtidigt. En større værdi giver en kortere startdybde.\n\nAndel vakante angiver om MeOS skal lodtrække vakante pladser ind i startfeltet. Angiv 0% for ingen vakante. Forventet antal eftertilmeldte bruges til at reservere plads i startfeltet for eftertilmeldte. Ingen vakante pladser indsættes, men der efterlades plads i startlisten med garanti for at ingen samtidigt startende skal have samme bane. +info:multieventnetwork = For at administrere flere etaper skal du arbejde lokalt. Gem en kopi af løbet, åbn den lokalt og overfør resultat til næste etape. Derefter uploader du næste etape til serveren for at afvikle den derfra. +info:readout_action = X: Brik Y aflæst.\nManuel behandling er nødvendig. +info:readout_queue = X: Brik Y aflæst.\nBrikken er sat i kø. +info:runnerdbonline = Da du er tilsluttet en server er det ikke muligt at redigere klub og løberdatabase manuelt. Foretag ændringer før løbet uploades til serveren. Det er muligt at erstatte den eksisterende database på serveren ved at importere en ny database (fra IOF XML). +info_shortening = Vælg en eksisterende bane der afkortes til den nuværende bane. Det er muligt med flere niveauer af afkortning. +inforestwarning = Der skulle ikke være flere løbere i skoven. De de data analysen er baseret på kan være forkerte, bør du som arrangør dog også checke dette på anden måde. +kartor = kort +klar = færdig +kontroll = post +kontroll X (Y) = post X (Y) +listinfo:inputresults = Vis resultater af tidligere dele. +listinfo:singleclub = Dan resultatliste for en enkelt klub.\n\nBrug klub ID som inputparameter +localhost = localhost +lopp = løb +min/km = min/km +mål = mål +målet = målet +målet (X) = målet (X) +newcmp:featuredesc = Vælg hvilke funktioner i MeOS du har brug for i dette løb. Du kan fjerne eller tilføje faciliteter nårsomhelst ved at vælge på siden Løb. +nia = ni +nionde = niende +olshooting:notimepunishment = Resultatliste Biatlon uden tidstillæg.\n\nAktiver MeOS-funktionerne Pointløb og Manuel pointreduktion og justering. Brug feltet Pointreduktion på faneblad Deltagere til at registrere forbiere i formatet LLSS hvor LL er forbiere liggende og SS forbiere stående. Eksempel: 0201 betyder 2 forbiere liggende og 1 forbier stående. +olshooting:timepunishment = Resultatliste Biatlon med tidstillæg.\n\nAktiver MeOS-funktionerne Pointløb og Manuel pointreduktion. Brug feltet Pointreduktion på faneblad Deltagere til at registrere forbiere i formatet PPPLLSS, hvor PPP er fejlindprikning i mm, LL forbiere liggende og SS forbiere stående. Eksempel 0030201 betyder 3 mm fejl, 2 liggende og 1 stående forbier. +open_error = Kan ikke åbne X.\n\nY. +open_error_locked = Dette løb er allerede åbnet i MeOS. \n\nDet er nødvendigt at bruge en database hvis mere end en instans af løbet skal bruges samtidigt. +radio X = radio X +saknas = mangler +se license.txt som levereras med programmet = see license.txt som følger med programmet +serverbackup = server backup +sexa = seks +sjua = syv +sjunde = syvende +sjätte = sjette +skicka stämplar = send stemplinger +sortering: X, antal rader: Y = sortering: X, antal rækker: Y +sortering: X, antal rækker: Y = sorteringsorden: X, antal rækker: Y +starten (X) = starten (X) +sträcka X = tur X +stämplade vid = stemplede ved +stämplar vid X som Y, på tiden Z = stempler ved X som Y, i tiden Z +tar ledningen med tiden X = overtager føringen med tiden X +tar ledningen vid X med tiden Y = tager føringen ved X med tiden Y +tia = ti +till = til +tionde = tiende +tolfte = tolvte +tolva = tolv +tooltip:analyze = Analyser data og forhåndsvis import. +tooltip:builddata = Udvid MeOS's kendskab til løbere, klubber og klasser ved at analysere løbsdata. +tooltip:import = Importer tilmeldinger fra fil. +tooltip:inforest = Liste over løbere i skoven og løbere som ikke er startet. +tooltip:paste = Indsæt fra udklipsholder. +tooltip:resultprint = Udskriv resultater til at hænge op +tooltip:voice = Computerstemme der læser forvarslinger op. +tooltip_explain_status = - = Ukendt status (Intet resultat endnu)\nOK = Godkendt løb\nEj start = Løber ikke startet\nFejlklip = Mangler stempling(klip)\nUdgået = Løber udgået (ingen måltid)\nDiskv. = Løber diskvalificeret\nMaks.tid = Løbstid over maksimal løbstid\nDelt. ej = Deltager ikke i løbet +trea = tre +tredje = tredje +tvåa = toer +vid kontroll X = ved post X +väntas till X om någon minut = ventes til X i løbet af nogle minutter +väntas till X om någon minut, och kan i så fall ta en Y plats = ventes til X indenfor et minut, og kan i så fald tage en Y plads. +väntas till X om någon minut, och kan i så fall ta ledningen = ventes til X indenfor et minut, og kan tage føringen. +växeln = skiftet +växlar på X plats med tiden Y = skifter på X plads med tiden Y +växlar på X plats, efter Y, på tiden Z = skifter på X plads, efter Y, med tiden Z +växlar på delad X plats med tiden Y = skifter på en delt X plads med tiden Y +warn:changedtimezero = Ændrer nultiden for et løb der er i gang, hvilket ikke kan anbefales.\n\nVil du fortsætte alligevel? +warn:notextended = INFO: Programmer enheden til at bruge "Extended Protocol" med brug af SI.Config programmet for at gøre aflæsning af brikkerne hurtigere. +warn:olddbversion = Databasen bruges af en nyere version af MeOS. Opgradering anbefales. +warn:opennewversion = Dette løb er dannet i MeOS X. Du risikerer at tabe data hvis du fortsætter.\n\nVil du fortsætte? +warn:updatelegs = Det kan være nødvendigt at opdatere længden af de enkelte baner. +warning:dbproblem = ADVARSEL. Problemer med databaseforbindelsen: 'X'. Forbindelsen genoprettes automatisk. Fortsæt med at arbejde normalt. +warning:direct_result = OBS. bruf af kræver at alle poster er radioposter eller at MeOS kun bruges til tidtagning uden baner.\n\nSkal resultat ved målstempling aktiveres? +warning:drawresult = Klassen har allerede resultater, starttider overskrives. Vil du fortsætte? +warning:has_entries = Klassen har allerede løbere. Hvis du ændrer turfordelingen kan du miste data.\n\nVil du fortsætte? +warning:has_results = Klassen har allerede resultater. Ændring af turfordelingen er usædvanligt.\n\nVil du fortsætte? +xml-data = XML data +Äldre protokoll = Ældre protokol +Ändra = Skift +Ändra grundläggande inställningar och gör en ny fördelning = Skift grundlæggende indstillinger og foretag en ny fordeling +Ändra inställningar = Skift indstillinger +Ändra klassinställningar = Skift klasseindstillinger +Ändra lag = Skift hold +Ändra lagets gaffling = Ændr holdets gafflinger +Ändra sträckindelning = Skift turfordeling +Ändrad = Ændret +Ändrade avgift för X deltagare = Ændret afgift for X deltager(e) +Åldersfilter = Aldersfilter +Åldersgräns ungdom = Aldersgrænse ungdom +Åldersgräns äldre = Aldersgrænse ældre +Åldersgränser, reducerad anmälningsavgift = Aldersgrænser, reduceret løbsafgift +Ångra = Fortryd +Återansluten mot databasen, tävlingen synkroniserad = Gentilsluttet til databasen, løbet synkroniseret +Återbud = Slet tilmelding +Återgå = Gå tilbage +Återställ = Fortryd +Återställ / uppdatera klasstillhörighet = Gendan / opdater klassetilhørsforhold +Återställ löpare med registrering till = Gendan løber med registrering til +Återställ säkerhetskopia = Gendan fra sikkerhedskopi +Återställ tabeldesignen och visa allt = Gendan tabeldesign og vis alt +ÅÅÅÅ-MM-DD = ÅÅÅÅ-MM-DD +Ökande = Stigende +Öppen = Åben +Öppen klass = Åben klasse +Öppna = Åbn +Öppna fil = Åbn fil +Öppna från aktuell tävling = Åbn fra aktuelt løb +Öppna föregående = Åbn foregående +Öppna föregående etapp = Åbn foregående etape +Öppna i ett nytt fönster = Åbn i nyt vindue +Öppna klasser, ungdom = Åbne klasser, ungdom +Öppna klasser, vuxna = Åbne klasser, voksne +Öppna nästa = Åbn næste +Öppna nästa etapp = Åbn næste etape +Öppna tävling = Åbn løb +Öppna vald tävling = Åbn valgte løb +Öppnad tävling = Åbnet løb +Överför anmälda = Overfør tilmeldte +Överför nya deltagare i ej valda klasser med status "deltar ej" = Overfør nye deltagere i ikke valgte klasser med status "deltager ikke" +Överför resultat = Overfør resultater +Överför resultat till X = Overfør resultater til X +Överför resultat till nästa etapp = Overfør resultat til næste etape +Överföring = Overførsel +Övertid = Tidsoverskridelse +Övre datumgräns = Øvre datogrænse +Övre gräns (år) = Øvre datogrænse (år) +Övre ålder = Øvre alder +Övriga = Øvrige +är först i mål med tiden X = er først i mål med tiden X +är först vid X med tiden Y = er først ved X med tiden Y +är först vid växeln med tiden X = er først ved skiftet med tiden X +är inte godkänd = er diskvalificeret +återställd = gendannet +åtta = otte +åttonde = ottende +Antal banor = Antal baner +Antal per bana = Antal pr. bane +Could not load list 'X' = Kunne ikke indlæse liste 'X' +Från den här listan kan man skapa etiketter att klistra på kartor = Med denne liste kan man lave labels til klistre på kortene +Gafflingar i tabellformat = Gaflinger på tabelformat +Kopiera = Kopier +Kopiera till urklipp = Kopier til udklipsholder +Liveresultat = Live resultater +Result on leg = Result for stræk +RunnerStartCond = Løberens starttid (individuel) +StartTimeForClassRange = Klassens startperiode +TeamStartCond = Holdets starttid (hvis individuel) +Vakanser - X = Vakante - X +Visa rullande tider mellan kontroller i helskärmsläge = Vis rullende tider mellem poster i fuld skærm. +help:liveresultat = Denne funktion starter en timer i fuldskærmformat når en løber i en valgt klasse stempler posten og måler så tiden indtil posten stemples. Ellers vises en liste over de bedste tider på strækket. Begge poster skal naturligvis være online(radio) poster. Hvis data sendes over et netværk bør posterne være sat op til 'hurtig indsendelse' for at få en hurtigt reagerende visning. +Aktivera stöd för tider över 24 timmar = Understøt løb der varer mere end 24 timer +Alla uthyrda brickor har bockats av = Alle lejebrikker er krydset af +Avbockade brickor = Afkrydsede brikker +Avstämning hyrbrickor = Afstemning af lejebrikker +Betalningsmetoder = Måder hvorpå der kan betales +Betalsätt = Betalingsmåde +Bricka X används också av = Brik X bruges også af +Brickor markerade som både uthyrda och egna: X = Brikker der er markeret både som lejebrik og som privat X +Datumfilter = Dato filter +Destination: X = Destination: X +Du kan använda en SI-enhet för att läsa in bricknummer = Du kan bruge en SI enhed til at indlæse nummeret på brikken +Ej startstämpling = Ingen startstempling +Extraplatser = Ekstra pladser +Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD) = Fejlagtigt datoformat 'X' (Brug YYYY-MM-DD) +Felaktigt tidsformat 'X' (Använd TT:MM:SS) = Fejlagtigt tidsformat 'X' (Brug HH:MM:SS) +Fritt = Frit +Från lag = Fra hold +Förväntat antal besökare: X = Forventet antal deltagere: X +Gafflingsnyckel = Gafflingsnøgle +Hämta inställningar från föregående lottning = Hent indstillinger fra tidligere lodtrækning +Ignorera startstämpling = Ignorer startstempling +Ingen parstart = Individuel start +Inget filter = Intet filter +Inkludera information om flera lopp per löpare = Inkluder information om flere løb for den enkelte løber +Inlästa stämplar = Indlæs stemplinger +Invalid filter X = Ugyldigt filter X +Invalid font X = Ugyldigt font X +Klasserna X och Y har samma externa id. Använd tabelläget för att ändra id = Klasserne X og Y har samme eksterne id. Brug tabeltilstand til at rette id +Lag + sträcka = Hold + tur +Lotta klasser med banan X = Lodtræk klasser med bane 'X' +Lotta klasser med samma bana gemensamt = Lodtræk klasser med samme bane samlet +Lotta starttider = Lodtræk starttider +Löpare saknas = Ingen løbere +MeOS Timing = MeOS Timing +Med resultat = Med resultat +Nollställ = Nulstil +Nollställ minnet; markera alla brickor som icke avbockade = Nulstil hukommelse; glem alle afkrydsede brikker +Nummerlappshantering = Håndtering af brystnumre +Ogiltig destination X = Ugyldig destination X +Ogiltigt antal sekunder: X = Ugyldigt antal sekunder: X +Oordnade parallella = Ikke ordnede paralelle +Parvis (två och två) = Parvis (to og to) +Rapport = Rapport +Result at a control = Resultat ved post +RunnerLegNumber = Løbere grupperet efter stræk +RunnerRogainingPointGross = Rogaining (hold) point før reduktion +RunnerStartZero = Løberes relative starttid (nultid) +Samlade poäng = Samlet antal point +Spara starttider = Gem starttider +Starttiden är definerad genom klassen eller löparens startstämpling = Starttiden er defineret ud fra klassen eller ud fra løberens startstempling +Säkerhetskopierar om = Laver sikkerhedskopi om +Säkerhetskopiering = Interval Backup +TeamStartZero = Holdets relative start tid (nul tid) +Tidsavdrag = Fradrag i tid +Total/team result at a control = Samlet/hold resultat ved en post +Totalt antal unika avbockade brickor: X = Samlet antal (unikke) afkrydsede brikker: X +Uppdatera inte starttiden vid startstämpling = Opdater ikke starttid ved startstempling +Uthyrda brickor som inte avbockats = Lejbrikker som ikke er krydset af +Uthyrda: X, Egna: Y, Avbockade uthyrda: Z = Lejede: X, Private: Y, Lejede/afkrydsede: Z +Varning: Brickan X används redan av Y = Advarsel: Brik x bruges allerede af Y +Vill du göra om avbockningen från början igen? = Vil du starte forfra med afkrydsning? +Vill du koppla isär X från inläst bricka Y? = Vil du fjerne kobling af X til den indlæste brik Y? +Vissa inställningar kräver omstart av MeOS för att ha effekt = Nogle indstiller kræver at MeOS genstartes før de virker +X och Y[N by N] = X og Y +X p = X p +X platser. Startar Y = X pladser. Starter Y +Year of birth = Førdselsår +delar placering med X = deler placering med X +encoding = encoding +false[boolean] = false +help:checkcards = Brug denne funktion for at tælle og krydse lejebrikker af for at se at de alle er returneret. Kobl en SI enhed til PC'en (helst programmeret som postenhed eller mål, da det er hurtigere end hvis den er sat op til aflæs) og stempl alle de returnerede brikker. Tryk på Rapport for at se om der mangler brikker. \n\nDette foregår lokalt på denne PC og ændrer ikke ved selve løbets data. +help:long_times = Løbsdato er dato hvor alle klasser starter. Nultid er midnat. +help:paymentmodes = Man kan definere egne betalingsformer for at kunne skelne i regnskabet. +leder med X = fører med X +leder med X; har tappat Y = fører med X; har tabt Y +leder med X; sprang Y snabbare än de jagande = fører med X; løb Y hurtigere end de efterfølgende +prefsAccount = Standard kontonummer +prefsAddress = Standard adresse +prefsAdvancedClassSettings = Vis avancerede klasseindstillinger +prefsAutoSaveTimeOut = Interval for automatisk backup (ms) +prefsAutoTie = Kobl automatisk løber til brik +prefsCardFee = Standard brikleje +prefsClient = Client navn i netværk +prefsControlFrom = Seneste fra kontrol +prefsControlTo = Seneste til kontrol +prefsCurrencyFactor = Valutakurs +prefsCurrencyPreSymbol = Valutatype før beløb +prefsCurrencySeparator = Decimaltegn for valuta +prefsCurrencySymbol = valutasymbol +prefsDatabase = Brug løberdatabase +prefsDatabaseUpdate = Seneste opdatering af løberdatabase +prefsDefaultDrawMethod = Foretrukken lodtrækningsmetode +prefsDirectPort = Network port for advance punch data +prefsEMail = EMail +prefsEliteFee = Standard elite startgebyr +prefsEntryFee = Standard startgebyr +prefsEventorBase = URL til Eventor +prefsFirstInvoice = First regningsnummer +prefsFirstTime = Første opstart +prefsHomepage = Hjemmeside +prefsInteractive = Interaktiv brikhåndtering +prefsLateEntryFactor = Faktor for sen tilmelding +prefsLiveResultFont = Font brugt til Live resultater +prefsMIPURL = URL for MIP server +prefsMOPFolderName = Lokal MOP mappe +prefsMOPURL = URL for MOP server +prefsManualInput = Brug manuel resultat indlæsning +prefsMaximumSpeakerDelay = Maksimal forsinkelse af speakeropdatering +prefsOrganizer = Arrangør +prefsPort = MySQL netværks port +prefsRentCard = Leje af brik +prefsSeniorAge = Senioraldersgrænse +prefsServer = Standard netværks server +prefsSpeakerShortNames = Brug initialer i navne +prefsStreet = Arrangør adresse +prefsSynchronizationTimeOut = Network update timeout (ms) +prefsTextFont = MeOS text tegnsæt +prefsUseDirectSocket = Use avancerede stemplingsdata +prefsUseEventor = Brug Eventor +prefsUseEventorUTC = Brug UTC (universal coordinated time) mod Eventor +prefsUseHourFormat = Brug tidsformat HH:MM:SS i stedet for MMM:SS +prefsUserName = MySQL user name +prefsYouthAge = Ungdomsaldersgrænse +prefsYouthFee = Ungdoms startgebyr +prefsaddressxpos = Adresse x-koordinat +prefsaddressypos = Adresse y-koordinat +prefsclasslimit = Grænse for antal resultater per klasse +prefsintertime = Vis mellemtider +prefspagebreak = Indsæt sideskift +prefssplitanalysis = Foretag split time analyse +reused card = genbrugt brik +sekund = sekund +sekunder = sekunder +skickar ut X = sender X ud +true[boolean] = true +var först i mål med tiden X = var først i mål med tiden X +var först vid X med tiden Y = var først til X med tiden Y +var först vid växeln med tiden X = var først til skiftet med tiden X +Ändra MeOS lokala systemegenskaper = Skift MeOS lokale systemegenskaber +Ändra X = Ændr X +Ändra lokala inställningar = Skift lokale indstilliger +är X efter = er X efter +är X efter Y = er X efter Y +är X efter; har tagit in Y = er X efter; har indhentet Y +är X efter; har tappat Y = er X efter; har tabt Y +är X före Y = er X foran Y +är nu på X plats med tiden Y = er nu på X plads med tiden Y +är nu på delad X plats med tiden Y = er nu på delt X plads med tiden Y +övriga = øvrige +ClassTeamLegResult = Klasse og tur resultat +Climb (m) = Stigning (m) +Databaskälla = Kildedatabase +Export language = Exportsprog +Export split times = Exporter mellemtider +Filnamn IOF (xml) eller OE (csv) med löpare = Filenavn IOF (xml) eller OE (csv) med løbere +Importinställning = Import opsætning +Längsta tid i sekunder att vänta med utskrift = Det længste, i sekunder, der ventes med udskrift +Max antal brickor per sida = Max antal Si-brikker per side +SortLastNameOnly = Efternavn +Sträcktider i kolumner (för standardpapper) = Stræktider i kolonner (på standard papirformat) +Utrymme: X = Plads: X +[Radera] = [Slet] +prefsExportCSVSplits = Inkluder mellemtider i csv export +prefsExportFormat = Foretrukket eksportformat +prefsImportOptions = Foretrukken import opsætning +prefsNumSplitsOnePage = Antal Si-brikker per side +prefsPayModes = Betalingsmåder +prefsSplitLateFees = Opdel beløb for for sen tilmelding i normal- og tillægsdel ved IOF XML eksport +prefsSplitPrintMaxWait = Maksimal ventetid for udskrift af mellemtider +prefsWideSplitFormat = Udskriv mellemtider i bredformat diff --git a/code/download.cpp b/code/download.cpp new file mode 100644 index 0000000..42da6fd --- /dev/null +++ b/code/download.cpp @@ -0,0 +1,457 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "Download.h" +#include +#include "Localizer.h" +#include "meos_util.h" +#include "progress.h" + +#include +#include +#include + +#include + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +Download::Download() +{ + hThread = 0; + doExit = false; +//hProgress = NULL; + + fileno = 0; + hInternet = NULL; + hURL = NULL; + + bytesLoaded = 0; + bytesToLoad = 1024; + + success = false; +} + +Download::~Download() +{ + shutDown(); + endDownload(); + + if (hInternet) + InternetCloseHandle(hInternet); +} + +void __cdecl SUThread(void *ptr) +{ + Download *dwl=(Download *)ptr; + dwl->initThread(); +} + +bool Download::createDownloadThread() { + doExit=false; + hThread=_beginthread(SUThread, 0, this); + + if (hThread==-1) { + hThread=0; + return false; + } + + return true; +} + +void Download::shutDown() +{ + if (hThread) { + doExit=true; + + int m=0; + while(m<100 && hThread) { + Sleep(0); + Sleep(10); + m++; + } + //If unsuccessful ending thread, do it violently + if (hThread) { + OutputDebugString("Terminate thread...\n"); + TerminateThread(HANDLE(hThread), 0); + CloseHandle(HANDLE(hThread)); + } + hThread=0; + } + +} + +void Download::initThread() +{ + int status = true; + while(!doExit && status) { + status = doDownload(); + } + hThread=0; +} + +void Download::initInternet() { + hInternet = InternetOpen("MeOS", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + + if (hInternet==NULL) { + DWORD ec = GetLastError(); + string error = lang.tl("Error: X#" + getErrorMessage(ec)); + throw std::exception(error.c_str()); + } + + DWORD dwTimeOut = 120 * 1000; + InternetSetOption(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeOut, sizeof(DWORD)); + InternetSetOption(hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwTimeOut, sizeof(DWORD)); +} + +void Download::downloadFile(const string &url, const string &file, const vector< pair > &headers) +{ + if (hURL || !hInternet) + throw std::exception("Not inititialized"); + + success = false; + + string hdr; + for (size_t k = 0; k= 400) { + char bf[256]; + switch (dwStatus) { + case HTTP_STATUS_BAD_REQUEST: + sprintf_s(bf, "HTTP Error 400: The request could not be processed by the server due to invalid syntax."); + break; + case HTTP_STATUS_DENIED: + sprintf_s(bf, "HTTP Error 401: The requested resource requires user authentication."); + break; + case HTTP_STATUS_FORBIDDEN: + sprintf_s(bf, "HTTP Error 403: Åtkomst nekad (access is denied)."); + break; + case HTTP_STATUS_NOT_FOUND: + sprintf_s(bf, "HTTP Error 404: Resursen kunde ej hittas (not found)."); + break; + case HTTP_STATUS_NOT_SUPPORTED: + sprintf_s(bf, "HTTP Error 501: Förfrågan stöds ej (not supported)."); + break; + case HTTP_STATUS_SERVER_ERROR: + sprintf_s(bf, "HTTP Error 500: Internt serverfel (server error)."); + break; + default: + sprintf_s(bf, "HTTP Status Error %d", dwStatus); + } + throw dwException(bf, dwStatus); + } + } + + fileno=_open(file.c_str(), O_BINARY|O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE); + + if (fileno==-1) { + fileno=0; + endDownload(); + char bf[256]; + sprintf_s(bf, "Error opening '%s' for writing", file.c_str()); + throw std::exception(bf); + } + + bytesLoaded = 0; + return; +} + +void Download::endDownload() +{ + if (hURL && hInternet) { + InternetCloseHandle(hURL); + hURL=NULL; + } + + if (fileno) { + _close(fileno); + fileno=0; + } +} + +bool Download::doDownload() +{ + if (hURL && hInternet) { + char buffer[512]; + + DWORD bRead; + if (InternetReadFile(hURL, buffer, 512, &bRead)) { + //Success! + if (bRead==0) { + //EOF + success=true; + endDownload(); + } + else{ + if (_write(fileno, buffer, bRead) != int(bRead)) { + endDownload(); + return false; + } + bytesLoaded+=bRead; + return true; + } + } + } + return false; +} + +void Download::setBytesToDownload(DWORD btd) +{ + bytesToLoad = btd; +} + +bool Download::isWorking() +{ + return hThread!=0; +} + +bool Download::successful() +{ + return success; +} + +void Download::postFile(const string &url, const string &file, const string &fileOut, + const vector< pair > &headers, ProgressWindow &pw) { + SetLastError(0); + DWORD_PTR dw = 0; + URL_COMPONENTS uc; + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + char host[128]; + char path[128]; + char extra[256]; + uc.lpszExtraInfo = extra; + uc.dwExtraInfoLength = sizeof(extra); + uc.lpszHostName = host; + uc.dwHostNameLength = sizeof(host); + uc.lpszUrlPath = path; + uc.dwUrlPathLength = sizeof(path); + + InternetCrackUrl(url.c_str(), url.length(), ICU_ESCAPE, &uc); + int port = INTERNET_DEFAULT_HTTP_PORT; + if (uc.nScheme == INTERNET_SCHEME_HTTPS) + port = INTERNET_DEFAULT_HTTPS_PORT; + else if (uc.nPort>0) + port = uc.nPort; + HINTERNET hConnect = InternetConnect(hInternet, host, port, + NULL, NULL, INTERNET_SERVICE_HTTP, 0, dw); + bool success = false; + int errorCode = 0; + try { + success = httpSendReqEx(hConnect, path, headers, file, fileOut, pw, errorCode); + } + catch (std::exception &) { + InternetCloseHandle(hConnect); + throw; + } + InternetCloseHandle(hConnect); + + if (!success) { + if (errorCode != 0) + errorCode = GetLastError(); + + string error = errorCode != 0 ? getErrorMessage(errorCode) : ""; + if (error.empty()) + error = "Ett okänt fel inträffade."; + throw std::exception(error.c_str()); + } + } + +bool Download::httpSendReqEx(HINTERNET hConnect, const string &dest, + const vector< pair > &headers, + const string &upFile, const string &outFile, + ProgressWindow &pw, + int &errorCode) const { + errorCode = 0; + INTERNET_BUFFERS BufferIn; + memset(&BufferIn, 0, sizeof(BufferIn)); + BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); + + HINTERNET hRequest = HttpOpenRequest (hConnect, "POST", dest.c_str(), NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + + DWORD dwBytesRead = 0; + DWORD dwBytesWritten = 0; + BYTE pBuffer[4*1024]; // Read from file in 4K chunks + + string hdr; + for (size_t k = 0; k0) { + + HANDLE hFile = CreateFile(upFile.c_str(), GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile == HANDLE(-1)) + return false; + + + BufferIn.dwBufferTotal = GetFileSize (hFile, NULL); + BufferIn.dwHeadersLength = hdr.length(); + BufferIn.lpcszHeader = hdr.c_str(); + + double totSize = BufferIn.dwBufferTotal; + + if (!HttpSendRequestEx( hRequest, &BufferIn, NULL, 0, 0)) { + CloseHandle(hFile); + InternetCloseHandle(hRequest); + return false; + } + + DWORD sum = 0; + do { + if (!ReadFile (hFile, pBuffer, sizeof(pBuffer), &dwBytesRead, NULL)) { + errorCode = GetLastError(); + CloseHandle(hFile); + InternetCloseHandle(hRequest); + return false; + } + + if (dwBytesRead > 0) { + if (!InternetWriteFile(hRequest, pBuffer, dwBytesRead, &dwBytesWritten)) { + errorCode = GetLastError(); + CloseHandle(hFile); + InternetCloseHandle(hRequest); + return false; + } + } + sum += dwBytesWritten; + + try { + pw.setProgress(int(1000 * double(sum) / totSize)); + } + catch (std::exception &) { + CloseHandle(hFile); + InternetCloseHandle(hRequest); + throw; + } + } + while (dwBytesRead == sizeof(pBuffer)) ; + + CloseHandle(hFile); + + if (!HttpEndRequest(hRequest, NULL, 0, 0)) { + DWORD error = GetLastError(); + errorCode = error; + if (error == ERROR_INTERNET_FORCE_RETRY) + retry--; + else if (error == ERROR_INTERNET_TIMEOUT) { + throw std::exception("Fick inget svar i tid (ERROR_INTERNET_TIMEOUT)"); + } + else { + InternetCloseHandle(hRequest); + return false; + } + } + else + retry = 0; // Done + } + + DWORD dwStatus = 0; + DWORD dwBufLen = sizeof(dwStatus); + int success = HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, + (LPVOID)&dwStatus, &dwBufLen, 0); + + if (success) { + if (dwStatus >= 400) { + char bf[256]; + switch (dwStatus) { + case HTTP_STATUS_BAD_REQUEST: + sprintf_s(bf, "HTTP Error 400: The request could not be processed by the server due to invalid syntax."); + break; + case HTTP_STATUS_DENIED: + sprintf_s(bf, "HTTP Error 401: The requested resource requires user authentication."); + break; + case HTTP_STATUS_FORBIDDEN: + sprintf_s(bf, "HTTP Error 403: Åtkomst nekad (access is denied)."); + break; + case HTTP_STATUS_NOT_FOUND: + sprintf_s(bf, "HTTP Error 404: Resursen kunde ej hittas (not found)."); + break; + case HTTP_STATUS_NOT_SUPPORTED: + sprintf_s(bf, "HTTP Error 501: Förfrågan stöds ej (not supported)."); + break; + case HTTP_STATUS_SERVER_ERROR: + sprintf_s(bf, "HTTP Error 500: Internt serverfel (server error)."); + break; + default: + sprintf_s(bf, "HTTP Status Error %d", dwStatus); + } + throw dwException(bf, dwStatus); + } + } + + int fileno = _open(outFile.c_str(), O_BINARY|O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE); + + do { + dwBytesRead=0; + if (InternetReadFile(hRequest, pBuffer, sizeof(pBuffer)-1, &dwBytesRead)) { + _write(fileno, pBuffer, dwBytesRead); + } + } while(dwBytesRead>0); + + _close(fileno); + + InternetCloseHandle(hRequest); + return true; +} diff --git a/code/download.h b/code/download.h new file mode 100644 index 0000000..3f8cca8 --- /dev/null +++ b/code/download.h @@ -0,0 +1,91 @@ +// Download.h: interface for the Download class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DOWNLOAD_H__DEBC6296_9CAE_4FF6_867B_DD896D0B6A7A__INCLUDED_) +#define AFX_DOWNLOAD_H__DEBC6296_9CAE_4FF6_867B_DD896D0B6A7A__INCLUDED_ + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +typedef HANDLE HINTERNET; + +class dwException : public std::exception { +public: + int code; + dwException(const char *msg, int id) : std::exception(msg), code(id) {} + virtual ~dwException() {} +}; + +class ProgressWindow; + +class Download { +private: + volatile unsigned hThread; + volatile bool doExit; + //HWND hProgress; + + HINTERNET hInternet; + HINTERNET hURL; + + int fileno; + + DWORD bytesLoaded; + DWORD bytesToLoad; + bool success; + void initThread(); + + bool httpSendReqEx(HINTERNET hConnect, const string &dest, const vector< pair > &headers, + const string &upFile, const string &outFile, ProgressWindow &pw, int &errroCode) const; + +public: + + void postFile(const string &url, const string &file, const string &fileOut, + const vector< pair > &headers, ProgressWindow &pw); + int processMessages(); + bool successful(); + bool isWorking(); + void setBytesToDownload(DWORD btd); + void endDownload(); + void downloadFile(const string &url, const string &file, const vector< pair > &headers); + void initInternet(); + void shutDown(); + bool createDownloadThread(); + void downLoadNoThread() {initThread();} + + Download(); + virtual ~Download(); + +protected: + bool doDownload(); + + friend void SUThread(void *ptr); + +}; + +#endif // !defined(AFX_DOWNLOAD_H__DEBC6296_9CAE_4FF6_867B_DD896D0B6A7A__INCLUDED_) diff --git a/code/english.lng b/code/english.lng new file mode 100644 index 0000000..57b4811 --- /dev/null +++ b/code/english.lng @@ -0,0 +1,2241 @@ +encoding = ANSI +%s m = %s m +%s meter = %s meters +%s, block: %d = %s, block: %d +(ledare) = (leader) +(lokalt) = (local, no server) +(okänd) stämplade vid = (unknown) punched at +(på server) = (on server) +(sekunder) = (seconds) +(sträckseger) = (leg winner) +ALLA( = All( +API-nyckel = API key +Accepterade elektroniska fakturor = Accepted electronic invoices +Adress = Address +Adress och kontakt = Address and contact +Aktivera = Activate +Alla = All +Alla banfiler = All course files +Alla deltagare måste ha ett namn = All competitors must have a name +Alla fakturor = All Invoices +Alla händelser = All events +Alla lag måste ha ett namn = All teams must have a name +Alla listor = All Lists +Alla lopp = All races +Alla sträckor/lopp i separata filer = All legs/races in separate files +Alla typer = All types +Allmänna resultat = General results +Andel vakanser = Vacancy fraction +Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar = Provide the first bib number, or blank for no bibs +Ange om kontrollen fungerar och hur den ska användas = Specify if the controls is operational and how it is to be used +Ange startintervall för minutstart = Enter start interval for restart +Ange tiden relativt klassens första start = Enter time relative the first start of the class. +Anm. avg. = Entry fee +Anm. avgift = Entry fee +Anm. datum = Entry date +Anmäl = Enter +Anmäl X = Enter X for the competition +Anmälda = Entries +Anmälda per distrikt = Entries per district +Anmälningar = Entries +Anmälningar (IOF (xml) eller OE-CSV) = Entries (IOF (xml) or OE-CSV) +Anmälningsavgift = Entry fee +Anmälningsläge = Quick entry mode +Anslut = Connect +Anslut till en server = Connect to a server +Ansluten till = Connected to +Ansluter till Internet = Connecting to the Internet +Anslutna klienter = Connected clients +Anslutningar = Connections +Anslutningsinställningar = Connection settings +Antal = Number +Antal besökare X, genomsnittlig bomtid Y, största bomtid Z = Number of visitors X, average lost time Y, max lost time Z +Antal ignorerade: X = Number of ignored entries: X +Antal importerade = Number of imported +Antal kartor = Number of maps +Antal klasser = Number of classes +Antal löpare = Number of runners +Antal löpare på vanligaste banan X = Number of runners on most used course X +Antal misslyckade: X = Number of failed entries: X +Antal startande per block = Number of starts per block +Antal startande per intervall (inklusive redan lottade) = Numbers of starts per interval (including already drawn) +Antal sträckor = Number of legs +Antal vakanser = Number of vacancies +Antal: %d = Number: %d +Antal: X = Number: X +Antalet rader i urklipp får inte plats i selektionen = The number of rows on the clipboard does not fit the selection +Använd Eventor = Use Eventor +Använd banpool = Use course pool +Använd funktioner för fleretappsklass = Use functions for multi stage class +Använd första kontrollen som start = Use first control as start +Använd löpardatabasen = Use runner database +Använd sista kontrollen som mål = Use last control as finish +Använd speakerstöd = Use Speaker Module +Använd stor font = Use large type face +Använd symbolen X där MeOS ska fylla i typens data = Use the symbol X where MeOS should fill in the data +Användarnamn = User name +Applicera för specifik sträcka = Apply for a specific leg +Arrangör = Organizer +Att betala = To pay +Att betala: X = To pay: X +Automater = Services +Automatisera = Automatize +Automatisk lottning = Draw Automatically +Automatisk skroll = Automatic Scroll +Automatisk utskrift = Automatic printout +Automatisk utskrift / export = Automatic printing / export +Av MeOS: www.melin.nu/meos = By MeOS: www.melin.nu/meos +Avancerat = Advanced +Avbryt = Cancel +Avgift = Fee +Avgifter = Fees +Avgiftshöjning (procent) = Fee extension (percent) +Avgjorda klasser (prisutdelningslista) = Settled classes (Prize Ceremony List) +Avgjorda placeringar - %s = Settled Results - %s +Avgörande händelser = Decisive events +Avgörs X = Ready at X +Avgörs kl = Time ready +Avläsning/radiotider = Readout/radio +Avmarkera allt = Deselect all +Avrundad tävlingsavgift = Competition fee, rounded +Avsluta = Exit +Bad file format = Bad file format +Bana = Course +Bana %d = Course %d +Banan används och kan inte tas bort = The course is in use +Banan måste ha ett namn = The course must have a name +Banmall = Course +Banor = Courses +Banor (antal kontroller) = Courses (number of controls) +Banor för %s, sträcka %d = Courses for %s, leg %d +Banor, IOF (xml) = Courses, IOF (xml) +Banor, OCAD semikolonseparerat = Courses, OCAD format +Banpool = Course pool +Banpool, gemensam start = Course pool, simultaneous start +Banpool, lottad startlista = Course pool, drawn start list +Bantilldelning = Course Assignment +Bantilldelning, individuell = Course assignment, individual +Bantilldelning, stafett = Course assignment, relay +Bantilldelningslista - %s = Assigned Courses - %s +Basintervall (min) = Base interval (min) +Begränsa antal per klass = Limit number per class +Begränsa per klass = Limit class-wise +Begränsning, antal visade per klass = Limit, number of entries per class +Behandlar löpardatabasen = Processing runner database +Behandlar tävlingsdata = Processing competition data +Behandlar: X = Processing: X +Bekräfta att %s byter klass till %s = Please confirm that %s changes class to %s +Bekräfta att deltagaren har lämnat återbud = Please confirm drop out of this runner +Betalat = Paid +Betalningsinformation = Payment details +Bevakar händelser i X = Monitoring events in X +Bevakningsprioritering = Select runner to watch +Block = Block +Blockbredd = Block width +Bläddra = Browse +Bold = Bold +BoldHuge = Bold, gigantic +BoldLarge = Bold, large +BoldSmall = Bold, small +Bommade kontroller = Control mistakes +Bomtid = Time lost +Bomtid (max) = Lost time (max) +Bomtid (medel) = Lost time (average) +Bomtid (median) = Lost time (median) +Bomtid: X = Lost time: X +Bricka = Card +Bricka %d används redan av %s och kan inte tilldelas = Card %d is in use by %s and cannot be assigned +Brickan redan inläst = Card has already been read out +Brickhyra = Card fee +Bricknummret är upptaget (X) = The card is in use (X) +Brickor = Cards +Bygg databaser = Build Databases +COM-Port = COM-Port +Check = Check +ClassCourseResult = Class, course, result +ClassFinishTime = Class, finish time +ClassLength = Course length for class +ClassName = Class +ClassPoints = Class, points +ClassResult = Class, result +ClassResultFraction = Fraction of class complete +ClassStartName = Start name +ClassStartTime = Class, start time, name +ClassStartTimeClub = Class, start time, club +ClassTotalResult = Class, total result +Club = Club +ClubName = Club +ClubRunner = Club (competitor) +CmpDate = Competition date +CmpName = Competition name +CourseClimb = Course climb +CourseLength = Course length, specific course +CourseName = Course name +CourseResult = Course, result +CurrentTime = Current time +Databasanslutning = Database Connection +Databasvarning: X = Database warning: X +Datorröst som läser upp förvarningar = Computer voice announcing runners +Datum = Date +Decimalseparator = Decimal separator +DefaultFont = Standard formatting +Dela = Split +Dela efter ranking = Split by ranking +Dela klass: X = Split Class: X +Dela klassen = Split Class +Dela klubbvis = Split by club +Deltagare = Competitors +Deltagare %d = Competitor %d +Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = The competitor 'X' is in the patrol class 'Y', but has no patrol. The results in this class might be inconsistent +Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = The competitor 'X' is in the relay class 'Y', but has no team. The results in this class might be inconsistent +Deltagaren 'X' saknar klass = The competitor 'X' has no class +Deltar ej = NTP +Denna etapps nummer = Ordinal of this stage +Destinationskatalog = Destination folder +Det går endast att sätta in vakanser på sträcka 1 = You can only add vacancies to the first leg +Det här programmet levereras utan någon som helst garanti. Programmet är = There is no warranty for this program; it is provided "as is". The program is +Direktanmälan = Quick entry +Disk. = DISQ +Distriktskod = District code +Don't know how to align with 'X' = Don't know how to align with 'X' +Du kan importera banor och klasser från OCADs exportformat = You can import courses and classes from the export format of OCAD +Du måste välja en klass = You have to select a class +Duplicera = Duplicate +E-post = Email +Efter = Behind +Efteranm. avg. = Late fee +Efteranmälda (efter ordinarie) = Late Entries (After) +Efteranmälda (före ordinarie) = Late Entries (Before) +Efteranmälda före ordinarie = Late entries in front +Efteranmälningar = Late Entries +Egen listrubrik = Custom list heading +Egen text = Custom text +Egenskaper = Properties +Eget fönster = New Window +Egna listor = Custom Lists +Ej accepterade elektroniska fakturor = Refused electronic invoices +Ej elektronisk = Not electronic +Ej lottade = Not Drawn +Ej lottade, efter = Draw Remaining After +Ej lottade, före = Draw Remaining Before +Ej start = DNS +Ej tidtagning = Without timing +Ekonomisk sammanställning = Economical summary +Elektronisk = Electronic +Elektronisk godkänd = Electronic accepted +Elit = Elite +Elitavgift = Elite fee +Elitklasser = Elite classes +En gafflad sträcka = One forked stage +En klass kan inte slås ihop med sig själv = You cannot merge a class with itself +En klubb kan inte slås ihop med sig själv = A club cannot be merged with itself +Endast en bana = Single Course +Enhetstyp = Unit type +Etapp = Stage +Etapp X = Stage X +Etappresultat = Stage Results +Eventorkoppling = Eventor Connection +Export av resultat/sträcktider = Export Results / Splits +Exportera = Export +Exportera / Säkerhetskopiera = Export / Backup +Exportera alla till HTML = Export all to HTML +Exportera datafil = Export Data +Exportera elektroniska fakturor = Export electronic invoices +Exportera inställningar och löpardatabaser = Export Settings and Databases +Exportera löpardatabas = Export Runner Database +Exportera nu = Export now +Exportera på fil = Export to file +Exportera resultat på fil = Export results to file +Exportera startlista på fil = Export start list to file +Exportera sträcktider = Export Splits +Exportera tävlingsdata = Export data +Externt Id = External ID +Extra = Extra +Extra stämplingar = Extra punches +Extralöparstafett = Co-runner relay +FAKTURA = INVOICE +FEL, inget svar = Error, no response +FEL: Porten kunde inte öppnas = Error: Port could not be opened +Failed to generate card = Failed to generate card +Failed to open 'X' for reading = Failed to open 'X' for reading +Faktiskt startdjup: X minuter = Actual start depth: X minutes +Faktura = Invoice +Faktura nr = Invoice no +Faktureras = To be invoiced +Fakturor = Invoices +Fel: X = Error: X +Fel: hittar inte filen X = Error. File not found 'X' +Felaktig kontroll = Bad control +Felaktig nyckel = Incorrect key +Felaktig sträcka = Incorrect leg number +Felaktigt filformat = Bad file format +Felst. = MP +Fil att exportera till = File to export to +Fil: X = Filename: X +Filnamn = Filename +Filnamn (OCAD banfil) = Filename (OCAD courses) +Filnamn IOF (xml) med klubbar = Filename IOF (xml) with clubs +Filnamn IOF (xml) med löpare = Filename IOF (xml) with runners +Filnamnet får inte vara tomt = The file name must not be empty +Filter = Filtering +FilterHasCard = With card +FilterNoCard = Without card +FilterNotVacant = Not vacant +FilterOnlyVacant = Only vacant +FilterRentCard = Borrowed card +FilterResult = With result +FilterStarted = Has started +Filtrering = Filtering +FinishTime = Finish time, name +Flera banor = Multiple courses +Flera banor / stafett / patrull / banpool = Multiple Courses / Relay / Patrol / Course Pool +Flera banor/stafett = Several Courses / Relay +Flytta höger = Move Right +Flytta vänster = Move Left +Format = Format +Formaterat webbdokument (html) = Free web document (html) +Formateringsregler = Formatting rules +Formulärläge = Form Mode +Fortsätt = Continue +Fri anmälningsimport = Free Entry Import +Fri starttid = Free start time +Fria starttider = Free start times +Från kontroll = From control +Fullskärm = Full Screen +Funktioner = Functions +Födelseår = Birth year +Följande deltagare deltar ej = The following competitors will not take part +Följande deltagare har bytt klass = The following competitors have changed class +Följande deltagare har bytt klass (inget totalresultat) = The following competitors have changed class (no total result) +Följande deltagare har tilldelats en vakant plats = The following competitors have taken a vacant position +Följande deltagare är anmälda till nästa etapp men inte denna = The following competitors are registered for the next stage, but not this one +Följande deltagare är nyanmälda = The following competitors generated new entries +Följande deltagare överfördes ej = The following competitors were ignored +För att ändra måltiden måste löparens målstämplingstid ändras = To change the finish time, the finish punch time must be changed +För muspekaren över en markering för att få mer information = Hoover the mouse pointer over a marking to get more information +För många kontroller = Too many controls +Förbered lottning = Prepare Drawing Times +Fördefinierade tävlingsformer = Predefined competitions +Fördela starttider = Distribute Times +Föregående = Previous +Föregående etapp = Preceding stage +Förhandsgranskning, import = Import Preview +Förhöjd avgift = Extended fee +Först-i-mål, gemensam = First to finish, common +Först-i-mål, klassvis = First to finish, class-wise +Första (ordinarie) start = First (ordinary) start +Första kontrollen = First control +Första omstartstid = First time for restart +Första ordinarie starttid = First regular start time +Första start = First start +Första starttid = First start time +Första sträckan kan inte vara parallell = First leg cannot be parallel +Försöket misslyckades = Operation failed +Förvarning på (SI-kod): alla stämplingar = Forewarning (SI code): all punches +Förvarningsröst = Forewarning Voice +Förväntad andel efteranmälda = Expected fraction of late entries +Gata = Street +Gemensam start = Simultaneous start +Generera = Generate +Generera testtävling = Generate Test Competition +Genererad = Generated at +Geografisk fördelning = Geographical distribution +Global sorteringsordning = Global sort order +Godkänd API-nyckel = API key accepted +Granska inmatning = Preview +Grund avg. = Base fee +Grundavgift = Base fee +Grundinställningar = Basic Settings +Hantera brickor = Manage Cards +Hantera flera etapper = Manage Several Stages +Hantera jaktstart = Handle Pursuit +Hantera klubbar och ekonomi = Manage clubs and economy +Hantera kvar-i-skogen = Handle Remaining Runners +Hantera löparbrickor = Handle Runner Cards +Hemsida = Homepage +Hjälp = Help +Hoppar över stafettklass: X = Skipping relay class: X +Huvudlista = Main list +Hyravgift = Card hire +Hyrbricka = Borrowed card +Hyrbricksrapport = Report with Borrowed Cards +Hyrbricksrapport - %s = Borrowed Cards - %s +Hyrd = Borrowed +Hämta (efter)anmälningar från Eventor = Fetch (late) entries from Eventor +Hämta data från Eventor = Fetch Data from Eventor +Hämta efteranmälningar = Fetch Late Entries +Hämta löpardatabasen = Fetch Runner Database +Hämta svar om elektroniska fakturor = Get data on accepted invoices +Hämta tävlingsdata = Fetch competition data +Hämta tävlingsdata för X = Fetch competition data for X +Hämtar anmälda = Fetching entries +Hämtar information om = Collecting information about +Hämtar klasser = Fetching classes +Hämtar klubbar = Fetching clubs +Hämtar löpardatabasen = Fetching runner database +Hämtar tävling = Fetching competition +Händelser = Events +Händelser - tidslinje = Events - Time line +Hög avgift = Late fee +IOF (xml) = IOF (xml) +IOF Resultat (xml) = IOF Results (xml) +IOF Resultat, version 2.0.3 (xml) = IOF Results, version 2.0.3 (xml) +IOF Resultat, version 3.0 (xml) = IOF Results, version 3.0 (xml) +IOF Startlista (xml) = IOF Start list (xml) +IOF Startlista, version 3.0 (xml) = IOF Start list, version 3.0 (xml) +IOF Startlista, version 2.0.3 (xml) = IOF Start list, version 2.0.3 (xml) +IOF Löpardatabas, version 3.0 (xml) = IOF Competitor List, version 3.0 (xml) +IOF Klubbdatabas, version 3.0 (xml) = IOF Organization List, version 3.0 (xml) +IP-adress eller namn på en MySQL-server = IP address or the name of a MySQL server +Id = Id +Identifierar X unika inledningar på banorna = Identified X unique openings of courses +Importera = Import +Importera IOF (xml) = Import IOF (xml) +Importera anmälningar = Import Entries +Importera banor = Import Courses +Importera banor/klasser = Import courses/classes +Importera en tävling från fil = Import competition from file +Importera fil = Import File +Importera från OCAD = Import from OCAD +Importera från fil = Import from File +Importera löpardatabas = Import Runner Database +Importera löpare = Import Runners +Importera löpare och klubbar / distriktsregister = Import Runners and Clubs +Importera stämplingar = Import Punches +Importera tävling = Import Competition +Importera tävlingsdata = Import Data +Importerar = Importing +Importerar OCAD csv-fil = Importing OCAD CSV +Importerar OE2003 csv-fil = Importing OE2003 CSV +Importerar OS2003 csv-fil = Importing OS2003 CSV +Importerar anmälningar (IOF, xml) = Importing entries (IOF, xml) +Importerar banor (IOF, xml) = Importing courses (IOF, xml) +Importerar klasser (IOF, xml) = Importing classes (IOF, xml) +Importerar klubbar (IOF, xml) = Importing clubs (IOF, xml) +Importerar tävlingsdata (IOF, xml) = Importing competition data (IOF, xml) +Importerbara = Importable +Index = Index +Individuell = Individual +Individuell resultatlista, alla lopp = Individual result list, all races +Individuell resultatlista, sammanställning av flera lopp = Individual results, summary +Individuell resultatlista, visst lopp = Individual results, race +Individuell resultatlista, visst lopp (STOR) = Individual results, race (LARGE) +Individuell startlista, visst lopp = Individual start list, race +Individuella deltagare = Individual competitors +Individuella slutresultat = Individual Final Results +Individuella totalresultat = Individual Total Results +Info = Information +Inga = None +Inga deltagare = No competitors +Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning = No vacancies available. Vacancies are usually created when drawing the class +Ingen = None +Ingen bana = No course +Ingen deltagare matchar sökkriteriet = No competitor match the search criteria +Ingen klass = No class +Ingen klass vald = No class selected +Ingen löpare saknar bricka = All runners has a card +Ingen matchar 'X' = No match for 'X' +Ingen rogaining = No rogaining +Inkommande = Incoming +Inläst bricka ställd i kö = Card was put in queue +Inlästa brickor = Read cards +Inmatning av mellantider = Enter Radio Times +Inspekterar klasser = Inspecting classes +Installera = Install +Inställningar = Settings +Inställningar MeOS = MeOS, Settings +Interaktiv inläsning = Interactive readout +Intervall = Interval +Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras = Interval (seconds). Leave blank to update when competition data is changed. +Intervallet måste anges på formen MM:SS = The interval must be specified as MM:SS +Italic = Italic +ItalicMediumPlus = Italic, somewhat larger +Jag sköter lottning själv = I manage start list drawing myself +Jaktstart = Pursuit +Justera blockvis = Block-wise adjustment +Justera mot = Align with +Klart = Finished +Klart. Antal importerade: X = Finished. Number of entries imported: X +Klart. X deltagare importerade = Finished. X competitors imported +Klart. X lag importerade = Finished. X teams imported +Klart. X patruller importerade = Finished. X patrols imported +Klart: alla klasser lottade = Done: all classes drawn +Klart: inga klasser behövde lottas = Done: no classes needed to be drawn +Klass = Class +Klass %d = Class %d +Klass saknad = Missing class +Klass / klasstyp = Class / Type +Klass att slå ihop = Class to merge with +Klassbyte = Change Class +Klassen 'X' har jaktstart/växling på första sträckan = The class 'X' has pursuit/changeover on the first leg +Klassen används och kan inte tas bort = The class is in use and cannot be removed +Klassen lottas inte, startstämpling = Use only start punch +Klassen måste ha ett namn = The class must have a name +Klassens bana = Class's course +Klasser = Classes +Klasser (IOF, xml) = Classes (IOF, xml) +Klasser där nyanmälningar ska överföras = Classes where new entries will be transferred +Klassinställningar = Class Settings +Klassnamn = Class name +Klasstyp = Class type +Klientnamn = Client name +Klistra in = Paste +Klistra in data från urklipp (X) = Paste from clipboard (X) +Klocktid: X = Clock: X +Klubb = Club +Klubb att ta bort = Club to remove +Klubb: X = Club: X +KlubbId = Club Id +Klubbar = Clubs +Klubbar (IOF, xml) = Clubs (IOF, xml) +Klubbar som inte svarat = Clubs that did not answer +Klubbdatabasen = Club Database +Klubblös = No club +Klubbresultat = Club Results +Klubbresultatlista = Club Results +Klubbresultatlista - %s = Club Results - %s +Klubbstartlista = Club Start List +Klubbstartlista - %s = Club Start List - %s +Klungstart = Grouped start +Knyt löpare till sträckan = Tie a runner to the leg +Knyt löparna till banor från en pool vid målgång = Tie runners to courses at readout +Kom ihåg listan = Remember the List +Kommentar / version = Comment / Version +Kommunikation = Communication +Kontant = Cash +Kontant betalning = Cash +Konto = Account +Kontroll = Control +Kontroll %s = Control %s +Kontroll X = Control X +Kontroll inför tävlingen = Check competition +Kontrollen används och kan inte tas bort = The control is in use and cannot be removed +Kontrollens ID-nummer = ID of Control +Kontroller = Controls +Kontrollnamn = Control name +Kopia X = Copy X +Kopiera länken till urklipp = Copy link to clip board +Kopiera selektionen till urklipp (X) = Copy selection to clipboard (X) +Koppla ifrån = Disconnect +Koppla ner databas = Disconnect Database +Kopplar ifrån SportIdent på = Disconnecting SportIdent on +Kortast teoretiska startdjup utan krockar är X minuter = Shortest theoretical start depth without clashes is X minutes +Kortnamn = Short name +Kunde inte ansluta till Eventor = Could not connect to Eventor +Kunde inte ladda upp tävlingen (X) = Failed to upload competition (X) +Kvar-i-skogen = Competitors in Forest +Kvinna = Woman +Kvinnor = Women +Källkatalog = Source folder +Kön = Sex +Kör kontroll inför tävlingen = Run Competition Check +Ladda upp öppnad tävling på server = Upload Competition to Server +Lag = Team +Lag %d = Team %d +Lag(flera) = Teams +Laget 'X' saknar klass = The team 'X' has no class +Laget hittades inte = Team not found +Lagnamn = Team name +Lagrade säkerhetskopior = Stored backups +Land = Country +LargeFont = Large text +Latitud = Latitude +Lista = List +Lista av typ 'X' = List of type 'X' +Lista med mellantider = List with split times +Lista med sträcktider = List with split times +Listan kan inte visas = Cannot show list +Listegenskaper = List Properties +Listnamn = List name +Listor = Lists +Listor och sammanställningar = Lists and Summaries +Listpost = List Entry +Listredigerare = List Editor +Listredigerare – X = List Editor – X +Listrubrik = List heading +Listtyp = List type +Listval = List choice +Ljudfiler, baskatalog = Sound files, base folder +Lokalt = Locally +Longitud = Longitude +Lopp %d = Race %d +Lopp %s = Race %s +Lopp X = Race X +Lotta = Draw +Lotta / starttider = Draw / Manage Start Times +Lotta flera klasser = Draw Start Times for Several Classes +Lotta klassen = Draw Class +Lotta klassen X = Draw the class 'X' +Lotta löpare som saknar starttid = Draw runners without start time +Lotta om hela klassen = Redraw class +Lottad = Drawn +Lottad startlista = Drawn start list +Lottar efteranmälda = Drawing late entries +Lottar: X = Drawing start order: X +Lottning = Draw random +Lyssna = Listen +Lägg till = Add +Lägg till alla = Add All +Lägg till en ny rad i tabellen (X) = Add row to table (X) +Lägg till klasser = Add / update classes +Lägg till ny = Add New +Lägg till ny etapp = Add New Stage +Lägg till rad = Add Row +Lägg till stämpling = Add Punch +Lägger till klubbar = Adding clubs +Lägger till löpare = Adding runners +Längd (m) = Length (m) +Länk till resultatlistan = Link to the result list +Länk till startlistan = Link to the start list +Läs brickor = Read cards +Läser klubbar = Reading clubs +Läser löpare = Reading runners +Långt namn = Long name +Låt klassen ha mer än en bana eller sträcka = Let the class have more than one leg or course. +Löpande information om viktiga händelser i tävlingen = Get notifications for events in the competition +Löparbricka %d = Card %d +Löpardatabasen = Runner Database +Löpare = Runner +Löpare saknar klass eller bana = Runner without class or course +Löpare som förekommer i mer än ett lag = Runners existing in more than one team +Löpare utan SI-bricka: %d = Runner without card: %d +Löpare utan bana: %d = Runners without course: %d +Löpare utan klass: %d = Runners without class: %d +Löpare utan klubb: %d = Runners without club: %d +Löpare utan starttid: %d = Runners without start time: %d +Löpare, Ej Start, med registrering (kvar-i-skogen!?) = Runners, Status DNS, with Registration (In Forest!?) +Löpare, Status Okänd, med registrering (kvar-i-skogen) = Runners, Status unknown, with registration (in forest) +Löpare, Status Okänd, som saknar registrering = Runners, Status Unknown, missing registration +Löpare: = Competitors: +Löpare: X, kontroll: Y, kl Z = Competitor: X, control: Y, time: Z +Löparen hittades inte = Runner not found +Löptid = Running time +Lösenord = Password +Man = Man +Manuell lottning = Draw Manually +Manuella avgifter = Manual fees +Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar = Input first bib number, or leave blank to remove bibs +Mata in radiotider manuellt = Enter radio times by hand +Max antal gemensamma kontroller = Max number common controls +Max parallellt startande = Max. number parallel start +Max. vakanser (per klass) = Max. vacancy (per class) +Maximal tid efter ledaren för att delta i jaktstart = Maximal time after leader to participate in pursuit. +Maxtid = OMT +Maxtid efter = Maximum time after +MeOS = MeOS +MeOS lokala datakatalog är = MeOS local data folder is +MeOS – Resultatkiosk = MeOS – Result Kiosk +Med stafettklasser = With relay +Med sträcktidsanalys = With split analysis +MediumFont = Medium text +MediumPlus = Somewhat larger text +Medlöpare = Co-runner +Mellantider visas för namngivna kontroller = Intermediate times are shown for named controls +Metod = Method +Min. vakanser (per klass) = Min. vacancies (per class) +Minitid = Min. time +Minst MySQL X krävs. Du använder version Y = MeOS need MySQL X or later. You are using version Y +Minsta intabbning = Least indentation +Minsta intervall i klass = Smallest interval in class +Minsta startintervall = Smallest start interval +Minsta sträcktid = Shortest leg time +Minutstartlista = Minute Start List +Motion = Exercise +Multipel = Multiple +MySQL Server / IP-adress = MySQL Server / IP-address +Män = Men +Mål = Finish +Målstämpling saknas = Missing finish punch +Måltid = Finish time +Måltid saknas = Finish time missing +Måltid: X = Finish time: X +Namn = Name +Nationalitet = Nationality +Nollställ avgifter = Reset Fees +Nollställ databaser = Clear databases +Nollställde avgift för X deltagare = Cleared fee for X competitor(s) +Nolltid = Zero time +None = None +Normal = Normal +NormalFont = Normal text +Normalavgift = Normal fee +Not implemented = Not implemented +Nr = Number +Nummerlapp = Bib +Nummerlappar = Bibs +Nummerlappar i X = Bibs for X +Nuvarande innehavare: X = Current owner: X +Ny bana = New Course +Ny deltagare = New Competitor +Ny klass = New Class +Ny klubb = New Club +Ny kontroll = New Control +Ny lista = New List +Ny tävling = New Competition +Nyckel för Eventor = Eventor Key +Nytt fönster = New Window +Nytt lag = New Team +Nästa = Next +Nästa etapp = Next stage +Nästa försök = Next try +OE Semikolonseparerad (csv) = OE Semicolon separated (csv) +OK = OK +Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y' = Invalid course file. Expected a control number at position X, but found 'Y' +Ogiltig föregående/efterföljande etapp = Invalid previous/next stage +Ogiltig första starttid. Måste vara efter nolltid = Invalid first start time. Must be after zero time +Ogiltig omstartstid = Invalid restart time +Ogiltig repdragningstid = Invalid rope time +Ogiltig starttid i 'X' på sträcka Y = Invalid start time in 'X' on leg Y +Ogiltig starttid: X = Invalid start time: X +Ogiltig tid = Invalid time +Ogiltigt bricknummer X = Invalid card number X +Ogiltigt filformat = Invalid file format. +Okänd bricka = Unknown card +Okänd funktion = Unknown mode +Okänd klass = Unknown class +Okänd klubb med id X = Unknown club with id X +Om MeOS = About MeOS +Om MeOS – ett Mycket Enkelt OrienteringsSystem = About MeOS – a Much Easier Orienteering System +Omstart = Restart +Omstart i stafettklasser = Relay Restart +Omstartstid = Restart time +Omvänd jaktstart = Reversed pursuit +Oparad = Unpaired +Operationen misslyckades = Operation unsuccessful +Operationen stöds ej = Unsupported operation +Optimerar startfördelning = Optimizing start time distribution +Ordinarie anmälningsdatum = Last entry date +Ordinarie avgift = Normal fee +Organisation = Organization +Oväntad kontroll 'X' i bana Y = Unexpected control 'X' in course Y +Packar upp löpardatabas = Expanding runner database +Par- eller singelklass = Patrol or single class +Para ihop = Pair +Para ihop bricka X med en deltagare = Pair card X with a competitor +Parallell = Parallel +PatrolClubNameNames = Competitor's (or patrol's) club(s) +PatrolNameNames = Competitor's (or patrol's) name(s) +Patrull = Patrol +Patrull, 1 SI-pinne = Patrol, One card +Patrull, 2 SI-pinnar = Patrol, Two cards +Personer = Persons +Plac. = Place +Placering in = Place in +Plats = Place +Port = Port +Port för TCP = Port for TCP +Postadress = Postal address +Postkod = ZIP +Poäng = Points +Poäng in = Points in +Poängavdrag (per minut) = Point reduction (per minute) +Poängavdrag per påbörjad minut = Point reduction for each started minute +Poänggräns = Point limit +Prel. bomtid = Prel. time lost +Prel. placering = Prel. place +Prioritering = Prioritization +Prisutdelningslista = Prize Ceremony List +Programinställningar = Program Settings +Prolog + jaktstart = Prologue + pursuit +Publicera resultat = Publish Results +Publicera resultat och sträcktider på Eventor och WinSplits online = Publish results and split times on Eventor and WinSplits online +Publicera startlista = Publish Start List +Publicera startlistan på Eventor = Publish start list on Eventor +Publicerar resultat = Publishing results +Publicerar startlistan = Publishing the start list +PunchNamedTime = Named split time +PunchTime = Punch time +Punches = Punches +Radera = Delete +Radera listan från aktuell tävling = Delete list from this competition +Radera starttider = Erase Start Times +Radera tävlingen = Remove Competition +Radera vakanser = Delete Vacancies +Radiotider, kontroll = Radio times, control +Ranking = Ranking +Ranking (IOF, xml) = Ranking (IOF, xml) +Rapport inför = Report for +Rapporter = Reports +Rapportläge = Report Mode +Red. avg. efteranm = Red. late fee +Red. avgift = Reduced fee +Redigera deltagaren = Edit competitor +Redigera lista = Edit List +Redigera listpost = Edit list entry +Reducerad avg = Reduced fee +Reduktionsmetod = Reduction method +Region = Region +Relativ skalfaktor för typsnittets storlek i procent = Relative scale factor for the font face (percent) +Rep = Rope +Reparera vald tävling = Repair Selected Competition +Reparerar tävlingsdatabasen = Repairing competition database +Repdragningstid = Rope time +Repdragningstiden måste ligga före omstartstiden = The rope time must be before the restart time +Reserverade = Reserved +Resultat = Result +Resultat && sträcktider = Results && Splits +Resultat (STOR) = Results (LARGE) +Resultat - %s = Results - %s +Resultat - X = Results - X +Resultat banvis per klass = Result course-wise per class +Resultat efter klass och bana - X = Result by class and course - X +Resultat efter sträcka X = Results After Leg X +Resultat efter sträckan = Results after leg +Resultat för ett visst lopp = Results for a given race +Resultat lopp X - Y = Result race X - Y +Resultat per bana = Result by course +Resultat per bana - X = Result by course - X +Resultat, generell = Results, general +Resultat, individuell = Results, individual +Resultat, patrull = Results, patrol +Resultatkiosk = Result Kiosk +Resultatlista - %s = Results - %s +Resultatlista – inställningar = Results – settings +Resultatlistor = Results +Resultatutskrift = Print Results +Resultatutskrift / export = Print / Export Results +Rogaining = Rogaining +Rogaining, individuell = Rogaining, individual +Rogaining-poäng = Rogaining points +RogainingPunch = Punch, rogaining +Rubrik = Heading +Rulla upp och ner automatiskt = Scroll up and down automatically +Runner = Competitor +RunnerBib = Competitor's bib +RunnerCard = Card number +RunnerClassCoursePlace = Position on course within class +RunnerClassCourseTimeAfter = Time after on course within class +RunnerClub = Competitor's club +RunnerCompleteName = Complete name +RunnerCourse = Competitor's course +RunnerFamilyName = Last name +RunnerFinish = Competitor's finish time +RunnerGivenName = First name +RunnerLegNumberAlpha = Competitor's exact leg number +RunnerLegNumber = Competitor's grouped leg number +RunnerName = Competitor's name +RunnerPlace = Competitor's place +RunnerPlaceDiff = Competitor's place difference +RunnerRank = Ranking +RunnerRogainingPoint = Rogaining points +RunnerStart = Competitor's start time +RunnerStartNo = Competitor's start number +RunnerTempTimeAfter = Competitor's time after at selected control +RunnerTempTimeStatus = Competitor's time / status at selected control +RunnerTime = Competitor's time +RunnerTimeAfter = Competitor's time after +RunnerTimeAfterDiff = Competitor's time after difference +RunnerTimeLost = Competitor's lost time +RunnerTimePlaceFixed = Time when Competitor's place is set +RunnerTimeStatus = Competitor's time / status +RunnerTotalPlace = Competitor's total place +RunnerTotalTime = Competitor's total time +RunnerTotalTimeAfter = Competitor's total time after +RunnerTotalTimeStatus = Competitor's total time / status +RunnerUMMasterPoint = Uppsala möte, master points +SI X inläst. Brickan tillhör Y som saknar klass = SI X was read out. The card belongs to Y, who has no class +SI X inläst. Brickan är inte knuten till någon löpare (i skogen) = SI X was read out. The card is not bound to any runner (in forest) +SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen = SI X is already read out. Use interactive readout to read it again. +SI X är redan inläst. Ska den läsas in igen? = SI X is already read out. Read it again? +SI på = SI on +SI-dubbletter: %d = SI duplicates: %d +SOFT-avgift = SOFT fee +SOFT-lottning = Swedish draw method +Saknad starttid = Missing Start Time +Sammanställning = Summary +Sammanställning, ekonomi = Summary, economy +Sammanställning, klasser = Summary, classes +Samtliga deltagare tilldelades resultat = All competitors were assigned a result +Seedad lottning = Seeded start groups +Sekundär typ = Secondary type +Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? = The size of the selection and of the clipboard does not match. Paste anyway? +Semikolonseparerad (csv) = Semicolon separated (csv) +Sen avgift = Late fee +Sen red. avgift = Late red. fee +Server = Server +Server: [X] Y = Server: [X] Y +Sidbrytning mellan klasser = Page break +Sidbrytning mellan klasser / klubbar = Page break between classes / clubs +Simulera inläsning av stämplar = Simulate readout +Sista betalningsdatum = Payment due +Sista ordinarie anmälningsdatum = Last normal entry date +Sista start (nu tilldelad) = Latest start (assigned now) +Sista start (nu tilldelad): X = Last start (now assigned): X +Sista sträckan = Last leg +Ska X raderas från tävlingen? = Do you want to remove X from the competition? +Skalfaktor = Scale factor +Skapa en ny tävling med data från Eventor = Create a new competition with data from Eventer +Skapa en ny, tom, tävling = Create a new, empty, competition +Skapa fakturor = Create Invoices +Skapa generell lista = Create General List +Skapa listan = Create List +Skapa ny klass = Create new class +Skapad av = Created by +Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) = Created a course for the class %s with %d controls in card %d. +Skapade en lokal kopia av tävlingen = Created a local copy of the competition +Skapar ny etapp = Create new stage +Skapar ny tävling = Creating new competition +Skapar saknad klass = Created missing class +Skattad avgift = Taxable fee +Skippar lottning = Skip drawing start order +Skript = Script +Skript att köra efter export = Script to run after export +Skriv endast ut ändade sidor = Only print modified pages +Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben = Type the first letters of the club name and press down arrow to find the club. +Skriv första starttid på formen HH:MM:SS = Write the first start time as HH:MM:SS +Skriv ut = Print +Skriv ut alla = Print all +Skriv ut dem utan e-post = Print all missing e-mail +Skriv ut ej accepterade elektroniska = Print all not yet accepted +Skriv ut eller exportera listan automatiskt = Print or export the list automatically +Skriv ut fakturan = Print the invoice +Skriv ut listan = Print the list +Skriv ut nu = Print now +Skriv ut rapporten = Print the report +Skriv ut sträcktider = Print Splits +Skriv ut tabellen = Print the table +Skriv ut tabellen (X) = Print the table (X) +Skriv över existerande bricknummer? = Overwrite existing card number? +Skrivare = Printer +Skrivarinställningar för sträcktider = Printer settings +Skriver sträcktider om = Printing in +Slutresultat = Final Results +Slå ihop = Merge +Slå ihop klass: X = Merge class: X +Slå ihop klass: X (denna klass behålls) = Merge class with X (keep this class) +Slå ihop klasser = Merge Classes +Slå ihop klubb = Merge Club +SmallFont = Small text +SmallItalic = Small, italic text +Snabbinställningar = Quick Settings +SortNameOnly = Name +Sortering = Sorting +Sortering: %s, antal rader: %d = Sorting: %s, number of rows: %d +Spara = Save +Spara anmälningar = Save Entries +Spara den här listan som en favoritlista = Save this list as a favorite list +Spara fil = Save file +Spara för webben = Save web document +Spara i aktuell tävling = Save in This Competition +Spara som = Save as +Spara som fil = Save as File +Spara sträcktider till en fil för automatisk synkronisering med WinSplits = Save splits to file for automatic synchronization with WinSplits +Sparade listval = Stored Lists +Speaker = Speaker +Speakerstöd = Speaker Module +SportIdent = SportIdent +Språk = Language +Stad = City +Stafett = Relay +Stafett (sammanställning) = Relay (Summary) +Stafett - sammanställning = Relay - Summary +Stafett - sträcka = Relay - Leg +Stafett - total = Relay - Total +Stafettklasser = Relay classes +Stafettresultat, delsträckor = Relay results, legs +Stafettresultat, lag = Relay results, team +Stafettresultat, sträcka = Relay results, leg +Stafettresultat, sträcka (STOR) = Relay results, leg (LARGE) +Start = Start +Start nr = Start no. +StartTime = Start time, name +StartTimeForClass = Common start time, class +Starta = Start +Starta automaten = Start the Service +Starta en guide som hjälper dig göra klassinställningar = Start a guide that helps you setup classes +Startade automater = Started services +Startande = Starting +Startar SI på = Starting SI on +Startblock = Start block +Startblock: %d = Start block: %d +Startintervall = Start Interval +Startintervall (min) = Start interval (min) +Startlista = Start List +Startlista %%s - sträcka %d = Start List %%s - Leg %d +Startlista - %s = Start List - %s +Startlista - X = Start List - X +Startlista ett visst lopp = Start list for the race +Startlista lopp X - Y = Start List Race X - Y +Startlista, individuell = Start list, individual +Startlista, patrull = Start list, patrol +Startlista, stafett (lag) = Start list, relay (team) +Startlista, stafett (sträcka) = Start list, relay (leg) +Startlistor = Start lists +Startmetod = Start method +Startnamn = Start name +Startnummer = Start number +Starttid = Start time +Starttid (HH:MM:SS) = Start time (HH:MM:SS) +Starttid: X = Start time: X +Starttiden är upptagen = Start time is not available +Starttyp = Start type +Status = Status +Status OK = Status OK +Status in = Status input +Stoppa automaten = Stop the service +Stor = Large +Str. = Leg +Str. %d = Leg %d +String = Text +Struken = Canceled +Struken med återbetalning = Canceled, fee refunded +Struken utan återbetalning = Canceled, no refund +Strukturerat exportformat = Structured export format +Strukturerat webbdokument (html) = Structured web document (html) +Sträcka = Leg +Sträcka %d = Leg %d +Sträcka X = Leg X +Sträcka att lotta = Leg to draw +Sträckans banor = Courses of the leg +Sträcktider = Split Times +Sträcktider (WinSplits) = Split Times (WinSplits) +Sträcktider / WinSplits = Split Times / WinSplits +Sträcktider/WinSplits = Splits/WinSplits +Sträcktidsfil = File name +Sträcktidsutskrift = Print Splits +Sträcktidsutskrift[check] = Print splits automatically +Sträcktilldelning, stafett = Leg assignment, relay +Sträcktyp = Leg type +Stämpelkod(er) = Punch code(s) +Stämpelkoder = Punching codes +Stämplar om = Punching in +Stämplingar = Punches +Stämplingar saknas: X = Missing punches: X +Stämplingsautomat = Punch machine +Stämplingsintervall (MM:SS) = Punch interval (MM:SS) +Stämplingstest = Punching Test +Stämplingstest [!] = Punch Test [!] +Stäng = Close +Stäng tävlingen = Close Competition +Större = Larger +Störst = Largest +Största gruppen med samma inledning har X platser = Largest group with same course opening has X starters +Största intervall i klass = Greatest interval in class +SubCounter = Secondary counter +SubSubCounter = Tertiary counter +Summera = Sum +Synkronisera med Eventor = Synchronize with Eventor +Säkerhetskopiera = Backup / Save as +Sätt okända löpare utan registrering till = Set Status for Runners without Registration +Sätt som oparad = Unpair +Sätter reptid (X) och omstartstid (Y) för = Applying rope time (X) and restart time (Y) for +Sök = Search +Sök (X) = Search (X) +Sök deltagare = Find Competitor +Sök och starta automatiskt = Automatic Search and Start +Sök på namn, bricka eller startnummer = Search for a name, card or start number +Söker efter SI-enheter = Searching for SportIdent units +TCP: Port %d, Nolltid: %s = TCP: Port %d, Zero time: %s +TRASIG( = Bad( +Ta bort = Remove +Ta bort / slå ihop = Remove / Merge +Ta bort listposten = Remove list entry +Ta bort markerad = Remove Selected +Ta bort stämpling = Remove Punch +Ta bort valda rader från tabellen (X) = Remove selected rows from the table (X) +Tabell = Table +Tabelläge = Table Mode +Team = Team +TeamBib = Team's bib +TeamClub = Team's club +TeamLegTimeAfter = Team's time after on leg +TeamLegTimeStatus = Team's time / status on leg +TeamName = Team name +TeamPlace = Team's place +TeamRogainingPoint = Team's rogaining points +TeamRunner = Name of team member +TeamRunnerCard = Card number of team member +TeamStart = Team's start time +TeamStartNo = Team's start number +TeamStatus = Team status +TeamTime = Team's time +TeamTimeAfter = Team's time after +TeamTimeStatus = Team's time / status +Telefon = Phone +Test = Test +Test av stämplingsinläsningar = Test punching +Testa rösten = Test the voice +Text = Text +Text: X = Text: X +Textfiler = Text files +Textstorlek = Text size +Tid = Time +Tid efter: X = Time after: X +Tid efter: X; har tagit in Y = Time after: X; gained Y +Tid efter: X; har tappat Y = Time after: X; lost Y +Tid in = Time in +Tid: X, nuvarande placering Y/Z = Time: X, current place Y/Z +Tidsavdrag: X poäng = Point reduction: X points +Tidsgräns = Time limit +Tidsinmatning = Manual Times +Tidsintervall (MM:SS) = Time interval (MM:SS) +Tidsjustering = Time adjustment +Tidslinje – X = Time line – X +Tidsskalning = Time scaling +Till huvudsidan = To Main Page +Till kontroll = To control +Tilldela = Assign +Tilldela avgifter = Assign Fees +Tilldela endast avgift till deltagare utan avgift = Assign fee only to competitors without fee +Tilldela hyrbrickor = Assign cards +Tilldela nummerlappar = Assign bibs +Tilldelning av hyrbrickor = Assign Cards +Tillgängliga automater = Available services +Tillsatte vakans = Filled vacancy +Tillsätt vakans = Fill Vacancy +Tillämpa parstart = Start pairwise +Tillåt decimaler = Allow decimals +Tillåt direktanmälan = Allow quick entry +Tillåt valutauttryck med decimaler = Allow currency expressions with decimals +Topplista, N bästa = Top list, N best +Total = Total +Total tävlingsavgift = Total competition fee +TotalCounter = Primary counter +Totalresultat = Total result +Totalresultat - X = Total Results - X +Totalt = Total +Totalt faktureras = To invoice +Totalt kontant = Total cash +Totaltid = Total time +Trasig = Bad +Träning = Training +Tvåmannastafett = Two-runner relay +Typ = Type +Typ av delning = Split type +Typ av export = Type of export +Typ av lista = Type of list +Typsnitt = Typeface +Tävling = Competition +Tävling från Eventor = Competition from Eventor +Tävlingen innehåller inga resultat = There are no results yet +Tävlingen måste ha ett namn = The competition must be named +Tävlingens namn: X = The competition's name: X +Tävlingsdata har sparats = Competition data was saved +Tävlingsinställningar = Competition Settings +Tävlingsinställningar (IOF, xml) = Competition settings (IOF, xml) +Tävlingsnamn = Competition name +Tävlingsrapport = Competition Report +Tävlingsregler = Competition rules +Tävlingsstatistik = Competition Statistics +Underlag för tävlingsavgift = Data for competition fee +Underlista = Sub list +Underrubrik = Subheading +Undre datumgräns = Lower date limit +Undre gräns (år) = Lower limit (years) +Undre ålder = Lower Age +Ungdom = Youth +Ungdomsavgift = Youth fee +Ungdomsklasser = Youth classes +Uppdatera = Update +Uppdatera alla klubbar = Update All Clubs +Uppdatera alla värden i tabellen = Update table +Uppdatera alla värden i tabellen (X) = Refresh all values of the table (X) +Uppdatera från Eventor = Update from Eventor +Uppdatera fördelning = Update Distribution +Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan = Update the distribution of start times taking manual changes into account +Uppdatera klubbar && löpare = Update Clubs && Runners +Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret = Update clubs and runners using the runner database. +Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret = Update clubs using the runner database. +Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret = Update the club using the runner database. +Uppdatera löpardatabasen = Update Runner Database +Urval = Filter +Urval %c%s = Filter %c%s +Utan inställningar = No settings +Utan tidtagning = No timing +Utbyt tävlingsdata med Eventor = Exchange competition data with Eventor +Utför lottning = Perform the Drawing +Utfört = Done +Utg. = DNF +Utskrift / export = Print / export +Utskriftsintervall (MM:SS) = Printing interval (MM:SS) +Utökat protokoll = Extended protocol +VALFRI( = OneOf( +Vak. ranking = Vacancy ranking +Vakanser = Vacancies +Vakanser / klassbyte = Late Changes +Vakanser och efteranmälda = Vacancies and Late Entries +Vakanser stöds ej i stafett = Vacancies not supported in relays +Vakant = Vacant +Val av export = Choose export +Valbar = Optional +Vald bricka = Chosen card +Valuta = Currency +Valutakod = Currency code +Valutasymbol = Currency symbol +Valutasymbol före = Currency symbol in front +Varning: Deltagaren 'X' finns inte = Warning: The competitor 'X' does not exist +Varning: Laget 'X' finns inte = Warning: The team 'X' does not exist +Varning: Banan 'X' finns inte = Warning: The course 'X' does not exist +Varning: Banan 'X' förekommer flera gånger = Warning: The course 'X' is specified more than once +Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) = Warning: No organizer given (See Competition Settings) +Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Warning: No account given (See Competition Settings) +Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) = Warning: payment due not given (See Competition Settings) +Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Warning: A competitor without name was found. MeOS requires a name, and has assigned the name 'N.N.' +Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Warning: A team without name was found. MeOS requires a name and has assigned the name 'N.N.' +Verkställ = Confirm +Version X = Version X +Vi stöder MeOS = We support MeOS +Viktiga händelser = Important events +Vill du flytta löpare från X till Y och ta bort Z? = Do you want to move runners from X to Y and remove Z? +Vill du klistra in X nya rader i tabellen? = Do you want to paste X new rows into the table? +Vill du lägga till banan 'X' (Y)? = Do you wish to add the course 'X' (Y)? +Vill du lägga till deltagaren 'X'? = Do you wish to add the competitor 'X'? +Vill du lägga till klassen 'X'? = Do you wish to add the class 'X'? +Vill du lägga till laget 'X'? = Do you wish to add the team 'X'? +Vill du radera X rader från tabellen? = Do you want to delete X rows from the table? +Vill du radera alla vakanser från tävlingen? = Do you want to remove all vacancies from the competition? +Vill du skapa en ny klass? = Do you want to create a new class? +Vill du spara ändringar? = Do you want to save changes? +Vill du verkligen radera alla starttider i X? = Do you really want to clear start times in X? +Vill du verkligen radera starttider i X klasser? = Do you really want to erase start times from X classes? +Vill du verkligen radera tävlingen? = Do you wish to remove the competition? +Vill du verkligen stänga MeOS? = Do you wish to close MeOS? +Vill du verkligen ta bort laget? = Do you with to remove the team? +Vill du verkligen ta bort löparen? = Do you wish to remove the runner? +Visa = Show +Visa alla = Show All +Visa avancerade funktioner = Show advanced settings +Visa en tabell över alla stämplingar = Show a table with punches +Visa klubbdatabasen = Show club database +Visa listan i fullskärm = Show the list in full screen +Visa löpardatabasen = Show runner database +Visa mellantider = Show split times +Visa och hantera löpardatabasen = Show and manage runner database +Visa senast inlästa deltagare = Show last read out competitor +Visa startlistan = Show start list +Visa tillgängliga säkerhetskopior = Show available backups +Visa valda deltagare = Show Selected Competitors +Visar de X bästa = Showing top X +Visualisera startfältet = Visualize Start Field +Vuxen = Adult +Vuxenklasser = Adult classes +Vuxna = Adults +Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad = Click to store the cards. Interactive readout is not activated +Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad = Click to store the cards. Interactive readout is activated +Välj alla = Select All +Välj alla klasser = Select all classes +Välj allt = Select All +Välj automatiskt = Automatic Selection +Välj den etapp som föregår denna tävling = Select the stage preceding this stage +Välj den etapp som kommer efter denna tävling = Select the stage following this stage +Välj en vakant plats nedan = Choose a vacant position below +Välj ingen = Select None +Välj inget = Select None +Välj klass = Select class +Välj klass och starttid nedan = Choose class and start time below +Välj klasser = Choose classes +Välj klasser där alla löpare saknar starttid = Select classes where no runner has a start time +Välj klasser där någon löpare saknar starttid = Select classes where some runner misses start time +Välj kolumner = Choose Columns +Välj kolumner att visa = Choose columns to show +Välj kolumner för tabellen X = Choose columns for the table X +Välj lista = Select list +Välj lopp = Select race +Välj löpare = Choose runner +Välj löpare att prioritera bevakning för = Select runners to prioritize +Välj löpare för sträcka X = Set runner for leg X +Välj skrivare = Choose printer +Välj tävling = Choose competition +Välj vilka klasser och kontroller du vill bevaka = Select Classes and Controls you want to watch +Välj vilka klasser och kontroller som bevakas = Select which classes and controls to watch +Välj vilka kolumner du vill visa = Choose columns to show +Välj vy = Choose view +Välkommen till MeOS = Welcome to MeOS +Vänligen betala senast = Please pay at latest +Vänligen återlämna hyrbrickan = Please return your borrowed card +Växling = Changeover +Webb = Web Document +Webbdokument = Web document +Webbdokument (html) = Web document (html) +Webben (html) = The web (html) +X (Saknar e-post) = X (Has no e-mail) +X (Y deltagare, grupp Z, W) = X (Y competitors, group Z, W) +X har startat = X started +X kontroller = X controls +X meter = X meter +X poäng fattas = X points missing +X rader kunde inte raderas = X row(s) could not be deleted +X senaste = X latest +X: Y. Tryck för att spara = X: Y. Press to save +Zooma in (Ctrl + '+') = Zoom in (Ctrl + '+') +Zooma ut (Ctrl + '-') = Zoom out (Ctrl + '-') +[Bevaka] = [Watch] +[Flytta ner] = [Move down] +[Bort] = [Remove] +[Klassens bana] = [From Class] +[Uppdaterad anmälan] = [Updated entry] +[VARNING] ingen/okänd = [VARNING] none/unknown +[Återställ] = [Reset] +andra = second +ask:addpunches = No card has been read out for this runner. Would you like to add punches manually? +ask:changedclassfee = The entry fee was modified in some classes. Do you want to apply the new fees to existing runners in these classes?\n\nWarning: Manually assigned fees will be overwritten. +ask:changedcmpfee = The entry fees are modified. Do you want to apply the new fees on existing runners and classes?\n\nWarning: Manually assigned fees will be overwritten. +ask:firstasstart = There exist runners with result for this course. If you use the first control as start, the start times will be overwritten.\n\nDo you wish to continue? +ask:kiosk = When you start a result kiosk, you put MeOS in a mode where it is only possible to show result reports. No other operations are permitted until the program is restarted. If there is an active SI device connected to the computer, MeOS will automatically show results for the last read card.\n\nYou should consider protecting the database with a password, if you publicly expose a result kiosk.\n\nDo you wish to start a result kiosk? +ask:missingcourse = Some classes (X) have no course.\n\nMeOS use the courses when drawing to avoid that runners with the same first controls start at the same time.\n\nDo you wish to proceed anyway? +ask:overwrite_server = The competition is already on server. Do you want to overwrite the competition on the server? +ask:overwriteconfirm = You have chosen to overwrite the competition. Make sure no one else is connected.\n\nDo you wish to proceed? +ask:repair = Repair the database only if you experience problems.\n\nImportant:\n- Make sure no one else is connected to the database.\n- If the server crashes or goes down while repairing, you must restart it and retry the repair before doing anything else. If you make any other operation with the database all data will be lost.\n\nDo you wish to try a repair operation now? +backup = backup +c/o = c/o +check (X) = a check (X) +ej aktiv = not active +elfte = eleventh +elva = eleventh +ett Mycket Enkelt OrienteringsSystem = a Much Easier Orienteering System +eventor:help = If you use MeOS for orienteering in Sweden, we recommend that you use MeOS's Eventor connection. +eventor:question = X\n\nDo you wish to use the Eventor connection? +femma = fifth +femte = fifth +fjärde = fourth +fritt att använda och du är välkommen att distribuera det under vissa villkor = free to use and you are welcome to redistribute it under certain conditions +fyra = fourth +går i mål på X plats med tiden Y = finishes as X with time Y +går i mål på X plats, efter Y, på tiden Z = finishes as X, behind Y, with time Z +går upp i delad ledning med tiden X = takes a shared lead with the time X +handskakning = hand shaking +har startat = has started +help:10000 = A service in MeOS is a small program that automatically does something every now and then or when the competition data is changed. +help:12138 = Select a class to merge with the this class. If start times are drawn you might want to draw again, since the runners keep their start times. +help:12290 = The competition is created by another version of MeOS and cannot be opened from a server. You can however import the competition from file. +help:12352 = This operation removes the club you have chosen (%s, id=%d) and moves all runners of that club to the new club you choose below. The operation cannot be undone. +help:12662 = Add controls by adding a sequence of control numbers (control id numbers). You need not specify the finish. Example: 31, 50, 36, 50, 37, 100. +help:14070 = The TCP port is used for receiving punches over TCP from other systems. Specify the port used. The zero time of the protocol is 00:00:00. +help:14343 = A list with read card is shown. To tie a runner to another card, double click the card or runner you wish to move. +help:146122 = You can extend MeOS knowledge of runners, clubs and classes by searching databases in MeOS format or the IOF (xml) format.\n\nDo you wish to proceed? +help:14692 = Input control number, runner (start number or card number) and clock time (HH:MM:SS). You may leave the time field blank; then the computer clock is used. Press to save. +help:15491 = You can export settings, club and runner databases to a specified folder. This settings and databases can be imported to another computer. +help:21576 = If you make a mistake, click the runners name to change the entry. Use the page runners to remove entries. To see a class in the list below, it must be marked for quick entry on the page classes. +help:25041 = Here you define your courses. A course is then tied to one or more classes (or runners). It is also possible to import courses from OCAD, Condes, or other course software. If you specify the number of maps, MeOS will keep track of available maps in the quick entry form. +help:26963 = A course pool is used for defining a pool of courses for a leg. The course is tied to the runner on finish by control matching. Define courses in the pool by adding them under Several Courses / Relay. An [S] after the class means that all its competitors has a start time. +help:29191 = You can install settings, clubs and runner database from a specified source folder. Your local settings are overwritten. MeOS might be restarted after the installation.\n\nThe button takes you to a page where instead you can export your current settings. +help:29758 = Here you manage clubs and print invoices. You can assign competition fees based on class type and entry date. Duplicated (misspelled) clubs can be merged with the corresponding correct club. You can also update club addresses from the registry. +help:30750 = You can create many different sorts of lists and reports. These can be shown on screen, printed, or saved in web format. The list is automatically updated when competition data is changed. Automatic result printing is done on the page Services. To export competition data, for example split times, go to the page Competition. +help:31661 = A restart is defined by a rope time and a restart time. At the rope time, the changeover is closed and no competitors are let out into the forest. The remaining runners start at the rope time. It is possible to specify different times for individual legs, but by using this function you can quickly handle whole classes. +help:33940 = Import entries in free text format. Specify name, club, class, and card number (possibly also start time), preferably separated by comma, one person (team) per row. It is also possible to specify many competitors in the same club / class by partly leaving out these fields. It is also possible to import data formatted in other ways. +help:41072 = Select a punch from the list to change or remove it. You can add missing punches from the course template. If the finish time is missing, the runner gets status . If a punch is missing, the status is . It is not possible to assign a status incompatible with the punches. If there is a finish punch, you must modify it to set a manual finish time. The same principle applies for the start punch. +help:41641 = Enter a first start time and start interval. Draw random gives an unconditionally random start order. Swedish draw method uses special rules to distribute runners from the same club. Clumped start means the whole class starts in small groups during the specified interval (extended mass start). In the field leg, you can specify which leg is to be drawn, if the class has several. +help:425188 = You can handle runners that didn't start automatically by reading out SI stations (clear/check/start/controls) in SIConfig. Save the readout as a semi colon separated text file and import this file into MeOS. Runners in this import get a registration. Then you can give DNS status to all runners without registration. If you later import more runners, you can reset the status (from DNS to Unknown) on the runners now imported. +help:471101 = Activate the SI unit by selecting its COM-port, or by searching for installed SI units. Press Information to get status for the selected port.\n\nInteractive readout lets you directly handle problems, such as wrong card number. Do not use this option when runners with problems are handled separately.\n\nThe runner database is used if you want to automatically add new runners. The punches are used to find (guess) the right class. +help:50431 = You are now connected to a server. To open a competition on the server, select it in the list and click open. Do add a competition to the server, open the competition locally and select upload. When you have opened a competition on the server, you will see all other connected MeOS clients. +help:52726 = Connect to a server below.\n\nInstallation\nDownload and install MySQL 5 (Community Edition) from www.mysql.com. You can use default settings. It is only necessary to install MySQL on the computer acting server. When MySQL is installed, start MySQL Command Line Client and create a user account for MeOS. You write like this:\n\n> CREATE USER meos;\nGRANT ALL ON *.* TO meos;\n\nYou have now created a user meos with no password. Enter the name of the server below (you may have to configure firewalls to let through the traffic).\n\nAs an alternative you can use the built-in root account of MySQL. User name is 'root' and password is the one you provided when installing MySQL. +help:5422 = Found no SI unit. Are they connected and started? +help:59395 = In this form, you can quickly make basic settings for many classes in one step.\n\nStart is the name of the start as it is printed in the start list.\n\nBlock is a number between 0 and 100 which can provide an even finer distribution of runners. Classes in the same block will be printed on the same minute start list. \n\nIndex is a sorting key. The classes are sorted by this key in all lists.\n\nThe course can be specified for classes which have exactly one course; if there are several possible courses you need to use the standard class form.\n\nQuick entry determines if the class supports quick entry mode, i.e., is a possible choice in the quick entry class list. +help:59395_more = The class fees, which shows if you have activated Economy features, are used for new entries. If you change a fee, MeOS will ask if you wish to apply the change to existing competitors.\n\nFor bibs you have the options None, Consecutive and Manual. You can also type the first bib in the class, for example A100, or 50. Consecutive means that the last number of the preceeding class is used to define the first number in this class. Reserved bib numbers gives a gap (of the specified width) in the numbering between classes.\n\nMeOS updates bibs when you draw start times or change the settings. Manual means that MeOS will never automatically update bibs.\n\nFor classes with teams the setting Team member controls the relation between the team number and the bibs. It can be the same, increasing (100, 101, 102), leg dependent (100-1, 100-2, etc.) or completely independent. +help:7618 = The number of runners in a team is specified on the page Classes. +help:7620 = Interval (seconds). Leave the field blank to update when the competition is changed. +help:89064 = For every control, you specify one or more code number (SI codes). In a course, you refer to the control by its ID number. Usually, you do not need to add controls manually, since MeOS automatically adds all controls needed.\n\nMore than one SI code is useful for replacing malfunctioning controls or to create simple forks. For an ordinary control, it is required that the runner visit on of the specified controls. If the control status is , all specified controls must be visited (in any order). If the status is , the control is ignored.\n\nIf you specify a control name, it is possible to print result lists with intermediate times at named controls.\n\nTime adjustment can be used if it turns out that a control has wrong time. Time format is +/-MM:SS or +/-HH:MM:SS.\n\nShortest leg time defines the shortest possible time on that leg. No runner will get a shorter time to this control, no matter how fast he/she is. This can be used, for example, if a dangerous road must be crossed.\n\nStatus means that the time to the control is ignored; the total time will be the same no matter what the actual time to this control is. +help:9373 = Give one or more control numbers (SI codes) used by this control.\nExample: 31, 32, 33. +help:9615 = Received no answer. Do you want to open the port in passive mode; should MeOS listen to incoming punches? +help:assignfee = MeOS will take care of entry fees for you automatically in many cases. The competitors are assigned fees based on age and entry date (you define the limits under Competition Settings). Every class defines its fees. You provide default values for different class types under Competition Settings, but you can also manually change class settings using Quick Settings for the class.\n\nThis page lets you manually use different ages and time limits for different fees. On the page competitor, you can manually adjust the fee for individual competitors, if needed. +help:baudrate = Transmission speed/Baudrate: use 4800 or 38400. +help:computer_voice = An incoming punch is matched against a start number and plays the file , where N is the start number. The files are located in the folder below. If the runner/team belongs has nationality NAT, MeOS first tries to play the file , which should contain the number in an appropriate language version. +help:dbage = The runner database is older than two months. Do you wish to download a new database from Eventor? +help:duplicate = Make a local copy of this competition. +help:eventorkey = Type your club's Eventor (Sweden) API key. You get the key from your club's Eventor administrator. +help:fullscreen = You can adjust the scroll speed using Ctrl+M (increase) and Ctrl+N (decrease) on your keyboard. To escape full screen mode, press Esc. +help:import_entry_data = You can import runners, classes, clubs and entries from a number of different text and XML formats. It is not necessary to provide all files below. For example, an OE-CSV file with entries contains clubs and classes, so in that case these fields should be left empty.\n\nIf the same runner is imported several times you will not get several copies of the runner. Instead the entry is updated. This means that it is harmless to re-import or import an extended file with entries. +help:importcourse = You can import courses and classes from (for example) an OCAD or Condes export. +help:ocad13091 = If you have access to the courses (for example, from OCAD or Condes) you can provide the name of the course file here. Otherwise, you may add courses later. +help:relaysetup = Use the guide below to choose between a number of predefined competition forms. After you apply the settings, it is possible to manually adapt the settings for each leg and setup courses.\n\nSome explanations:\n- Relay is used for different kinds of relays.\n- Two-runner relay means that two runners make a team and take turns running.\n- Co-runner relay is sometimes used in youth classes and allow for more than one runner on some legs. (the first runner changes over).\n- A patrol race can be run with one or two punching cards.\n- Prologue + pursuit is individual, but with two races.\n- Course pool means there are several course variants, but that it is not decided in advance who runs which course; it is decided automatically when the runner finishes. +help:restore_backup = Choose a backup to restore by clicking the time when the backup was created. +help:runnerdatabase = By importing a runner and club database, MeOS will automatically recognize unknown runners (by card number), and you will get addresses and phone numbers to clubs. +help:save = MeOS automatically saves all settings when needed. +help:speaker_setup = Choose which classes and courses you want to watch. +help:speakerprio = Check those runners/teams you wish to watch from start, and as long as the runner/team is doing well. Put two checks to watch even if the result is not so good. No check means monitoring only if the runner/team is doing well (not from start). +help:splitexport = Decide if you want to export total results, or individual results for each race. If you choose to export all races, numbered files will be created. +help:startmethod = MeOS will automatically apply the chosen start method. No matter what you choose here, you can always change start method or redraw lists later. +help:winsplits_auto = This service saves split times to an IOF (xml) file at regular intervals. If you open this file in WinSplits, the splits there will be updated live. +help:zero_time = Set zero time to one hour before first planned start. +help:long_times = Competition date is the date when all classes start. Zero time is at midnight. +help_autodraw = Provide a first (ordinary) start time, a least start interval (within a class) and the fraction of vacancies. You can also choose the method use when drawing and if late entries are to start in front of or after the ordinary entries. The first start time must be after the zero time of the competition.\n\nIf you click , MeOS will inspect all classes. If the class is not drawn, it will be, if there are late entries without start time in a class, these will be drawn.\n\nMeOS ensures that runners with similar courses do not start simultaneously, and space will be reserved to allow for late entries under the same conditions.\n\nIf you instead click you will be able to control exactly which classes are drawn and with which parameters. +help_draw = You draw the start list in a two-step process. First you choose which classes to draw and you make some basic settings. When you press MeOS will use your settings to distribute start time slots between classes. MeOS ensures that classes with similar courses do not start at the same time, taking already drawn classes into account. A goal is an even distribution of starters.\n\nThe calculated distribution is presented in a table, where you can make your own changes, or let MeOS update its distribution, taking your changes into account. When you are happy with the distribution, you let MeOS draw the selected classes.\n\nThe basic settings you have to make is to provide a first allowed time to start and a smallest allowed interval. The maximal number of parallel starts determines how many runners can start at the same time. An increased value gives a shorter start depth.\n\nThe fraction of vacant positions controls the number of vacant positions. If you need no vacancies, type 0%. The expected number of late entries reserves space for these in the start list with a guarantee that no runner starting on the same time will have the same course. +info:multieventnetwork = To handle more than one stage you must work locally. Save a copy of the competition, open it locally and transfer results to the next stage. Then upload the next stage to the server. +info:readout_action = X: Card no. Y was read out.\nManual actions needed. +info:readout_queue = X: Card no. Y was read out.\nThe card has been queued. +inforestwarning = No runners seems to be in the forest. Since the data behind this conclusion might be incorrect, you should verify that no runner is left in the forest by other means. +kartor = maps +klar = settled +kontroll = control +kontroll X (Y) = control X (Y) +localhost = localhost +lopp = race +mål = finish +målet = the finish +målet (X) = the finish (X) +nia = ninth +nionde = ninth +radio X = radio X +saknas = missing +se license.txt som levereras med programmet = see license.txt which is delivered with the software +serverbackup = server backup +sexa = sixth +sjua = seventh +sjunde = seventh +sjätte = sixth +skicka stämplar = send punches +sortering: X, antal rader: Y = sort order: X, number of rows: Y +starten (X) = the start (X) +sträcka X = leg X +stämplade vid = punched at +stämplar vid X som Y, på tiden Z = punches at X as Y, with time Z +tar ledningen med tiden X = takes the lead with time X +tia = tenth +till = to +tionde = tenth +tolfte = twelfth +tolva = twelfth +tooltip:analyze = Analyze data and preview import. +tooltip:builddata = Extend MeOS knowledge of runners, clubs, and classes by analyzing competition data. +tooltip:import = Import entries from file. +tooltip:inforest = List of runners in forest and runners that did not start. +tooltip:paste = Paste entries from clip board. +tooltip:resultprint = Print results to put on display +tooltip:voice = Computer voice reading forewarnings. +trea = third +tredje = third +tvåa = second +väntas till X om någon minut = is soon expected to X +väntas till X om någon minut, och kan i så fall ta en Y plats = is expected to X in a minute, and can take a Y place +väntas till X om någon minut, och kan i så fall ta ledningen = is expected to X in a minute, and can take the lead +växeln = the changeover +växlar på X plats med tiden Y = changes over as X with time Y +växlar på X plats, efter Y, på tiden Z = changes over at a X place, after Y, with time Z +växlar på delad X plats med tiden Y = changes over as X with time Y +warn:changedtimezero = Changing the zero time for a competition with results is not recommended.\n\nDo you wish to proceed anyway? +warn:olddbversion = The database is in use by a later version of MeOS. Upgrading is recommended. +warning:dbproblem = WARNING. Problems with database connection: 'X'. The connection will automatically be restored. Continue to work normally. +warning:drawresult = The class already has results, start times will be overwritten. Do you want to proceed? +warning:has_entries = The class already has runners. Changing the leg distribution at this stage, may cause data loss.\n\nDo you wish to proceed? +warning:has_results = The class already has results. Changing the leg distribution at this stage is unusual.\n\nDo you wish to proceed? +xml-data = xml data +Äldre protokoll = Old protocol +Ändra = Change +Ändra grundläggande inställningar och gör en ny fördelning = Modify basic settings and make a new distribution +Ändra inställningar = Modify Settings +Ändra klassinställningar = Change Class Settings +Ändra lag = Change team +Ändra sträckindelning = Modify Leg Setup +Ändrad = Modified +Ändrade avgift för X deltagare = Modified fee for X competitor(s) +Åldersfilter = Age filter +Åldersgräns ungdom = Age limit, low +Åldersgräns äldre = Age limit, high +Åldersgränser, reducerad anmälningsavgift = Age limits, fee reduction +Ångra = Undo +Återansluten mot databasen, tävlingen synkroniserad = Reconnected to database, competition synchronized +Återbud = Drop Out +Återgå = Return +Återställ = Revert +Återställ / uppdatera klasstillhörighet = Reset / update competitor's class +Återställ löpare med registrering till = Reset Status to for Runners with Registration +Återställ säkerhetskopia = Restore Backup +Återställ tabeldesignen och visa allt = Restore table design +ÅÅÅÅ-MM-DD = YYYY-MM-DD +Öppen = Open +Öppen klass = Open class +Öppna = Open +Öppna fil = Open File +Öppna från aktuell tävling = Open from This Competition +Öppna föregående = Open Preceding +Öppna föregående etapp = Open preceding stage +Öppna i ett nytt fönster = Open in a new window +Öppna klasser, ungdom = Open classes, youth +Öppna klasser, vuxna = Open classes, adults +Öppna nästa = Open Next +Öppna nästa etapp = Open next stage +Öppna tävling = Open Competition +Öppna vald tävling = Open selected competition +Öppnad tävling = Opened competition +Överför anmälda = Transfer entires +Överför nya deltagare i ej valda klasser med status "deltar ej" = Transfer new competitors in remaining classes with status +Överför resultat = Transfer results +Överför resultat till X = Transferring results to X +Överför resultat till nästa etapp = Transfer Results to the Next Stage +Övre datumgräns = Upper date limit +Övre gräns (år) = Upper limit (years) +Övre ålder = Upper age +Övriga = Other +är först i mål med tiden X = is first to the finish with time X +är först vid X med tiden Y = is first at X with time Y +är först vid växeln med tiden X = is first to the changeover with time X +är inte godkänd = is disqualified +återställd = restored +åtta = eight +åttonde = eighth +Kopia (X) = Copy (X) +Tillåt samma bana inom basintervall = Allow same course within base interval +Välj X = Select X +Ett startblock spänner över flera starter: X/Y = A start block spans more than one start: X/Y +Bricka X = Card X +RunnerTimePerKM = Speed min/km +X är inget giltigt sträcknummer = X is not a valid leg number +Listan togs bort från tävlingen = List was removed from the competition +Töm = Clear +Status matchar inte deltagarnas status = The status does not match runner status. +Status matchar inte data i löparbrickan = The status does not match data in punching card. +Döp om = Rename +går upp i delad ledning vid X med tiden Y = shares the lead at X, time Y +X:e = X:th +tar ledningen vid X med tiden Y = takes the lead at X, time Y +Eventor server = Eventor server +(har stämplat) = (has punched) +documentation = meos_doc_eng.html +Hittar inte hjälpfilen, X = Cannot find documentation, X +X har redan ett resultat. Vi du fortsätta? = X already has a result. Do you wish to continue? +Aktuell tid = Current time +Godkänd = OK +Nummerlapp, SI eller Namn = Bib, card number, or name +Utgått = DNF +Manuell inmatning = Manual input +Tilldelad = Assigned +Eventors tider i UTC (koordinerad universell tid) = Eventor times in UTC (Universal Coordinated Time) +Exportera tider i UTC = Export times in UTC +Tidszon = Time Zone +RunnerAge = Competitor's age +RunnerBirthYear = Competitor's year of birth +RunnerFee = Competitor's fee +RunnerNationality = Competitor's nationality +RunnerPhone = Competitor's phone number +RunnerSex = Competitor's sex +TeamFee = Team's fee +Varning: ändringar i X blev överskrivna = Warning: Changes in X was overwritten +help:simulate = This service lets you simulate readout of SI cards. Times and punches are generated for all runners. Also radio contol punches can be simulated.\n\nWARNING: Use for testing only. If you use this on a real event, it will be corrupted. +Rogainingresultat - %s = Rogaining results - %s +TeamPlaceDiff = Team's place difference (this stages) +TeamTotalPlace = Team's summed place (all stages) +TeamTotalTime = Team's summed time (all stages) +TeamTotalTimeAfter = Team's summed time after (all stages) +TeamTotalTimeDiff = Team's summed time after difference (this stage) +TeamTotalTimeStatus = Team's summed time or status (all stages) +Vill du dumpa aktuellt tävling och skapa en testtävling? = Do you want to dump the current competition and create a test competition? +Radera alla klubbar = Delete All Clubs +Radera alla klubbar och ta bort klubbtillhörighet = Remove all clubs and clear club memberships +Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa = Do you wish to remove all clubs from the competition? No competitor will have a club. +Besökare = Visitors +Föregående kontroll = Preceding control +Ja = Yes +Nej = No +På banan = On course +Stämpelkod = Control code +Tidpunkt = Time +Antal deltagare = Competitors +Förekomst = Occurrence +Exporterar om = Exporting in +Exportformat = Export format +Filnamnsprefix = Filename prefix +Mapp = Folder +Mappnamnet får inte vara tomt = Folder name cannot be empty +Onlineresultat = On-Line Results +Packa stora filer (zip) = Compress large files (zip) +Publicera resultat direkt på nätet = Publish results directly on the web +Resultat online = Results On-Line +Skicka till webben = Send to the web +Spara på disk = Save to disk +Till exempel X = For example X +Tävlingens ID-nummer = Competition ID number +URL = URL +URL måste anges = URL missing +Tidsintervall (sekunder) = Time interval (seconds) +Antal skickade uppdateringar X (Y kb) = Number of updates X (Y kb) +Filen finns redan: X = Destination already exists: X +Misslyckades med att ladda upp onlineresultat = Failed to upload on-line results +Onlineservern svarade felaktigt = Remote server gave unexpected reply (Incorrect configuration?) +Onlineservern svarade: ZIP stöds ej = Response from remote server: ZIP not supported. +Onlineservern svarade: Serverfel = Response from remote server: Server error +Onlineservern svarade: Felaktigt lösenord = Response from remote server: Wrong password +Onlineservern svarade: Felaktigt tävlings-id = Response from remote server: Wrong competition id +Online Results Error X = On-Line Results Error X +PDF = PDF +ClassTeamLeg = Class, team, leg +Okänd = Unknown +Antal hämtade uppdateringar X (Y kb) = Number of received updates X (Y kb) +Använd ROC-protokoll = Use ROC protocol +Definierade mappningar = Defined mappings +Funktion = Function +Hämta stämplingar m.m. från nätet = Fetch punches etc. from the Internet. +Inmatning online = Remote Input +Kod = Code +Kontrollmappning = Control Mapping +Ogiltig funktion = Invalid function +Ogiltig kontrollkod = Invalid control code +Onlineinput = Remote input +Online Input Error X = Remote Input Error X +Ekonomi = Economy +Fakturainställningar = Invoice Settings +Hantera klubbar = Manage Clubs +Spara som PDF = Save as PDF +Avgifter och valuta ställer du in under = Fees and currency settings are changed from +Fakturanummer = Invoice number +Formatering = Formatting +Första fakturanummer = First invoice number +Koordinater (mm) för adressfält = Coordinates (mm) for address field +Organisatör = Organizer +Tilldela nya fakturanummer till alla klubbar? = Assign new invoice numbers to all clubs? +Exportera alla till PDF = Export all to PDF +help:onlineresult = The service is used to automatically send results and start lists to the Internet for immediate publication in some form. You need to make settings adapted to the remote service you want to user: the provider of the remote service can give you necessary details.\n\nIf you want to develop you own services, you can find documentation and examples on MeOS web site: www.melin.nu/meos. +help:onlineinput = The service is used to receive radio punches from the Internet, for example a radio control connected via a mobile phone. It is also possible to construct a simple web form, where you can manually enter the bib number of runners as the pass by.\n\nThe service protocol also supports other types of data entry, such as team line-up, direct entries, card changes etc. If you want to develop you own services, you can find documentation and examples on MeOS web site: www.melin.nu/meos. +Egna textrader = Custom text lines +Inga bommar registrerade = No control mistakes detected +Inställningar sträcktidsutskrift = Print Split Times Settings +Med km-tid = Include tempo (min/km) +Tidsförluster (kontroll-tid) = Time loss (control/time) +Underlag saknas för bomanalys = No data for control mistakes +min/km = min/km +X har redan bricknummer Y. Vill du ändra det? = X already has card number Y. Do you want to change it? +Avmarkera 'X' för att hantera alla bricktildelningar samtidigt = Uncheck 'X' to handle all card assignments on one page +Bricknr = Card number +Knyt automatiskt efter inläsning = Auto assign on readout +Knyt bricka / deltagare = Assign Card to Competitor +Nummerlapp, lopp-id eller namn = Bib, race id, or name +Lopp-id = Race Id +Markera 'X' för att hantera deltagarna en och en = Check 'X' to handle competitors one by one +Installerbara listor = Installable Lists +Listor i tävlingen = Lists in the Competition +Radera permanent = Delete Permanently +Tillgängliga listor = Available lists +Vill du ta bort 'X'? = Do you want to remove 'X'? +classcourseresult = Results class and course-wise +Hantera egna listor = Manage Custom Lists +Redigera = Edit +Skriver sträcktider när tävlingsdata ändras = Writing file when competition data is changed +Bana med slingor = Course with loops +En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning = A course with loops allow the competitor to take the loops in any order +Varvningskontroll = Common control +warn:notextended = INFO: Program the unit with extended protocol in SI.Config to speed up card reading. +help:DirectResult = - If there is no course, the status is set to OK on finish punch.\n\n- If there is a course, radio punches are used as controls. No card readout is necessary. +Resultat vid målstämpling = Result on finish punch +Stämpling = Punch +Skicka och ta emot snabb förhandsinformation om stämplingar och resultat = Send and receive fast advance information on control punches and results +Centrera = Center +Färg = Color +Höger = Right +PunchControlCode = Control code +PunchControlNumber = Punch code +PunchControlPlace = Place, leg to control +PunchControlPlaceAcc = Place, total after control +PunchLostTime = Time lost at control +Slå ihop text med föregående = Merge with previous +Textjustering = Text adjustment +Vänster = Left +X (press Ctrl+Space to confirm) = X (press + to confirm) +Press Enter to continue = Press to continue +ask:overwriteresult = X already has a result. Do you want to overwrite it? +Brickan används av X = The card is used by X +DATABASE ERROR = DATABASE ERROR +Lyssnar på X = Listening to X +vid kontroll X = at Control X +info:runnerdbonline = Since you are connected to a server, it is not possible to edit the club and runner databases manually. Make changes before uploading the competition to a server. It is also possible to replace the existing database on the server by importing a new database (from IOF XML). +ask:cleardb = Do you want to clear the runner and club databases? +Banan saknar rogainingkontroller = The course has no defined rogaining controls +Banans kontroller ger för få poäng för att täcka poängkravet = The rogaining controls awards too few points to cover the requirement +CustomSort = Custom order +Brickhantering = Handle Cards +HTML med AutoRefresh = HTML with AutoRefresh +Importera laguppställningar = Import Team Line-Ups +MeOS Funktioner = MeOS Features +Målfil = Destination file +Spara tid = Save time +Stämplingstid = Punching time +Data from result module (X) = Data from result module (X) +Forkings = Forkings +Forkings for X = Forkings for X +Gruppera = Group +Resultatuträkning = Result calculation +RunnerRogainingPointTotal = Competitor's total points +Show forking = Show Forking +Standard = Standard +TeamRogainingPointTotal = Team's total points +The forking is fair = The forking is fair +Underfilter = Sub Filter +Ogiltigt lag på rad X = Invalid team on row X +Okänd klass på rad X = Unknown class on row X +Klassen X är individuell = The class X is individual +Använd befintliga deltagare = Use competitors already in competition +Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka) = Group already existing competitors to the team (identified by name and/or card number) +Laguppställning = Team Line-up +Bakåt = Back +Bibs = Bibs +Club and runner database = Club and runner database +Clubs = Clubs +Economy and fees = Economy and fees +Forked individual courses = Forked individual courses +General = General +Manual point reductions and adjustments = Manual point reductions and adjustments +Manual time penalties and adjustments = Manual time penalties and adjustments +MeOS Features = MeOS Features +MeOS – Funktioner = MeOS – Features +Patrols = Patrols +Prepare start lists = Prepare start lists +Relays = Relays +Several MeOS Clients in a network = Several MeOS Clients in a network +Several races for a runner = Several races for a runner +Spara laguppställningar = Save Team Line-Ups +Teams and forking = Teams and forking +Track runners in forest = Track runners in forest +Vacancies and entry cancellations = Vacancies and entry cancellations +Banan saknas = Missing course +Klassen saknas = Missing class +Alla lopp som individuella = Every race as individual +Exportera individuella lopp istället för lag = Export as individual races instead of teams +Exportera startlista = Export start list +Exporttyp = Export type +Exportval, IOF-XML = Export settings, IOF-XML +Failed to read file = Failed to read file. +Klassval = Class selection +The forking is not fair = The forking is not fair +Unfair control legs = Unfair control legs +Växel = Changeover +help:teamlineup = Here you can import team line-ups from a structured text based format, which is easy to produce manually from a spreadsheet program. The file must have the following format:\n\nClass;Team name;[Club]\nCompetitor 1;[Card No];[Club];[Course];[Competitor's class]\nCompetitor 2;[Card No];[Club];[Course];[Competitor's class]\n...\nClass;Team name;[Club]\n...\n\nFields marked with [] may be excluded. Note that referred classes and courses must exist, and that the number of legs in the class must match the number of competitor rows following the class. Empty rows can be used if there is no competitor. The option means that only competitors already in the competition are moved to the team; other competitors specified are ignored. +Poängjustering = Point adjustment +Use initials in names = Use initials in names +Exportera klubbar (IOF-XML) = Export Clubs (IOF-XML) +Exportera personer (IOF-XML) = Export Persons (IOF-XML) +Töm databasen = Clear Database +Several stages = Several stages +Assign courses and apply forking to X = Assign Courses and Apply Forking to X +Assign selected courses to selected legs = Assign Selected Courses to Selected Legs +Calculate and apply forking = Calculate and Apply Forking +Clear selections = Clear Selections +Define forking = Define Forking +Forking setup = Forking Setup +Leg X: Do not modify = Leg X: Do not modify +Legs = Legs +help:assignforking = This function computes an optimal forking pattern from selected courses. Assign one or more courses to the legs by selecting courses and legs from the lists above. All courses can have the same set of courses (equal forking) or it i possible to use different set of courses for different legs. Also in this case, MeOS will fork these courses against each other, if the courses allow it. +Leg X = Leg X +Leg X: Use Y = Leg X: Use Y +Created X distinct forkings using Y courses = Created X distinct forks using Y courses +Clear Memory = Clear Memory +Create Competition = Create Competition +Print Card Data = Print Card Data +Print card data = Print card data +help:analyzecard = This function allows you to print out card data without using any competition, much like a standalone printing unit. Select Print Splits to select and configure the printer.\n\nThe cards are also saved in memory (but not in the competition). You can edit name and club for a card by clicking the name (Or 'Unknown'). You can also save the cards to file (Save) or create a new competition from card data. Note that if a competition is currently open, you must close it to make this option available. +Använd endast en bana i klassen = Use only one course in the class +Gafflade banor = Courses with Forks +Unroll split times for loop courses = Unroll split times for loop courses +Löpare per klass = Runners per class +Alla funktioner = All Features +Anmäl inga deltagare nu = No Entries +Datum (för första start) = Date (of first start) +Endast grundläggande = Basic Features +Funktioner i MeOS = MeOS Features +Första tillåtna starttid = First possible start time +Importera anmälda = Import Entries +Individuell tävling = Individual Competition +Namn och tidpunkt = Name and Time +Skapar tävling = Creating Competition +Tävling med lag = Competition with Teams +Tävlingen måste avgöras mellan X och Y = The competition must take place between X and Y +Tävlingens namn = Competition name +Välj från lista = Detailed Selection +Välj vilka funktioner du vill använda = Select which MeOS features you need for this competition +Individuellt, gafflat = Forked Individual +Skapa tävlingen = Create Competition +newcmp:featuredesc = Select which MeOS feature you need for this competition. You may add or remove features at any time by selecting on the page Competition. +Exportera till fil = Export to file +FilterPrelResult = Prel. result +FinishTimeReverse = Reversed finish time (last first) +Open a Copy = Open as Copy +Point calculation for runner = Point calculation for runner +Point calculation for team = Point calculation for team +Result score calculation for runner = Result score calculation for runner +Result score calculation for team = Result score calculation for team +ResultDescription = Name of result type +Skapa = Create +Status calculation for runner = Status calculation for runner +Status calculation for team = Status calculation for team +Support time from control = Support time from control +Support time to control = Support time to control +Time calculation for runner = Time calculation for runner +Time calculation for team = Time calculation for team +TimingFrom = Name of start point +TimingTo = Name of finish point +Applying rules to the current competition = Applying rules to the current competition +Available symbols = Available symbols +Cancel = Cancel +Description = Description +Edit Clubs = Edit Clubs +Edit Result Modules = Edit Result Modules +Edit rule for = Edit rule for +Name of result module = Name of result module +New Result Module = New Result Module +New Set of Result Rules = New Set of Result Rules +Result Calculation = Result Calculation +Result Module – X = Result Module – X +Result module identifier = Result module identifier +Result Modules = Result Modules +Save = Save +Save changes = Save changes +Source code = Source code +Test Result Module = Test Result Module +Result score calculation for team = Result score calculation for team +Time: X = Time: X +Start: X = Start: X +Index in X[index] = Index in X[index] +X är inget giltigt index = X is not a valid index +ResultModuleNumber = Result Module: Number +ResultModuleTime = Result Module: Time +ResultModuleNumberTeam = Result Module: Number (for Team) +ResultModuleTimeTeam = Result Module: Time (for Team) +RunnerRogainingOvertime = Competitor's overtime (rogaining) +RunnerRogainingReduction = Competitor's point reduction +TeamRogainingOvertime = Team's overtime (rogaining) +TeamRogainingReduction = Team's point reduction +Automatic rogaining point reduction = Automatic rogaining point reduction +Choose result module = Choose result module +Deviation +/- from expected time on course leg = Deviation +/- from expected time on course leg +Leg number in team, zero indexed = Leg number in team, zero indexed +Length of course = Length of course +Maximum allowed running time = Maximum allowed running time +Place on course leg = Place on course leg +Result Modules = Result Modules +Runner's card, matched control ids (-1 for unmatched punches) = Runner's card, matched control ids (-1 for unmatched punches) +Runner's card, punch codes = Runner's card, punch codes +Runner's card, punch times = Runner's card, punch times +Runner's course = Runner's course +Runner's split times = Runner's split times +Runner's total running time to control = Runner's total running time to control +Runner/team fee = Runner/team fee +Runner/team finish time = Runner/team finish time +Runner/team input place = Runner/team input place +Runner/team input points = Runner/team input points +Runner/team input running time = Runner/team input running time +Runner/team input status = Runner/team input status +Runner/team place = Runner/team place +Runner/team rogaining overtime = Runner/team rogaining overtime +Runner/team rogaining points = Runner/team rogaining points +Runner/team rogaining points adjustment = Runner/team rogaining points adjustment +Runner/team running time = Runner/team running time +Runner/team start time = Runner/team start time +Runner/team status = Runner/team status +Runner/team time adjustment = Runner/team time adjustment +Runner/team total place = Runner/team total place +Runner/team total running time = Runner/team total running time +Runner/team total status = Runner/team total status +Shortest time in class = Shortest time in class +Status as computed by your status method = Status as computed by your status method +Status code for a missing punch = Status code for a missing punch +Status code for a time over the maximum = Status code for a time over the maximum +Status code for a valid result = Status code for a valid result +Status code for an unknown result = Status code for an unknown result +Status code for disqualification = Status code for disqualification +Status code for not competing = Status code for not competing +Status code for not finishing = Status code for not finishing +Status code for not starting = Status code for not starting +Points as computed by your point method = Points as computed by your point method +Time as computed by your time method = Time as computed by your time method +Time after leg winner = Time after leg winner +Finish time for each team member = Finish time for each team member +Matched control ids (-1 for unmatched) for each team member = Matched control ids (-1 for unmatched) for each team member +Punch codes for each team member = Punch codes for each team member +Punch times for each team member = Punch times for each team member +Result Modules = Result Modules +Rogaining points for each team member = Rogaining points for each team member +Runner's method output numbers = Runner's method output numbers +Runner's method output times = Runner's method output times +Running time for each team member = Running time for each team member +Start time for each team member = Start time for each team member +Status for each team member = Status for each team member +Check: X = Check: X +Debug = Debug +Debug Output = Debug Output +Debug X for Y = Debug X for Y +Do you want to clear the card memory? = Do you want to clear the card memory? +Portable Document Format (PDF) = Portable Document Format (PDF) +Poängavdrag = Point reduction +RunnerPointAdjustment = Competitors's point adjustment +RunnerTimeAdjustment = Competitors's time adjustment +Save changes in rule code? = Save changes in rule code? +Symboler = Symbols +TeamPointAdjustment = Team's point adjustment +TeamTimeAdjustment = Team's time adjustment +Variabler = Variables +Check: X = Check: X +Choose result module = Choose result module +Result Modules = Result Modules +Error in result module X, method Y (Z) = Error in result module 'X', method 'Y'\n\nZ +Invalid operator X = Invalid operator X +Unknown symbol X = Unknown symbol X +RunnerGlobal = Competitor (classes together) +TeamGlobal = Team (classes together) +List Error: X = List Error: X +Rader markerade med (*) kommer från en lista i tävlingen = Rows with a (*) originates from a list in the competition +Resultatmodulen används i X = The Result Module is used in X +Valfri = Optional +Vill du sätta resultatet från tidigare etapper till ? = Do you want to change the result for earlier stages to (Not taking part)? +Hantera deltagare som bytt klass = Treatment of competitors that have changed class +Välj klasser med nya anmälningar = Specify classes where new entries are allowed +Byt till rätt klass (behåll eventuell starttid) = Switch to the right class (keep start time) +Byt till vakansplats i rätt klass (om möjligt) = Switch to a vacant position in the right class (if possible) +Tillåt ny klass, behåll resultat från annan klass = Allow new class and keep results from other class +Tillåt ny klass, inget totalresultat = Allow new class but without total result +tooltip_explain_status = - = Unknown Status (No result yet)\nOK = Valid result\nDNS = Did Not Start\nMP = Missing Punch\nDNF = Did Not Finish\nDISQ = Disqualified\nOMT = Over Maximum Time\nNTP = Not Taking Part +Placering = Place +Resultat från tidigare etapper = Results from Earlier Stages +Input Results = Input Results +Input Results - X = Input Results - X +Individuella resultat = Individual results +Avdrag = Reduction +Team Rogaining = Team Rogaining +Övertid = Over time +Kunde inte öppna tävlingen = Could not open the competition +warn:opennewversion = The competition is created in MeOS X. Data may be lost if you proceed.\n\nDo you wish to continue? +District id number = District id number +Kunde inte ladda X\n\n(Y) = Could not load X\n\n(Y) +Narrow Results = Narrow Result List +Club id number = Club id number +User input number = User defined input parameter +listinfo:singleclub = Create a result list for a single club.\nUse the input parameter to specify the club id. +listinfo:inputresults = Show input results from previous stages. +Ett värde vars tolkning beror på listan = A value with a list dependent interpretation +Listparameter = List parameter +Individual results in a club = Individual results within a club +OL-Skytte med tidstillägg = Orienteering/Shooting with Time Punishment +OL-Skytte utan tidstillägg = Orienteering/Shooting without Time Punishment +OL-Skytte stafettresultat = Orienteering/Shooting Relay +Sluttid = Final time +olshooting:timepunishment = Result list Orienteering/Shooting with Time Punichment.\n\nActivate support for Rogaining and manual point adjustments. The use the field Point reduction on the page Competitors to specify misses on the form PPPLLSS, where PPP is the point orienteering error in millimetres, LL misses lying and SS is misses standing. Example 30201 means 3 mm error, 2 lying and 1 standing miss. +olshooting:notimepunishment = Result list Orienteering/Shooting without Time Punichment.\n\nActivate support for Rogaining and manual point adjustments. The use the field Point reduction on the page Competitors to specify misses on the form LLSS, where LL means misses lying and SS means misses standing. Example: 0201 means 2 lying and 1 standing miss. +Namnet kan inte vara tomt = The name cannot be empty +Ingen / okänd = None / unknown +Inget nummer = No number +Stafettresultat = Relay Results +Döp om X = Rename X +Gräns för maxtid = Limit for maximum time (OMT) +Individual Example = Individual Example +Long = Long +MeOS Three Days Race X = MeOS Three Days Race X +Medium = Medium +Open = Open +Open X = Open X +Prologue + Pursuit = Prologue + Pursuit +Relay Example = Relay Example +Short = Short +Ultra Long = Ultra Long +Tillgängliga filer installerades. Starta om MeOS. = Settings was installed. Please restart MeOS. +edit_in_forest = Manage\nRemaining Runners +Latest Results = Latest Results +warning:direct_result = Note that using requires that all control punches on the course have been sent as radio controls, or that MeOS is used only for timing without a course.\n\nUse result on finish punch? +Inställningar startbevis = Print Start Certificate Settings +Skrivarinställningar = Printer Settings +Skrivarinställningar för sträcktider och startbevis = Printer settings for split times and start certificates +Startbevis = Start Certificate +Startbevis X = Start Certificate X +Skriv ut startbevis = Print Start Certificate +Skriv ut startbevis för deltagaren = Print start certificate for competitor +Utskrift = Print +Från klassen = From class +Tillsätt ytterligare vakans = Fill Another Vacancy +Överföring = Transfer +Anmäl till efterföljande etapper = Enter for subsequent stages +Totalt antal etapper = Total number of stages +Vill du använda den nya brickan till alla etapper? = Do you want to use the new card for all stages? +Avkortad banvariant = Shortened course +Avkortning = Shortening +Hantera laget = Manage team +Med avkortning = With shortening +info_shortening = Select an existing course that shortens the current course. Several levels of shortening is possible. +Tilldela starttider = Assign start times +Avkortar: X = Shortens: X +Vill du nollställa alla manuellt tilldelade banor? = Do you wish to clear all manually assigned courses? +Ange löpande numrering eller första nummer i klassen = Specify consecutive numbering between classes or specify first number in class +Ange relation mellan lagets och deltagarnas nummerlappar = Specify the relation between team's bib and team member's bibs +Lagmedlem = Team member +Löpande = Consecutive +Oberoende = Independent +Samma = Same +Ökande = Increasing +Manuell = Manual +Vill du uppdatera alla nummerlappar? = Do you want to update all bibs? +Hela banan = Entire course +Ogiltigt maximalt intervall = Invalid maximum interval +Startintervallet får inte vara kortare än basintervallet = A start interval may not be shorter than the base interval +Ett startintervall måste vara en multipel av basintervallet = A start interval must be a multiple of the base interval +Ogiltigt minimalt intervall = Invalid minimal interval +Ogiltigt basintervall = Invalid base interval +Country = Country +CourseShortening = Course shortening +Nationality = Nationality +Number of shortenings = Number of shortenings +Längd = Length +Redigera sträcklängder = Edit Leg Lengths +Redigera sträcklängder för X = Edit Leg Lengths for 'X' +Oordnade parallella sträckor = Out of order parallel legs +Tillåt löpare inom en parallell grupp att springa gruppens banor i godtycklig ordning = Allow competitors within a parallel group to run the courses of the group in any order +Laguppställningen hade fel, som har rättats = The team line-up had errors, which have been corrected +ControlClasses = Control's classes +ControlCodes = Control's punch codes +ControlCourses = Control's courses +ControlMaxLostTime = Control, lost time, maximum +ControlMedianLostTime = Control, lost time, median +ControlMistakeQuotient = Control, quotient of runners with lost time +ControlName = Control's name +ControlPunches = Control's actual number of visitors +ControlRunnersLeft = Control's remaining number of visitors +ControlVisitors = Control's expected number of visitors +CourseClasses = Course's classes +CourseUsage = Course's number of required maps +CourseUsageNoVacant = Course's number of entries excluding vacant positions +Bomkvot = Mistake Quotient +Control = Control +Control Statistics = Control Statistics +Control Statistics - X = Control Statistics - X +Course = Course +FilterSameParallel = Collect parallel legs +Kontrollrapport - X = Control Report - X +Maxbom = Max Mistake +Control Overview = Control Overview +Medianbom = Median Mistake +N.N. = X +Endast på obligatoriska sträckor = Only process non-optional legs. +Fyll obesatta sträckor i alla lag med anonyma tillfälliga lagmedlemmar (N.N.) = Fill vacant legs in all teams with anonymous temporary team members (X) +Skapa anonyma lagmedlemmar = Appoint Anonymous Team Members +Tillsätt tillfälliga anonyma lagmedlemmar = Appoint Anonymous Team Members +Tillsätt = Appoint +help:anonymous_team = Create and appoint (temporary) team members for all teams, to whom you can assign SI Card, Course etc. +Anonymt namn = Anonymous name +Med anmälningsavgift (lagets klubb) = With entry fee (for the team club) +Tar bort X = Removing X +Källa = Source +Ta bort eventuella avanmälda deltagare = Remove canceled entries, if any +Verktyg = Tools +Automatisk = Automatic +Avstånd = Distance +Extra avstånd ovanför textblock = Extra distance above +FilterSameParallelNotFirst = Collect parallel legs, skip first +RunnerLeg = Competitor (specific leg) +Texten ska innehålla tecknet X, som byts ut mot tävlingsspecifik data = The text must include the symbol X, which is replaced by competition specific data +Tabellverktyg = Table tools +Antal reserverade nummerlappsnummer mellan klasser = Number of reserved bib numbers between classes +help:bibs = You can handle bibs automatically or manually. Here you can assign bibs manually for a certain class by specifying the method Manual and provide the first number in the class.\n\nThe method automatic works in the same way, with the difference that MeOS will update the bibs of all classes at once. Although it is possible to make this setting here, it is better to use the Quick settings for classes to get an overview over all classes.\n\nUse the method Automatic together with the methods None or Consecutive, which means that the last number in the preceding class is used as first number. The number of reserved bibs specifies the jump made in the numbering between classes.\n\nFor team classes you can specify how the competitors´ bibs relate to the team´s bib. It can be the Same, Independent, Increasing (Team 1: 101, 102, 103, 104, Team 2: 111, 112, 113, 114 etc) or Leg (100-1, 100-2, 100-3 etc). +RunnerGeneralPlace = Competitor's team's or individual place +RunnerGeneralTimeAfter = Competitor's team's or individual time after +RunnerGeneralTimeStatus = Competitor's team's or individual time / status +open_error = Failed to open X.\n\nY. +open_error_locked = This competition is already open in MeOS.\n\nYou have to use a database to open more than one instance of the competition. +Ogiltigt bricknummer = Invalid card number +ask:updatelegs = Lengths of individual course legs may require an update after this change.\n\nDo you wish fix that now? +warn:updatelegs = Lengths of individual course legs may require an update after this change. +Ingen deltagare vald = No competitor selected +Från klubben = From the Club +Från laget = From the Team +Gafflingsnyckel X = Forking Key X +help:teamwork = The runners swap position. You can make a sequence of swaps to reach the new team line-up. +Ordnat = Ordered +Str. X = Leg X +Vill du att X går in i laget? = Do you want to put X in the team? +Vill du att X och Y byter sträcka? = Do you want X and Y to switch leg? +Vill du att X tar sträckan istället för Y? = Do you want X to run the leg instead of Y? +Ändra lagets gaffling = Change Team Forking +Deltagarens klass styrs av laget = The class is defined by the team +För att delta i en lagklass måste deltagaren ingå i ett lag = To participate in a team class you need to assign a team to the competitor +Dela upp = Split +Alla sträckor = All legs +Liveresultat, deltagare = Live Results, individual +Använd enhets-id istället för tävlings-id = Use Unit ID instead of competition ID +Enhetens ID-nummer (MAC) = Unit ID (MAC) +Antal deltagare: X = Number of competitors: X +Dela efter placering = Split by result +Dela efter tid = Split by time +Dela slumpmässigt = Random split +Jämna klasser (placering) = Make equal classes (result) +Jämna klasser (ranking) = Make equal classes (ranking) +Jämna klasser (tid) = Make equal classes (time) +Klass X = Class X +Not yet implemented = Not yet implemented +Tidstillägg = Time punishment +help:seeding_info = Seeded start time allocation means that an earlier result or ranking controls the process in part. In the field seeding groups you may either enter a single group size, meaning that the entire class is partitioned into groups of this size. The group size "1" means that the seeding order is strictly used. You can also specify several group sizes. "15, 1000" would meen a seeded group with the 15 highest ranked runners and the remaining (at most 1000) runners are placed in a non-seeded group. +Ange en gruppstorlek (som repeteras) eller flera kommaseparerade gruppstorlekar = Supply one group size (to be repeated) or several comma separated sizes +Hindra att deltagare från samma klubb startar på angränsande tider = Prevent competitors from the same club to start at adjacent start times. +Låt de bästa start först = Let the highest ranked start first +Seedningsgrupper = Seeding groups +Seedningskälla = Seeding source +error:invalidmethod = The selected method gave no distribution. Source data is insufficient. +Ogiltig storlek på seedningsgrupper X = Invalid size of seeding groups: X +Bananvändning = Course Usage +Antal banor = Number of courses +Could not load list 'X' = Could not load list 'X' +Från den här listan kan man skapa etiketter att klistra på kartor = From this list, you can create labels to stick on the maps +Gafflingar i tabellformat = Forkings in table format +Vakanser - X = Vacancies - X +Kopiera = Copy +Kopiera till urklipp = Copy to the clipboard +RunnerStartCond = Competitor's start time (if individual) +StartTimeForClassRange = Class start time range +TeamStartCond = Team's start time (if individual) +Liveresultat = Live Results +Visa rullande tider mellan kontroller i helskärmsläge = Show rolling times between controls in full screen mode +help:liveresultat = This method starts a timer in full screen mode (large-screen) when a competitor in a selected class punches the control, and measures the time until the control is reached. Otherwise a top list with the best results is shown. Both controls need of course be online controls and if you use a network, make sure to activate to get a responsive timer. +Result at a control = Result at a control +Total/team result at a control = Total/team result at a control +prefsAccount = Default account number +prefsAddress = Default address +prefsAdvancedClassSettings = Show advanced class settings +prefsAutoSaveTimeOut = Automatic backup intervall (ms) +prefsCardFee = Default card fee +prefsClient = Name of client in a network +Vissa inställningar kräver omstart av MeOS för att ha effekt = Some settings require a restart of MeOS to have effect +prefsAutoTie = Tie runner/card automatically +prefsControlFrom = Last from control +prefsControlTo = Last to control +prefsCurrencyFactor = Currency scale factor +prefsCurrencyPreSymbol = Place currency symbol in front +prefsCurrencySeparator = Currency decimal separator +prefsCurrencySymbol = Currency symbol +prefsDatabase = Use runner database +prefsDatabaseUpdate = Last runner database update +prefsDefaultDrawMethod = Default draw method +prefsDirectPort = Network port for advance punch data +prefsEMail = EMail +prefsEliteFee = Default elite fee +prefsEntryFee = Default entry fee +prefsEventorBase = URL to Eventor +prefsFirstInvoice = First invoice number +prefsFirstTime = First startup +prefsHomepage = Homepage +prefsInteractive = Interactive card handling +prefsLateEntryFactor = Factor for late entry fee +prefsLiveResultFont = Font used for live results +prefsMIPURL = URL to MIP server +prefsMOPFolderName = Local MOP folder +prefsMOPURL = URL to MOP server +prefsManualInput = Use manual result input +prefsMaximumSpeakerDelay = Maximum delay in speaker update +prefsOrganizer = Organizer +prefsPort = MySQL network port +prefsRentCard = Rent card +prefsSeniorAge = Upper age limit +prefsServer = Default network server +prefsSpeakerShortNames = Use initials in names +prefsStreet = Organizer street address +prefsSynchronizationTimeOut = Network update timeout (ms) +prefsTextFont = MeOS text font +prefsUseDirectSocket = Use advance punch data +prefsUseEventor = Use Eventor +prefsUseEventorUTC = Use universal coordinated time with Eventor +prefsUseHourFormat = Use format HH:MM:SS instead of MMM:SS +prefsUserName = MySQL user name +prefsYouthAge = Low age limit +prefsYouthFee = Reduced fee +prefsaddressxpos = Address x-coordinate +prefsaddressypos = Address y-coordinate +prefsclasslimit = Limit shown results per class +prefsintertime = Show intermediate times +prefspagebreak = Add page breaks +prefssplitanalysis = Perform split time analysis +Ändra MeOS lokala systemegenskaper = Change MeOS local system properties +true[boolean] = true +false[boolean] = false +Ändra X = Change X +Ingen parstart = Individual start +Parvis (två och två) = Pairwise (two by two) +X och Y[N by N] = X by Y +Lotta klasser med samma bana gemensamt = Draw classes with the same course together +Lotta starttider = Draw Start Times +Lotta klasser med banan X = Draw classes with the course 'X' +MeOS Timing = MeOS Timing +Med resultat = With results +Säkerhetskopiering = Interval Backup +Destination: X = Destination: X +Ogiltig destination X = Invalid destination X +Säkerhetskopierar om = Backing up in +Year of birth = Year of birth +Ogiltigt antal sekunder: X = Invalid number of seconds: X +Du kan använda en SI-enhet för att läsa in bricknummer = You can use an SI unit to read card the number +Ignorera startstämpling = Ignore start punch +Uppdatera inte starttiden vid startstämpling = Do not update start time with start punch time +Ändra lokala inställningar = Change local settings +Gafflingsnyckel = Forking key +Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD) = Incorrect date format 'X' (Use YYYY-MM-DD) +Felaktigt tidsformat 'X' (Använd TT:MM:SS) = Incorrect time format 'X' (Use HH:MM:SS) +Hämta inställningar från föregående lottning = Fetch settings from previous session +Ej startstämpling = Disregard start punch +Extraplatser = Extra places +Fritt = Free +Från lag = From team +Lag + sträcka = Team + leg +Nummerlappshantering = Bib management +Oordnade parallella = Unordered parallel +Spara starttider = Save start times +X platser. Startar Y = X places. Starts Y +övriga = other +RunnerStartZero = Competitor's relative start time (zero time) +TeamStartZero = Team's relative start time (zero time) +Datumfilter = Date filter +Inget filter = No filter +Inlästa stämplar = Read punches +Löpare saknas = No competitor +Klasserna X och Y har samma externa id. Använd tabelläget för att ändra id = The classes X and Y have the same external id. Use the table mode to correct the id +Vill du koppla isär X från inläst bricka Y? = Would you like to disconnect X from the read out card Y? +RunnerRogainingPointGross = Rogaining points before reduction +Samlade poäng = Collected points +Tidsavdrag = Deduction +X p = X p +Bricka X används också av = Card X is also used by +reused card = reused card +Varning: Brickan X används redan av Y = Warning: The card X is already used by Y +Invalid filter X = Invalid filter X +Invalid font X = Invalid font X +Aktivera stöd för tider över 24 timmar = Activate support for running times longer than 24 hours. +Inkludera information om flera lopp per löpare = Include information about multiple races for a single runner. +Alla uthyrda brickor har bockats av = All rented cards are ticked off +Avbockade brickor = Ticked off cards +Avstämning hyrbrickor = Count returned hired cards +Brickor markerade som både uthyrda och egna: X = Cards used as both hired and owned: X +Nollställ = Clear +Nollställ minnet; markera alla brickor som icke avbockade = Clear memory; forget all ticked off cards +Rapport = Report +Totalt antal unika avbockade brickor: X = Number of unique ticked off cards: X +Uthyrda brickor som inte avbockats = Hired cards that are not ticked off +Uthyrda: X, Egna: Y, Avbockade uthyrda: Z = Hired Cards: X, Owned Cards: Y, Hired and Ticked Off: Z +Vill du göra om avbockningen från början igen? = Do you want to reset and start all over again? +help:checkcards = Use this function to count and tick off hired cards to check that they all have been returned. Attach a SI unit (preferably programmed as a control or finish, since that is faster than card read out), and punch all returned cards. Push the Report button to see if any card is missing.\n\n The check is done locally at this computer, and does not modify the competition. +Betalningsmetoder = Modes of Payment +help:paymentmodes = You can define custom modes of payment, in addition to invoicing, to distinguish these in the bookkeeping. +Betalsätt = Payment Mode +Förväntat antal besökare: X = Expected number of visitors: X +Starttiden är definerad genom klassen eller löparens startstämpling = The start time is defined through the class or through a start punch +sekunder = seconds +är X före Y = is X before Y +var först i mål med tiden X = was first to the finish with time X +var först vid X med tiden Y = was first at X with time Y +var först vid växeln med tiden X = was first to the changeover with time X +är nu på X plats med tiden Y = is now on a X place with time Y +är nu på delad X plats med tiden Y = is now on a shared X place with time Y +är X efter = is X behind +är X efter Y = is X behind Y +är X efter; har tappat Y = is X behind; has lost Y +är X efter; har tagit in Y = is X behind; as gained Y +leder med X; har tappat Y = leads with X; has lost Y +leder med X; sprang Y snabbare än de jagande = leads with X; ran Y faster than the others +leder med X = leads with X +delar placering med X = shares place with X +sekund = second +skickar ut X = sends out X +Export language = Export language +Export split times = Export split times +Climb (m) = Climb (m) +Utrymme: X = Size: X +[Radera] = [Delete] +prefsNumSplitsOnePage = Number of cards per page +prefsPayModes = Modes of payment +prefsSplitPrintMaxWait = Maximum split print wait time +prefsWideSplitFormat = Print splits in wide format +ClassTeamLegResult = Class and leg result +SortLastNameOnly = Family name +Databaskälla = Database source +Filnamn IOF (xml) eller OE (csv) med löpare = Filename IOF (xml) or OE (csv) with runners +Importinställning = Import settings +prefsExportCSVSplits = Include splits in csv export +prefsExportFormat = Preferred export format +prefsImportOptions = Preferred import option +prefsSplitLateFees = Split late fees into normal and late part for IOF XML export +Längsta tid i sekunder att vänta med utskrift = Longest time in seconds to wait for the printout +Max antal brickor per sida = Maximum number of cards per page +Sträcktider i kolumner (för standardpapper) = Times in columns (for standard paper) +Spara inmatade tider i tävlingen utan att tilldela starttider = Save times and settings for each class so that you can continue working later +SRR Dongle = SRR Dongle +red channel = red channel +blue channel = blue channel +Printing failed (X: Y) Z = Printing failed (X: Y) Z +prefsNameMode = Name format: 0 = 'Given Family', 1 = 'Family, Given' diff --git a/code/french.lng b/code/french.lng new file mode 100644 index 0000000..1ed8a6f --- /dev/null +++ b/code/french.lng @@ -0,0 +1,2241 @@ +encoding = ANSI +%s m = %s m +%s meter = %s mètres +%s, block: %d = %s, bloc: %d +(ledare) = (leader) +(lokalt) = (local, pas de serveur) +(okänd) stämplade vid = (inconnu) a poinçonné +(på server) = (sur serveur) +(sekunder) = (secondes) +(sträckseger) = (meilleur partiel) +ALLA( = Tous( +API-nyckel = clef API +Accepterade elektroniska fakturor = Factures électroniques acceptées +Adress = Adresse +Adress och kontakt = Adresse et contact +Aktivera = Activer lecteur +Alla = Tous +Alla banfiler = Tous les fichiers de circuit -oli +Alla deltagare måste ha ett namn = Tous les concurrents doivent avoir un nom +Alla fakturor = Toutes les factures +Alla händelser = Tous les evenements +Alla lag måste ha ett namn = Toutes les équipes doivent avoir un nom +Alla listor = Toutes les listes +Alla lopp = Toutes les courses +Alla sträckor/lopp i separata filer = Tous les partiels/courses dans des fichiers séparés +Alla typer = Tous les types +Allmänna resultat = Résultats généraux +Andel vakanser = Partie disponible +Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar = Entrer le premier numéro de dossard, ou laisser vide en l'absence de dossard +Ange om kontrollen fungerar och hur den ska användas = Indiquez si le boîtier est opérationnel et comment il doit être utilisé +Ange startintervall för minutstart = Entrez l'intervalle de départ pour le départ +Ange tiden relativt klassens första start = Entrez l'écart en temps par rapport au premier départ de la catégorie. +Anm. avg. = Tarifs d'inscription +Anm. avgift = Tarif d'incription +Anm. datum = Date d'inscription +Anmäl = Entrer +Anmäl X = Entrer X pour la compétition +Anmälda = Inscriptions +Anmälda per distrikt = Inscriptions par région +Anmälningar = Inscriptions +Anmälningar (IOF (xml) eller OE-CSV) = Inscriptions (IOF (xml) ou OE-CSV) +Anmälningsavgift = Droits d'inscription +Anmälningsläge = Mode saisie rapide +Anslut = Connecter +Anslut till en server = Connexion au serveur +Ansluten till = Connecté à +Ansluter till Internet = Connexion à Internet +Anslutna klienter = Clients connectés +Anslutningar = Connexions +Anslutningsinställningar = Configuration de la connexion +Antal = Nombre +Antal besökare X, genomsnittlig bomtid Y, största bomtid Z = Nombre de visiteurs X, temps moyen perdu Y, temps max perdu Z +Antal ignorerade: X = Nombre d'inscriptions ignorées: X +Antal importerade = Nombre de données importées +Antal kartor = Nombre de cartes +Antal klasser = Nombre de catégorie +Antal löpare = Nombre de coureurs +Antal löpare på vanligaste banan X = Nombre de coureurs sur le circuit le plus utilisé: X +Antal misslyckade: X = Nombre d'inscriptions =erronnées: X +Antal startande per block = Nombre de départ par bloc +Antal startande per intervall (inklusive redan lottade) = Nombre de départs par intervalle (y compris ceux déjà [affectés]) +Antal sträckor = Nombre de branches +Antal vakanser = Nombre de vacants +Antal: %d = Nombre: %d +Antal: X = Nombre: X +Antalet rader i urklipp får inte plats i selektionen = Le nombre de ligne dans le presse-papier ne correspond pas à la sélection +Använd Eventor = Utiliser Eventor +Använd banpool = Utiliser un [pool] de circuit +Använd funktioner för fleretappsklass = Utiliser les fonctions de courses à étape +Använd första kontrollen som start = Utiliser le premier boîtier comme boîtier départ +Använd löpardatabasen = Utiliser la base des coureurs +Använd sista kontrollen som mål = Utiliser le dernier boîtier comme boîtier d'arrivée +Använd speakerstöd = Utiliser le module speaker +Använd stor font = Utiliser une grande police +Använd symbolen X där MeOS ska fylla i typens data = Utilisez le symbole X à l'emplacement où MeOS doit insérer les données +Användarnamn = Nom de l'utilisateur +Applicera för specifik sträcka = Utiliser pour un partiel spécifique +Arrangör = Organisateur +Att betala = A payer +Att betala: X = A payer: X +Automater = Services +Automatisera = Automatiser +Automatisk lottning = Tirage au sort Automatique +Automatisk skroll = Défilement automatique +Automatisk utskrift = Impression automatique +Automatisk utskrift / export = Impression / export automatique +Av MeOS: www.melin.nu/meos = Par MeOS: www.melin.nu/meos +Avancerat = Personnalisation +Avbryt = Annuler +Avgift = Frais +Avgifter = Tarifs Inscription +Avgiftshöjning (procent) = Majoration de tarif (pourcentage) +Avgjorda klasser (prisutdelningslista) = Par catégories (Liste de remise de prix) +Avgjorda placeringar - %s = Résultats définitifs - %s +Avgörande händelser = Evènement décisif +Avgörs X = Prêt à X +Avgörs kl = Prêt à +Avläsning/radiotider = Lecture des puces/radio +Avmarkera allt = Tout déselectionner +Avrundad tävlingsavgift = Droits d'inscriptions, arrondis +Avsluta = Quitter +Bad file format = Mauvais format +Bana = Circuit +Bana %d = Circuit %d +Banan används och kan inte tas bort = Le circuit est en cours d'utilisation +Banan måste ha ett namn = Le circuit doit avoir un nom +Banmall = Circuit +Banor = Circuits +Banor (antal kontroller) = Circuit (nombre de postes) +Banor för %s, sträcka %d = Circuit pour %s, partiel %d +Banor, IOF (xml) = Circuits, IOF (xml) +Banor, OCAD semikolonseparerat = Circuits, format OCAD +Banpool = [pool de circuits] +Banpool, gemensam start = [pool de circuits], départ en masse +Banpool, lottad startlista = [pool de circuits], liste de départ établie +Bantilldelning = Affectation de circuit +Bantilldelning, individuell = Affectation de circuit, course individuelle +Bantilldelning, stafett = Affectation de circuit, relais +Bantilldelningslista - %s = Circuits affectés - %s +Basintervall (min) = Intervalle de base (min) +Begränsa antal per klass = Nombre max par catégorie +Begränsa per klass = Limite par catégorie +Begränsning, antal visade per klass = Nombre maximum de coureurs par catégorie +Behandlar löpardatabasen = Traitement de la base de données des coureurs +Behandlar tävlingsdata = Traitement des compétitions +Behandlar: X = Traitement: X +Bekräfta att %s byter klass till %s = Confirmer SVP que %s passe dans la catégorie %s +Bekräfta att deltagaren har lämnat återbud = Confirmez SVP l'annulation de ce coureur +Betalat = Payé +Betalningsinformation = Détails du paiement +Bevakar händelser i X = Moniteur d'évènement X +Bevakningsprioritering = Sélectionner le coureur à surveiller +Block = Bloc +Blockbredd = Largeur de bloc +Bläddra = Parcourir +Bold = Gras +BoldHuge = Gras, géant +BoldLarge = Gras, grand +BoldSmall = Gras, petit +Bommade kontroller = Erreurs de poste +Bomtid = Temps perdu +Bomtid (max) = Temsp perdu (max) +Bomtid (medel) = Temps perdu (moyenne) +Bomtid (median) = Temps perdu (médiane) +Bomtid: X = Temps perdu: X +Bricka = Puce +Bricka %d används redan av %s och kan inte tilldelas = La puce %d est utilisé par %s et ne peut être réaffectée +Brickan redan inläst = Puce déjà lue +Brickhyra = Location de puce +Bricknummret är upptaget (X) = Puce utilisée (X) +Brickor = Puces +Bygg databaser = Création des bases de données +COM-Port = Port COM +Check = Vérifier +ClassCourseResult = Catégorie, circuit, résultats +ClassFinishTime = Catégorie, temps +ClassLength = Longueur du circuit pour la catégorie +ClassName = Catégorie +ClassPoints = Catégorie, points +ClassResult = Catégorie, résultat +ClassResultFraction = Pourcentage de la catégorie ayant terminé +ClassStartName = Nom départ +ClassStartTime = Catégorie, heure de départ, nom +ClassStartTimeClub = Catégorie, heure de départ, club +ClassTotalResult = Catégorie, résultats globaux +Club = Club +ClubName = Nom du club +ClubRunner = Club / Coureur +CmpDate = Date de la compétition +CmpName = Nom de la compétition +CourseClimb = Dénivellée circuit +CourseLength = Longueur circuit +CourseName = Nom du circuit +CourseResult = Résultat du circuit +CurrentTime = Heure actuelle +Databasanslutning = Connexion base de données +Databasvarning: X = Base de donnée, warning: X +Datorröst som läser upp förvarningar = Annonce vocales des coureurs +Datum = Date +Decimalseparator = Séparateur décimal +DefaultFont = Formattage standard +Dela = temps intermédiaires +Dela efter ranking = Temps intermédiaire par classement +Dela klass: X = Temps intermédiaires catégorie: X +Dela klassen = Temps intermédiaires par catégorie +Dela klubbvis = Temps intermédiaire par club +Deltagare = Coureurs +Deltagare %d = Coureur %d +Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = Le coureur 'X' est dans la catégorie d'équipe 'Y', mais n'a pas d'équipe. Les résultats dans cette catégorie pourraient être faussés. +Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = Le coureur 'X' est dans la catégorie de relais 'Y', mais n'a pas d'équipe. Les résultats dans cette catégorie pourraient être faussés +Deltagaren 'X' saknar klass = Le coureur 'X' n'a pas de catégorie +Deltar ej = Ne participe pas +Denna etapps nummer = Numéro d'étape +Destinationskatalog = répertoire de destination +Det går endast att sätta in vakanser på sträcka 1 = Vous pouvez ajouter des places vacantes seulement sur le premier partiel +Det här programmet levereras utan någon som helst garanti. Programmet är = Ce programme est fourni tel quel, sans aucune garantie. Ce programme est +Direktanmälan = Saisie rapide +Disk. = Disq. +Distriktskod = Code de la Ligue +Don't know how to align with 'X' = Impossible d'aligner avec 'X' +Du kan importera banor och klasser från OCADs exportformat = Vous pouvez importer des circuits et des catégories à partir d'un fichier exporté par OCAD +Du måste välja en klass = Vous devez choisir une catégorie +Duplicera = Dupliquer +E-post = Courriel +Efter = Après +Efteranm. avg. = Frais inscription tardives +Efteranmälda (efter ordinarie) = Inscriptions tardives (Après) +Efteranmälda (före ordinarie) = Inscriptions tardives (Avant) +Efteranmälda före ordinarie = Inscriptions tardives en premier +Efteranmälningar = Inscriptions tardives +Egen listrubrik = En-tête personnalisée +Egen text = Texte personnalisé +Egenskaper = Propriétés +Eget fönster = Nouvelle fenêtre +Egna listor = Listes personnalisées +Ej accepterade elektroniska fakturor = factures électronique refusées +Ej elektronisk = Pas électronique +Ej lottade = Pas tiré au sort +Ej lottade, efter = Tirés au sort restant après +Ej lottade, före = Tirés au sort restant avant +Ej start = Non partant +Ej tidtagning = non chronométré +Ekonomisk sammanställning = Synthèse financière +Elektronisk = Electronique +Elektronisk godkänd = Accepté électroniquement +Elit = Elite +Elitavgift = Frais d'inscription pour les Elites +Elitklasser = Catégorie Elite +En gafflad sträcka = Un embranchement +En klass kan inte slås ihop med sig själv = Vous ne pouvez pas fusionner une catégorie avec elle-même +En klubb kan inte slås ihop med sig själv = Un club ne peut pas fusionner avec lui-même +Endast en bana = Circuit individuel +Enhetstyp = Type d'unité +Etapp = Etape +Etapp X = Etape X +Etappresultat = Résultats des étapes +Eventorkoppling = Connexion à Eventor +Export av resultat/sträcktider = Export résultats / temps intermédiaires +Exportera = Export +Exportera / Säkerhetskopiera = Export / Backup +Exportera alla till HTML = Exporter tout en HTML +Exportera datafil = Export des données +Exportera elektroniska fakturor = Exporter les factures électroniques +Exportera inställningar och löpardatabaser = Export de la configuration et des bases de données +Exportera löpardatabas = Export de la base des coureurs +Exportera nu = Exporter maintenant +Exportera på fil = Exporter dans un fichier +Exportera resultat på fil = Exporter les resultats dans un fichier +Exportera startlista på fil = Exporter les listes de départ dans un fichier +Exportera sträcktider = Export des temps intermédiaires +Exportera tävlingsdata = Export des données +Externt Id = Identifiant externe +Extra = Extra +Extra stämplingar = Poinçons supplémentaires +Extralöparstafett = [Co-runner relay] +FAKTURA = FACTURE +FEL, inget svar = Erreur, pas de réponse +FEL: Porten kunde inte öppnas = Error: le port ne peut pas être ouvert +Failed to generate card = Impossible de générer la puce[Failed to generate card] +Failed to open 'X' for reading = Echec de l'ouverture de 'X' en lecture +Faktiskt startdjup: X minuter = Durée des départs: X minutes +Faktura = Facture +Faktura nr = Facture n° +Faktureras = A facturer +Fakturor = Factures +Fel: X = Erreur: X +Fel: hittar inte filen X = Erreur. Fichier 'X' non trouvé +Felaktig kontroll = Mauvais poinçon +Felaktig nyckel = Clef incorrecte +Felaktig sträcka = Numéro de relayeur incorrect +Felaktigt filformat = Format de fichier incorrect +Felst. = PM +Fil att exportera till = Fichier à exporter vers +Fil: X = Nom de fichier: X +Filnamn = Nom de fichier +Filnamn (OCAD banfil) = Nom de fichier (circuitx OCAD) +Filnamn IOF (xml) med klubbar = Nom de fichier IOF (xml) avec clubs +Filnamn IOF (xml) med löpare = Nom de fichier IOF (xml) avec coureurs +Filnamnet får inte vara tomt = Le nom de fichier ne peut être vide +Filter = Filtrage +FilterHasCard = Avec puce +FilterNoCard = Sans puce +FilterNotVacant = Sans vacant +FilterOnlyVacant = Uniquement les vacants +FilterRentCard = Puce louée +FilterResult = Avec résultats +FilterStarted = A démarré +Filtrering = Filtrage +FinishTime = Heure d'arrivée, nom +Flera banor = Multi circuits +Flera banor / stafett / patrull / banpool = Multi circuits/ Relais / Patrouille / [Pool circuits] +Flera banor/stafett = Multi circuits / Relais +Flytta höger = Vers la droite +Flytta vänster = Vers la gauche +Format = Format +Formaterat webbdokument (html) = Document web (html) +Formateringsregler = Règles de formattage +Formulärläge = Mode formulaire +Fortsätt = Continue +Fri anmälningsimport = Inscriptions en format libre +Fri starttid = heure de départ libre +Fria starttider = heures de départ libres +Från kontroll = Du poste +Fullskärm = Plein écran +Funktioner = Fonctions +Födelseår = Année de naissance +Följande deltagare deltar ej = Les coureurs suivants ne participeront pas +Följande deltagare har bytt klass = Les coureurs suivants ont changé de catégorie +Följande deltagare har bytt klass (inget totalresultat) = Les coureurs suivants ont changé de catégorie (pas de résultat total) +Följande deltagare har tilldelats en vakant plats = Les coureurs suivants ont pris une place vacante +Följande deltagare är anmälda till nästa etapp men inte denna = Les coureurs suivants sont enregistrés pour l'étape suivante mais pas celle-ci +Följande deltagare är nyanmälda = Les coureurs suivants générès de nouvelles inscriptions +Följande deltagare överfördes ej = Les coureurs suivant ont été ignorés +För att ändra måltiden måste löparens målstämplingstid ändras = Pour modifier le temps de course, l'heure de poinçonnage de l'arrivée doit être changée +För muspekaren över en markering för att få mer information = Survoler avec le pointeur de la souris une zone pour obtenir plus d'information +För många kontroller = Trop de contrôles +Förbered lottning = Préparation du tirage au sort +Fördefinierade tävlingsformer = Compétitions prédéfinies +Fördela starttider = attribution des heures de départ +Föregående = Précédent +Föregående etapp = Etape précédente +Förhandsgranskning, import = Prévisualisation de l'import +Förhöjd avgift = Frais supplémentaires +Först-i-mål, gemensam = Du premier au dernier, commun +Först-i-mål, klassvis = Du premier au dernier, par catégorie +Första (ordinarie) start = Premier départ (ordinaire) +Första kontrollen = Premier contrôle +Första omstartstid = [First time for restart] +Första ordinarie starttid = Première heure de départ normale +Första start = Premier départ +Första starttid = Premier horaire de départ +Första sträckan kan inte vara parallell = Le premier partiel ne peut pas être dédoublé +Försöket misslyckades = L'opération a échoué +Förvarning på (SI-kod): alla stämplingar = Pré-warning (code SI): tous les poinçons +Förvarningsröst = Pré-warning Voix +Förväntad andel efteranmälda = Pourcentage d'inscriptions tardives attendu +Gata = Rue +Gemensam start = Départ en masse +Generera = Générer +Generera testtävling = Générer une compétition de test +Genererad = Généré à +Geografisk fördelning = Répartition géographique +Global sorteringsordning = Ordre de tri global +Godkänd API-nyckel = Clef API acceptée +Granska inmatning = Prévisualisation +Grund avg. = Tarifs de base +Grundavgift = Tarif de base +Grundinställningar = Configuration de base +Hantera brickor = Gestion des puces +Hantera flera etapper = Gestion courses à étapes +Hantera jaktstart = Gestion départ en chasse +Hantera klubbar och ekonomi = Gestion des clubs et du paiement +Hantera kvar-i-skogen = Gestion des coureurs non rentrés +Hantera löparbrickor = Gestion des puces +Hemsida = Site web +Hjälp = Aide +Hoppar över stafettklass: X = Sauter la catégorie de relais: X +Huvudlista = Liste principale +Hyravgift = Tarif de Location +Hyrbricka = Puces louées +Hyrbricksrapport = Rapport avec puces louées +Hyrbricksrapport - %s = Puces louées - %s +Hyrd = Louée +Hämta (efter)anmälningar från Eventor = Rechercher les enregistrements récents dans Eventor +Hämta data från Eventor = Rechercher des données dans Eventor +Hämta efteranmälningar = Rechercher les enregistrements récents +Hämta löpardatabasen = Recherche dans la base des données des coureurs +Hämta svar om elektroniska fakturor = Données des factures acceptées +Hämta tävlingsdata = Recherche des données en rapport avec la compétition +Hämta tävlingsdata för X = Recherche des données en rapport pour la compétition X +Hämtar anmälda = Recherche des inscriptions +Hämtar information om = Rassemblement d'information à propos de +Hämtar klasser = Recherche de catégories +Hämtar klubbar = Recherche de clubs +Hämtar löpardatabasen = Recherche dans la base des coureurs +Hämtar tävling = Recherche d'une compétition +Händelser = Evènement +Händelser - tidslinje = Evènement - Chronologie +Hög avgift = Frais d'inscription tardive +IOF (xml) = IOF (xml) +IOF Resultat (xml) = Résultats IOF (xml) +IOF Resultat, version 2.0.3 (xml) = Résultats IOF, version 2.0.3 (xml) +IOF Resultat, version 3.0 (xml) = Résultats IOF, version 3.0 (xml) +IOF Startlista (xml) = Horaires de départ IOF (xml) +IOF Startlista, version 3.0 (xml) = Horaires de départ IOF, version 3.0 (xml) +IOF Startlista, version 2.0.3 (xml) = Horaires de départ IOF, version 2.0.3 (xml) +IOF Löpardatabas, version 3.0 (xml) = Base de données des coureurs IOF, version 3.0 (xml) +IOF Klubbdatabas, version 3.0 (xml) = Base de données des clubs IOF, version 3.0 (xml) +IP-adress eller namn på en MySQL-server = Adresse IP ou nom d'un serveur MySQL +Id = Id +Identifierar X unika inledningar på banorna = Identification X ouvertures unique des circuits +Importera = Import +Importera IOF (xml) = Import IOF (xml) +Importera anmälningar = Importation des inscriptions +Importera banor = Importation des circuits +Importera banor/klasser = Importation des circuits/catégories +Importera en tävling från fil = Importer une compétition +Importera fil = Importation d'un fichier +Importera från OCAD = Import depuis OCAD +Importera från fil = Import depuis un fichier +Importera löpardatabas = Import de la base des coureurs +Importera löpare = Import des coureurs +Importera löpare och klubbar / distriktsregister = Import des coureurs et des clubs +Importera stämplingar = Import des poinçons +Importera tävling = Importer une compétition +Importera tävlingsdata = Import des données +Importerar = En cours d'importation +Importerar OCAD csv-fil = Importation OCAD CSV +Importerar OE2003 csv-fil = Importation OE2003 CSV +Importerar OS2003 csv-fil = Importation OS2003 CSV +Importerar anmälningar (IOF, xml) = Importation des inscriptions (IOF, xml) +Importerar banor (IOF, xml) = Importation des circuits (IOF, xml) +Importerar klasser (IOF, xml) = Importation des catégories (IOF, xml) +Importerar klubbar (IOF, xml) = Importation des clubs (IOF, xml) +Importerar tävlingsdata (IOF, xml) = Importation des données de compétition(IOF, xml) +Importerbara = Importable +Index = Index +Individuell = par catégorie +Individuell resultatlista, alla lopp = liste de résultat par nom, toute les courses +Individuell resultatlista, sammanställning av flera lopp = liste de résultat par nom, résumé +Individuell resultatlista, visst lopp = liste de résultat par nom, specifique +Individuell resultatlista, visst lopp (STOR) = liste de résultat par nom, specifique (GRAND) +Individuell startlista, visst lopp = Liste de départ par nom, spécifi +Individuella deltagare = Coureurs individuels +Individuella slutresultat = Résultats finaux individuels +Individuella totalresultat = Résultats totaux individuels +Info = Information +Inga = Aucun +Inga deltagare = Pas de coureurs +Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning = Aucun vacant disponible. Les vacants sont généralement créés quand on tire au sort les horaires des catégories +Ingen = aucun +Ingen bana = aucun circuit +Ingen deltagare matchar sökkriteriet = Aucun coureur ne répond aux critères de recherche +Ingen klass = Pas de catégorie +Ingen klass vald = Pas de catégorie sélectionnée +Ingen löpare saknar bricka = tous les coureurs ont une puce +Ingen matchar 'X' = Aucune correspondance pour 'X' +Ingen rogaining = Pas de course au score +Inkommande = Nouveautés +Inläst bricka ställd i kö = La puce a été mise en file d'attente +Inlästa brickor = Lecture de puces +Inmatning av mellantider = Entrez les temps intermédiaires +Inspekterar klasser = Visualisation des catégories +Installera = Installation +Inställningar = Configuration +Inställningar MeOS = Configuration de MeOS +Interaktiv inläsning = Lecture interactive +Intervall = Intervalle +Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras = Intervalle (secondes). Laisser vide pour une mise à jour quand les données de la course changent. +Intervallet måste anges på formen MM:SS = L'intervalle doit être de la forme MM:SS +Italic = Italique +ItalicMediumPlus = Italique, un peu plus grand +Jag sköter lottning själv = Je gère le tirage des horaires de départ moi-même +Jaktstart = Départ en chasse +Justera blockvis = Ajustement du bloc +Justera mot = Aligner avec +Klart = Terminé +Klart. Antal importerade: X = Terminé. Nombre d'inscriptions importées : X +Klart. X deltagare importerade = Terminé. X coureurs importés +Klart. X lag importerade = Terminé. X équipes importées +Klart. X patruller importerade = Terminé. X patrouille importées +Klart: alla klasser lottade = Tirage de toutes les catégories terminé +Klart: inga klasser behövde lottas = Terminé:aucune catégorie ne necessite un nouveau tirage +Klass = Catégorie +Klass %d = Catégorie %d +Klass saknad = Catégorie absente +Klass / klasstyp = Catégorie / Type +Klass att slå ihop = Catégories à fusionner +Klassbyte = Modifier la catégorie +Klassen 'X' har jaktstart/växling på första sträckan = La catégorie 'X' a une chasse/variation sur le premier partiel +Klassen används och kan inte tas bort = La catégorie est utilisée et ne peut être supprimée +Klassen lottas inte, startstämpling = Poinçon de départ uniquement +Klassen måste ha ett namn = La catégorie doit avoir un nom +Klassens bana = Circuit de la catégorie +Klasser = Catégories +Klasser (IOF, xml) = Catégories (IOF, xml) +Klasser där nyanmälningar ska överföras = Catégories dans laquelle les nouvelles inscriptions vont être transferrées +Klassinställningar = Configuration des catégories +Klassnamn = Nom de la catégorie +Klasstyp = Type de la catégorie +Klientnamn = Nom du client +Klistra in = Coller +Klistra in data från urklipp (X) = Coller depuis le presse papier (X) +Klocktid: X = Heure courante: X +Klubb = Club +Klubb att ta bort = Club à supprimer +Klubb: X = Club: X +KlubbId = Id du Club +Klubbar = Clubs +Klubbar (IOF, xml) = Clubs (IOF, xml) +Klubbar som inte svarat = Clubs qui n'ont pas répondu +Klubbdatabasen = Base de données des clubs +Klubblös = Pas de club +Klubbresultat = par club +Klubbresultatlista = Résultats par club +Klubbresultatlista - %s = Résultats par club - %s +Klubbstartlista = par club +Klubbstartlista - %s = Horaire de départ par club - %s +Klungstart = Départs groupés +Knyt löpare till sträckan = Affecter un coureur à une variation +Knyt löparna till banor från en pool vid målgång = Rattacher un coureur à une course lors de la lecture +Kom ihåg listan = Mémoriser la liste +Kommentar / version = Commentaire / Version +Kommunikation = Communication +Kontant = Espèces +Kontant betalning = Espèces +Konto = Compte +Kontroll = Poste +Kontroll %s = Poste %s +Kontroll X = Poste X +Kontroll inför tävlingen = Vérifier la compétition +Kontrollen används och kan inte tas bort = Le poste est utilisé et ne peut être retiré +Kontrollens ID-nummer = Numéro du poste +Kontroller = Postes +Kontrollnamn = Nom du poste +Kopia X = Copier X +Kopiera länken till urklipp = Copier le lien +Kopiera selektionen till urklipp (X) = Copier la sélection (X) +Koppla ifrån = Déconnecter +Koppla ner databas = Déconnexion de la base de données +Kopplar ifrån SportIdent på = Déconnexion du boîtier SPORTident sur +Kortast teoretiska startdjup utan krockar är X minuter = La plus petite durée de départs sans collision est X minutes +Kortnamn = Nom court +Kunde inte ansluta till Eventor = Connexion à Eventor impossible +Kunde inte ladda upp tävlingen (X) = Echec lors de la remonté de la compétition (X) +Kvar-i-skogen = Coureurs restants +Kvinna = Femme +Kvinnor = Femmes +Källkatalog = Répertoire source +Kön = Sexe +Kör kontroll inför tävlingen = Vérification de la compétition +Ladda upp öppnad tävling på server = Upload de la compétition sur le serveur +Lag = Equipe +Lag %d = Equipe %d +Lag(flera) = Equipes +Laget 'X' saknar klass = L'équipe 'X' n'a pas de catégorie +Laget hittades inte = Equipe non trouvée +Lagnamn = Nom de l'équipe +Lagrade säkerhetskopior = Copies sauvergardées +Land = Pays +LargeFont = Texte en grand +Latitud = Latitude +Lista = Liste +Lista av typ 'X' = Liste du type 'X' +Lista med mellantider = Liste avec temps partiels +Lista med sträcktider = Liste avec temps partiels +Listan kan inte visas = Affichage de la liste impossible +Listegenskaper = Liste des propriétés +Listnamn = Nom de la liste +Listor = Listes +Listor och sammanställningar = Listes et résumés +Listpost = Entrée de liste +Listredigerare = Editeur de liste +Listredigerare – X = Editeur de liste – X +Listrubrik = Titre de liste +Listtyp = Type de liste +Listval = Choix de liste +Ljudfiler, baskatalog = Répertoire de base des fichiers sonores +Lokalt = Localement +Longitud = Longitude +Lopp %d = Course %d +Lopp %s = Course %s +Lopp X = Course X +Lotta = Tirage +Lotta / starttider = Tirage / Gestion des horaires de départ +Lotta flera klasser = Tirage de plusieurs catégories +Lotta klassen = Tirage de la catégorie +Lotta klassen X = Tirage de la catégorie 'X' +Lotta löpare som saknar starttid = Tirage des coureurs sans horaire de départ +Lotta om hela klassen = Retirage de la catégorie +Lottad = Tirage effectué +Lottad startlista = Horaires de départ tirés +Lottar efteranmälda = Tirage des inscriptions tardives +Lottar: X = Tirage des heures de départ: X +Lottning = Tirage aléatoire +Lyssna = Ecouter +Lägg till = Ajouter +Lägg till alla = Tout ajouter +Lägg till en ny rad i tabellen (X) = Ajout d'une ligne à la table (X) +Lägg till klasser = Ajout / modification des catégories +Lägg till ny = Ajouter nouveau +Lägg till ny etapp = Ajouter une nouvelle étape +Lägg till rad = Ajouter ligne +Lägg till stämpling = Ajouter le poinçon +Lägger till klubbar = Ajout de club +Lägger till löpare = Ajout de participants +Längd (m) = Distance (m) +Länk till resultatlistan = Lien vers les résultats +Länk till startlistan = Lien vers les listes de départr +Läs brickor = Lecture de puce +Läser klubbar = Lecture de clubs +Läser löpare = Lecture de coureurs +Långt namn = Nom long +Låt klassen ha mer än en bana eller sträcka = Autoriser la catégorie à avoir plus d'une variation ou d'un circuit +Löpande information om viktiga händelser i tävlingen = Obtenir des notifications pour les évènements de la compétition +Löparbricka %d = Puce % +Löpardatabasen = Base de données coureurs +Löpare = Coureur +Löpare saknar klass eller bana = Coureur sans catégorie ou circuit +Löpare som förekommer i mer än ett lag = Coureur figurant dans plus d'une équipe +Löpare utan SI-bricka: %d = Coureurs sans puce: %d +Löpare utan bana: %d = Coureurs sans circuit: %d +Löpare utan klass: %d = Coureurs sans catégorie: %d +Löpare utan klubb: %d = Coureurs sans club: %d +Löpare utan starttid: %d = Coureurs sans horaire de départ: %d +Löpare, Ej Start, med registrering (kvar-i-skogen!?) = Coureurs inscrits non partants (en forêt ?) +Löpare, Status Okänd, med registrering (kvar-i-skogen) = Coureurs inscrits avec statut inconnu (en forêt) +Löpare, Status Okänd, som saknar registrering = Coureurs non enregistrés avec statut inconnu +Löpare: = Coureurs: +Löpare: X, kontroll: Y, kl Z = Coureur: X, poste: Y, temps: Z +Löparen hittades inte = Coureur non trouvé +Löptid = Temps de course +Lösenord = Mot de passe +Man = Homme +Manuell lottning = Tirage manuel +Manuella avgifter = Frais d'inscription manuels +Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar = Entrer le premier numéro de dossard, ou laisser vide pour supprimer le dossard +Mata in radiotider manuellt = Saisir le temps de passage radio manuellement +Max antal gemensamma kontroller = Nombre max de contrôles communs +Max parallellt startande = Nombre max de départs en parallèles +Max. vakanser (per klass) = Nombre max de vacants (par catégorie) +Maximal tid efter ledaren för att delta i jaktstart = Temps max après le leader pour participer au départ en chasse +Maxtid = Temps max +Maxtid efter = Temps max après +MeOS = MeOS +MeOS lokala datakatalog är = Le répertoire local des données MeOS est +MeOS – Resultatkiosk = MeOS – Diffusion des résultats +Med stafettklasser = Avec relais +Med sträcktidsanalys = Avec analyse des temps intermédiaires +MediumFont = Texte moyen +MediumPlus = Texte un peu plus grand +Medlöpare = Co-compétiteur +Mellantider visas för namngivna kontroller = Les temps intermédiaires sont affichés pour les contrôles nommés +Metod = Méthode +Min. vakanser (per klass) = Nombre min. de vacant (par catégorie) +Minitid = Temps min. +Minst MySQL X krävs. Du använder version Y = MeOS nécessite MySQL X ou plus récent. Vous utilisez la version Y +Minsta intabbning = Indentation minimale +Minsta intervall i klass = Plus petit intervalle dans la catégorie +Minsta startintervall = Plus petit intervalle de départ +Minsta sträcktid = Partiel le plus court +Minutstartlista = par heures de départ +Motion = Exercice +Multipel = Multiple +MySQL Server / IP-adress = Serveur MySQL / adresse IP +Män = Hommes +Mål = Arrivée +Målstämpling saknas = Poinçon d'arrivée manquant +Måltid = Heure d'arrivée +Måltid saknas = Heure d'arrivée manquante +Måltid: X = heure d'arrivée: X +Namn = Nom +Nationalitet = Nationalité +Nollställ avgifter = RAZ des frais d'inscription +Nollställ databaser = RAZ base de données +Nollställde avgift för X deltagare = Effacement des droits d'inscription pour X competiteur(s) +Nolltid = Heure zéro +None = Aucun +Normal = Normal +NormalFont = Texte normal +Normalavgift = Frais normaux +Not implemented = Non implémenté +Nr = Nombre +Nummerlapp = Dossard +Nummerlappar = Dossards +Nummerlappar i X = Dossards pour X +Nuvarande innehavare: X = Détenteur : X +Ny bana = Nouveau circuit +Ny deltagare = Nouveau coureur +Ny klass = Nouvelle catégorie +Ny klubb = Nouveau club +Ny kontroll = Nouveau poste +Ny lista = Nouvelle liste +Ny tävling = Nouvelle compétition +Nyckel för Eventor = Clef Eventor +Nytt fönster = Nouvelle fenêtre +Nytt lag = Nouvelle équipe +Nästa = Suivant +Nästa etapp = Prochaine étape +Nästa försök = Nouvel essai +OE Semikolonseparerad (csv) = OE (csv) +OK = OK +Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y' = Fichier de course invalide. Un numéro de poste était attendu à la position X, mais 'Y' a été trouvé +Ogiltig föregående/efterföljande etapp = Etape précédente/suivante invalide +Ogiltig första starttid. Måste vara efter nolltid = Heure du premier départ invalide. Doit être postérieure à l'heure zéro +Ogiltig omstartstid = Heure de nouveau départ invalide +Ogiltig repdragningstid = Temps de corde invalide [Invalid rope time] +Ogiltig starttid i 'X' på sträcka Y = Heure de départ dans 'X' invalide pour le relayeur Y +Ogiltig starttid: X = Heure de départ invalide: X +Ogiltig tid = Heure invalide +Ogiltigt bricknummer X = Numéro de puce invalide X +Ogiltigt filformat = Format de fichier invalide. +Okänd bricka = Puce inconnue +Okänd funktion = Mode inconnu +Okänd klass = Catégorie inconnue +Okänd klubb med id X = Club avec identifiant X inconnu +Om MeOS = A propos de MeOS +Om MeOS – ett Mycket Enkelt OrienteringsSystem = A propos de MeOS – un logiciel de CO nettement plus simple +Omstart = Redémarrage +Omstart i stafettklasser = Redémarrage du relais +Omstartstid = Heure de redémarrage +Omvänd jaktstart = Chasse inversée +Oparad = Non apairés +Operationen misslyckades = Echec de l'opération +Operationen stöds ej = Opération non supportée +Optimerar startfördelning = Optimisation de la distribution des horaires de départ +Ordinarie anmälningsdatum = Date de dernière inscription +Ordinarie avgift = Frais d'inscription normaux +Organisation = Organisation +Oväntad kontroll 'X' i bana Y = Poste 'X' non prévu dans le circuit Y +Packar upp löpardatabas = Expension de la base des coureurs +Par- eller singelklass = Catégorie pour patrouille ou individuel +Para ihop = Apairage +Para ihop bricka X med en deltagare = Association de la puce X avec un coureur +Parallell = Parallèle +PatrolClubNameNames = Clubs des coureurs (ou de la patrouille) +PatrolNameNames = Noms des coureurs (ou de la patrouille) +Patrull = Patrouille +Patrull, 1 SI-pinne = Patrouille, une puce +Patrull, 2 SI-pinnar = Patrouille, deux puces +Personer = Personnes +Plac. = Place +Placering in = Place dans +Plats = Place +Port = Port +Port för TCP = Port TCP +Postadress = Adresse postale +Postkod = Code postal +Poäng = Points +Poäng in = Points dans +Poängavdrag (per minut) = Point de pénalité (par minute) +Poängavdrag per påbörjad minut = Point de pénalité pour toute minute entamée +Poänggräns = Limite en points +Prel. bomtid = Temps perdu (prélim.) +Prel. placering = Place (prélim.) +Prioritering = Prioritisation +Prisutdelningslista = Résultats pour la remise des prix +Programinställningar = Configuration du programme +Prolog + jaktstart = Prologue + chasse +Publicera resultat = Publication des résultats +Publicera resultat och sträcktider på Eventor och WinSplits online = Publication des résultats et des temps intermédiaires sur Eventor et WinSplits en ligne +Publicera startlista = Publication des horaires de départ +Publicera startlistan på Eventor = Publication des horaires de départ sur Eventor +Publicerar resultat = Publication des résultats +Publicerar startlistan = Publication des horaires de départ +PunchNamedTime = temps intermédiaires nommés +PunchTime = Heure de poinçonnage +Punches = Poinçons +Radera = Supprimer +Radera listan från aktuell tävling = Supprimer la liste de cette compétition +Radera starttider = Effacer les heures de départ +Radera tävlingen = Supprimer la compétition +Radera vakanser = Supprimer les vacants +Radiotider, kontroll = Heures radio, poste +Ranking = Classement +Ranking (IOF, xml) = Classement (IOF, xml) +Rapport inför = Rapport pour +Rapporter = Rapports +Rapportläge = Mode rapport +Red. avg. efteranm = Retardat. réduit +Red. avgift = Réduit +Redigera deltagaren = Editer le coureur +Redigera lista = Editer la liste +Redigera listpost = Editer une entrée dans la liste +Reducerad avg = Frais d'inscription réduits +Reduktionsmetod = Méthode de réduction +Region = Region +Relativ skalfaktor för typsnittets storlek i procent = Facteur d'échelle pour la police (pourcentage) +Rep = Corde +Reparera vald tävling = Réparer la compétition sélectionnée +Reparerar tävlingsdatabasen = Réparation de la base de données de la compétition +Repdragningstid = Heure de corde [Rope time] +Repdragningstiden måste ligga före omstartstiden = L'heure de corde doit précéder l'heure des re-départs +Reserverade = Réservé +Resultat = Résultat +Resultat && sträcktider = Résultat && temps intermédiaires +Resultat (STOR) = Résultats (GRAND) +Resultat - %s = Résultats - %s +Resultat - X = Résultats - X +Resultat banvis per klass = Résultat circuit-wise par catégorie +Resultat efter klass och bana - X = Résultats par catégorie et circuit - X +Resultat efter sträcka %d = Résultats après le relayeur %d +Resultat efter sträckan = Résultats après le relayeur +Resultat för ett visst lopp = Résultats pour une course donnée +Resultat lopp X - Y = Résultats pour la course X - Y +Resultat per bana = Résultats par circuit +Resultat per bana - X = Résultats par circuit - X +Resultat, generell = Résultats général +Resultat, individuell = Résultats individuel +Resultat, patrull = Résultats, patrouille +Resultatkiosk = Résultats kiosque [Kiosk] +Resultatlista - %s = Résultats - %s +Resultatlista – inställningar = Résultats – configuration +Resultatlistor = Résultats +Resultatutskrift = Imprimer les résultats +Resultatutskrift / export = Imprimer / Exporter les résultats +Rogaining = Course au score +Rogaining, individuell = Course au score indivduelle +Rogaining-poäng = Points (course au score) +RogainingPunch = Poinçon (course au score) +Rubrik = Titre +Rulla upp och ner automatiskt = Défillement vertical automatique +Runner = Coureur +RunnerBib = Dossard du coureur +RunnerCard = Puce du coureur +RunnerClassCoursePlace = Classement dans la catégorie pour le circuit +RunnerClassCourseTimeAfter = Retard dans la catégorie pour le circuit +RunnerClub = Club du coureur +RunnerCompleteName = Nom complet du coureur +RunnerCourse = Circuit du coureur +RunnerFamilyName = Nom de famille du coureur +RunnerFinish = Heure d'arrivée du coureur +RunnerGivenName = Prénom du coureur +RunnerLegNumberAlpha = Numéro de relais exact du coureur +RunnerLegNumber = Numéro de relais groupé du coureur +RunnerName = Nom du coureur +RunnerPlace = Place du coureur +RunnerPlaceDiff = Différence de place du coureur +RunnerRank = Classement du coureur +RunnerRogainingPoint = Points de la course au score +RunnerStart = Heure de départ du coureur +RunnerStartNo = Numéro de départ du coureur +RunnerTempTimeAfter = Temps du coureur après le poste sélectionné +RunnerTempTimeStatus =Temps/statut du coureur au poste sélectionné +RunnerTime = Temps du coureur +RunnerTimeAfter = Retard du coureur +RunnerTimeAfterDiff = Différence de retard du coureur +RunnerTimeLost = Temps perdu par le coureur +RunnerTimePlaceFixed = Instant à partir duquel la place du coureur n'a plus évolué +RunnerTimeStatus = Temps/statut du coureur +RunnerTotalPlace = Place consolidée du coureur +RunnerTotalTime = Temps consolidé du coureur +RunnerTotalTimeAfter = Retard consolidé du coureur +RunnerTotalTimeStatus = Temps / statut consolidé du coureur +RunnerUMMasterPoint = Master points Uppsala möte +SI X inläst. Brickan tillhör Y som saknar klass = La puce X a été lue. La puce appartientt à Y, qui n'a pas de catégorie +SI X inläst. Brickan är inte knuten till någon löpare (i skogen) = La puce X a été lue. La puce est associé à aucun coureur (en forêt) +SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen = La puce X a déjà été lue. Utiliser la lecture interactive pour la relire. +SI X är redan inläst. Ska den läsas in igen? = La puce X a déjà été lue. La relire ? +SI på = SI en marche +SI-dubbletter: %d = SI dupliqué: %d +SOFT-avgift = Frais d'inscription SOFT [SOFT fee] +SOFT-lottning = Méthode de tirage suédoise +Saknad starttid = Heurede départ manquante +Sammanställning = Résumé +Sammanställning, ekonomi = Résumé financier +Sammanställning, klasser = Résumé des catégories +Samtliga deltagare tilldelades resultat = Tous les coureurs ont un résultat +Seedad lottning = Tirage au sort +Sekundär typ = Type secondaire +Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? = La taille de la sélection ne correspond pas au contenu du presse-papier. Coller tout de même ? +Semikolonseparerad (csv) = Fichier (csv) +Sen avgift = Retardat. +Sen red. avgift = Ret. réduit +Server = Serveur +Server: [X] Y = Serveur: [X] Y +Sidbrytning mellan klasser = Saut de page +Sidbrytning mellan klasser / klubbar = Saut de page entre catégories / clubs +Simulera inläsning av stämplar = Simuler la lecture de puce +Sista betalningsdatum = Paiements dus +Sista ordinarie anmälningsdatum = Date limite d'inscription au tarif normal +Sista start (nu tilldelad) = Dernier départ (affecter maintenant) +Sista start (nu tilldelad): X = Dernier départ (affecté): X +Sista sträckan = Dernier relais +Ska X raderas från tävlingen? = Voulez vous retirer X de la compétition ? +Skalfaktor = Facteur d'échelle +Skapa en ny tävling med data från Eventor = Créer une nouvelle compétition à partir des données de Eventor +Skapa en ny, tom, tävling = Créer une nouvelle compétition vide +Skapa fakturor = Générer les factures +Skapa generell lista = Créer la liste générale +Skapa listan = Créer la liste +Skapa ny klass = Créer une nouvelle catégorie +Skapad av = Créé par +Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) = Un circuit pour la catégorie %s avec %d poste dans la puce %d aété créée. +Skapade en lokal kopia av tävlingen = Copie locale de la compétition créée +Skapar ny etapp = Créer une nouvelle étape +Skapar ny tävling = Création d'une nouvelle compétition +Skapar saknad klass = Catégorie manquante créée +Skattad avgift = Frais d'inscription taxable +Skippar lottning = Ignorer le tirage au sort +Skript = Script +Skript att köra efter export = Script à exécuter après l'export +Skriv endast ut ändade sidor = Imprimer uniquement les pages modifiées +Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben = Entrer les premières lettres du nom du club et appuyer sur flèche bas pour trouver le club +Skriv första starttid på formen HH:MM:SS = Ecrire la première heure de départ au format HH:MM:SS +Skriv ut = Imprimer +Skriv ut alla = Tout imprimer +Skriv ut dem utan e-post = Imprimer tous les courriels manquants +Skriv ut ej accepterade elektroniska = Imprimer tout ce qui n'est pas encore accepté +Skriv ut eller exportera listan automatiskt = Imprimer ou exporter la liste automatiquement +Skriv ut fakturan = Imprimer les factures +Skriv ut listan = Imprimer la liste +Skriv ut nu = Imprimer maintenant +Skriv ut rapporten = Imprimer le rapport +Skriv ut sträcktider = Temps intermédiaires +Skriv ut tabellen = Imprimer la table +Skriv ut tabellen (X) = Imprimer la table (X) +Skriv över existerande bricknummer? = Ecraser le numéro de puce existant ? +Skrivare = Imprimante +Skrivarinställningar för sträcktider = Configuration de l'imprimante +Skriver sträcktider om = Impression dans +Slutresultat = Résultats finaux +Slå ihop = Fusionner +Slå ihop klass: X = Fusionner la catégorie: X +Slå ihop klass: X (denna klass behålls) = Fusionner la catégorie avec X (conserver cette catégorie) +Slå ihop klasser = Fusionner les catégories +Slå ihop klubb = Fusionner le club +SmallFont = Petit texte +SmallItalic = Texte en petit et italique +Snabbinställningar = Configuration rapide +SortNameOnly = Nom +Sortering = Tri +Sortering: %s, antal rader: %d = Tri: %s, nombre de ligne: %d +Spara = Enregistrer +Spara anmälningar = Enregistrer les inscriptions +Spara den här listan som en favoritlista = Enregistrer cette liste comme favori +Spara fil = Enregistrer le fichier +Spara för webben = Enregistrer le document web +Spara i aktuell tävling = Enregistrer dans cette compétition +Spara som = Enregistrer sous +Spara som fil = Enregistrer le fichier sous +Spara sträcktider till en fil för automatisk synkronisering med WinSplits = Enregistrer les temps intermédiaires pour synchronisation automatique avec WinSplits +Sparade listval = Listes enregistrées +Speaker = Speaker +Speakerstöd = Module Speaker +SportIdent = SPORTident +Språk = Langue +Stad = Ville +Stafett = Relais +Stafett (sammanställning) = Relais (résumé) +Stafett - sammanställning = Relais - résumé +Stafett - sträcka = Relais - relayeur +Stafett - total = Relais - total +Stafettklasser = Catégories pour le relais +Stafettresultat, delsträckor = Résulats du relais, detail relayeurs +Stafettresultat, lag = Résulats du relais, équipe +Stafettresultat, sträcka = Résulats du relais, par relayeur +Stafettresultat, sträcka (STOR) = Résulats du relais, par relayeur (GRAND) +Start = Départ +Start nr = Départ no. +StartTime = Neure de départ, nom +StartTimeForClass = Heure de départ commune, catégorie +Starta = Départ +Starta automaten = Démarrer le service +Starta en guide som hjälper dig göra klassinställningar = Démarrer un guide pour vous aider à construire les catégories +Startade automater = Services démarrés +Startande = Démarrage +Startar SI på = Démarrage du boîtier SI à +Startblock = Démarrer le bloc +Startblock: %d = Démarrer le bloc : %d +Startintervall = Intervalle de départ +Startintervall (min) = Intervalle de départ (min) +Startlista = Horaires de départ +Startlista %%s - sträcka %d = Horaires de départ %%s - Combinaison %d +Startlista - %s = Horaires de départ - %s +Startlista - X = Horaires de départ - X +Startlista ett visst lopp = Horaires de départ pour la course +Startlista lopp X - Y = Horaires de départ pour la course X - Y +Startlista, individuell = Horaires de départ individuels +Startlista, patrull = Horaires de départ, patrouille +Startlista, stafett (lag) = Horaires de départ, relais (équipe) +Startlista, stafett (sträcka) = Horaires de départ, relais (relayeur) +Startlistor = Horaires de départ +Startmetod = Méthode de départ +Startnamn = Nom du départ +Startnummer = Numéro de départ +Starttid = Heure de départ +Starttid (HH:MM:SS) = Heure de départ (HH:MM:SS) +Starttid: X = Heure de départ: X +Starttiden är upptagen = L'heure de départ n'est pas disponible +Starttyp = Type de départ +Status = Statut +Status OK = Statut OK +Status in = saisie du statut +Stoppa automaten = Arrêt du service +Stor = Grand +Str. = Relais +Str. %d = Relais %d +String = Texte +Struken = Annulé +Struken med återbetalning = Annulé, frais d'inscription remboursés +Struken utan återbetalning = Annulé, pas de remboursement des frais d'inscription +Strukturerat exportformat = Format d'export structuré +Strukturerat webbdokument (html) = Document web structuré (html) +Sträcka = Relayeur +Sträcka %d = Relayeur %d +Sträcka X = Relayeur X +Sträcka att lotta = Partiel à tirer au sort +Sträckans banor = Circuits du relais +Sträcktider = Temps intermédiaires +Sträcktider (WinSplits) = Temps intermédiaires (WinSplits) +Sträcktider / WinSplits = Temps intermédiaires / WinSplits +Sträcktider/WinSplits = Temps intermédiaires/WinSplits +Sträcktidsfil = Nom du fichier +Sträcktidsutskrift = Imprimer les temps intermédiaires +Sträcktidsutskrift[check] = Imprimer les temps intermédiaires automatiquement +Sträcktilldelning, stafett = Affectation de la combinaison, relais +Sträcktyp = Type de combinaison +Stämpelkod(er) = Poinçons +Stämpelkoder = Code de poinçon +Stämplar om = Poinçonnage de +Stämplingar = Poinçons +Stämplingar saknas: X = Poinçons manquants : X +Stämplingsautomat = Machine à poinçonner +Stämplingsintervall (MM:SS) = Intervalle entre poinçons (MM:SS) +Stämplingstest = Test de poinçonnage +Stämplingstest [!] = Test de poinçonnage [!] +Stäng = Fermer +Stäng tävlingen = Fermer la compétition +Större = Plus grand +Störst = Le plus grand +Största gruppen med samma inledning har X platser = Le plus grand groupe avec le même début a X participants +Största intervall i klass = Plus grand intervalle dans la catégorie +SubCounter = Compteur secondaire +SubSubCounter = Compteur tertiaire +Summera = Somme +Synkronisera med Eventor = Synchroniser avec Eventor +Säkerhetskopiera = Sauvegarder/Enregistrer sous +Sätt okända löpare utan registrering till = Définir le statut pour les coureurs non enregistrés +Sätt som oparad = Non appairé +Sätter reptid (X) och omstartstid (Y) för = Appliquer le temps de corde [Applying rope time] (X) et l'heure de redémarrage (Y) pour +Sök = Rechercher +Sök (X) = Rechercher (X) +Sök deltagare = Rechercher un coureur +Sök och starta automatiskt = Recherche automatique boîtier lecture +Sök på namn, bricka eller startnummer = Recherche d'un nom, d'une puce ou d'un numéro de départ +Söker efter SI-enheter = Recherche du boîtier SPORTident +TCP: Port %d, Nolltid: %s = TCP: Port %d, Heure initiale: %s +TRASIG( = Défectueux( +Ta bort = Supprimer +Ta bort / slå ihop = Supprimer / Fusionner +Ta bort listposten = Supprimer de la liste +Ta bort markerad = Supprimer la sélection +Ta bort stämpling = Supprimer le poinçon +Ta bort valda rader från tabellen (X) = Supprimer les lignes sélectionnées de la table (X) +Tabell = Table +Tabelläge = Mode table +Team = Equipe +TeamBib = Dossard de l'équipe +TeamClub = Club de l'équipe +TeamLegTimeAfter = Retard de l'équipe au relayeur +TeamLegTimeStatus = Temps / statut de l'équipe au relayeur +TeamName = Nom de l'équipe +TeamPlace = Place de l'équipe +TeamRogainingPoint = Score de l'équipe +TeamRunner = Nom des membres de l'équipe +TeamRunnerCard = Numéro de puce de l'équipe +TeamStart = Heure de départ de l'équipe +TeamStartNo = Numéro de départ de l'équipe +TeamStatus = Statut de l'équipe +TeamTime = Temps de l'équipe +TeamTimeAfter = Retard de l'équipe +TeamTimeStatus = Temps / statut de l'équipe +Telefon = Téléphone +Test = Test +Test av stämplingsinläsningar = Test de poinçonnage +Testa rösten = Test de synthèse vocale +Text = Texte +Text: X = Texte: X +Textfiler = Fichiers texte +Textstorlek = Taille du texte +Tid = Temps +Tid efter: X = Retard: X +Tid efter: X; har tagit in Y = Temps après: X; gagné Y +Tid efter: X; har tappat Y = Temps après: X; perdu Y +Tid in = Temps à +Tid: X, nuvarande placering Y/Z = Temps: X, place actuelle Y/Z +Tidsavdrag: X poäng = Pénalité : X points +Tidsgräns = Limite en temps +Tidsinmatning = temps manuels +Tidsintervall (MM:SS) = Intervalle de temps (MM:SS) +Tidsjustering = Ajustement de l'heure +Tidslinje – X = Chronologie – X +Tidsskalning = Echelle de temps +Till huvudsidan = Vers la page principale +Till kontroll = Vers le poste +Tilldela = Affecter +Tilldela avgifter = Affecter les frais d'inscription +Tilldela endast avgift till deltagare utan avgift = Affecter les frais d'inscription uniquement aux coureurs sans frais +Tilldela hyrbrickor = Affecter les puces louées +Tilldela nummerlappar = Affecter les dossards +Tilldelning av hyrbrickor = Affecter les puces louées +Tillgängliga automater = Services disponibles +Tillsatte vakans = Vacants utilisés +Tillsätt vakans = Remplir les vacants +Tillämpa parstart = Démarrer l'apairage +Tillåt decimaler = Autoriser les décimales +Tillåt direktanmälan = Autoriser la saisie rapide +Tillåt valutauttryck med decimaler = Autoriser les expressions monétaires avec décimales +Topplista, N bästa = Podiums, N meilleurs +Total = Total +Total tävlingsavgift = Recette totale +TotalCounter = Compteur primaire +Totalresultat = Résultat total +Totalresultat - X = Résultat total - X +Totalt = Total +Totalt faktureras = Facturation totale +Totalt kontant = Total des espèces +Totaltid = Temps total +Trasig = Défectueux +Träning = Entrainement +Tvåmannastafett = Relais en binôme +Typ = Type +Typ av delning = Type de temps intermédiaire +Typ av export = Type d'export +Typ av lista = Type de liste +Typsnitt = Police +Tävling = Compétition +Tävling från Eventor = Compétition depuis Eventor +Tävlingen innehåller inga resultat = Il n'y a pas encore de résultat +Tävlingen måste ha ett namn = Un nom doit être donné à la compétition +Tävlingens namn: X = Le nom de la compétition est : X +Tävlingsdata har sparats = Les données de la compétition ont été sauvées +Tävlingsinställningar = Configuration de la compétition +Tävlingsinställningar (IOF, xml) = Configuration de la compétition (IOF, xml) +Tävlingsnamn = Nom de la compétition +Tävlingsrapport = Rapport sur la compétition +Tävlingsregler = Règles de la compétition +Tävlingsstatistik = Statistiques de la compétition +Underlag för tävlingsavgift = Données pour les frais d'inscription de la compétition +Underlista = Sous liste +Underrubrik = Sous-titre +Undre datumgräns = Date limite basse [Lower date limit] +Undre gräns (år) = Limite basse (années) +Undre ålder = Age minimal +Ungdom = Jeune +Ungdomsavgift = Tarif jeunes +Ungdomsklasser = Catégories jeunes +Uppdatera = Mise à jour +Uppdatera alla klubbar = Mise à jour de tous les clubs +Uppdatera alla värden i tabellen = Mise à jour de la table +Uppdatera alla värden i tabellen (X) = Rafraîchir les valeurs de la table (X) +Uppdatera från Eventor = Mise à jour depuis Eventor +Uppdatera fördelning = Mise à jour de la diffusion +Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan = Mise à jour de la diffusion des horaires de départ en prenant en compte les changements manuels +Uppdatera klubbar && löpare = Mise à jour des clubs et coureurs +Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret = Mise à jour des clubs et coureurs en utilisant la base de données des coureurs +Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret = Mise à jour des clubs en utilisant la base de données des coureurs +Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret = Mise à jour du club en utilisant la base de données des coureurs +Uppdatera löpardatabasen = Mise à jour de la base de données des coureurs +Urval = Filtrer +Urval %c%s = Filtrer %c%s +Utan inställningar = Pas de configuration +Utan tidtagning = Pas de chronométrage +Utbyt tävlingsdata med Eventor = Echange des données de la compétition avec Eventor +Utför lottning = Effectuer le tirage au sort +Utfört = Fait +Utg. = Aband. +Utskrift / export = Imprimer / exporter +Utskriftsintervall (MM:SS) = Intervalle d'impression (MM:SS) +Utökat protokoll = Protocole étendu +VALFRI( = UnParmis( +Vak. ranking = Classement des vacants +Vakanser = Vacants +Vakanser / klassbyte = Changements tardifs +Vakanser och efteranmälda = Vacants et retardataires +Vakanser stöds ej i stafett = Les vacants ne sont pas supporté en relais +Vakant = Vacant +Val av export = Choisir Export +Valbar = Optionel +Vald bricka = Puce choisie +Valuta = Devise +Valutakod = Code devise +Valutasymbol = Symbole monétaire +Valutasymbol före = Symbole monétaire devant la valeur +Varning: Deltagaren 'X' finns inte = Attention: Le coureur 'X' n'existe pas +Varning: Laget 'X' finns inte = Attention: L'équipe 'X' n'existe pas +Varning: Banan 'X' finns inte = Attention: le circuit 'X' n'existe pas +Varning: Banan 'X' förekommer flera gånger = Attention: Le circuit 'X' est définie plus d'une fois +Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) = Attention: Aucun organisateur défini (Voir Configuration de la compétition) +Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Attention: Pas de compte défini (Voir Configuration de la compétition) +Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) = Attention: Aucune date limite de paiement définie (Voir Configuration de la compétition) +Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Attention: Un coureur sans nom a été détecté. MeOS a besoin d'un nom, et a affecté le nom 'N.N.' +Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Attention: Une équipe sans nom a été détectée. MeOS a besoin d'un nom et a affecté le nom 'N.N.' +Verkställ = Confirmer +Version X = Version X +Vi stöder MeOS = Nous soutenons MeOS +Viktiga händelser = Evènements importants +Vill du flytta löpare från X till Y och ta bort Z? = Voulez vous déplacer les coureurs de X vers Y et supprimer Z ? +Vill du klistra in X nya rader i tabellen? = Voulez vous coller X nouvelles lignes dans la table ? +Vill du lägga till banan 'X' (Y)? = Souhaitez vous ajouter le circuit 'X' (Y)? +Vill du lägga till deltagaren 'X'? = Souhaitez vous ajouter le coureur 'X'? +Vill du lägga till klassen 'X'? = Souhaitez vous ajouter la catégorie 'X'? +Vill du lägga till laget 'X'? = Souhaitez vous ajouter l'équipe 'X'? +Vill du radera X rader från tabellen? = Voulez-vous supprimer X lignes de la table ? +Vill du radera alla vakanser från tävlingen? = Voulez-vous supprimer tous les vacants de la compétition ? +Vill du skapa en ny klass? = Voulez-vous créer une nouvelle catégorie ? +Vill du spara ändringar? = Voulez-vous sauver les changements ? +Vill du verkligen radera alla starttider i X? = Voulez-vous vraiment effacer les horaires de départ dans X? +Vill du verkligen radera starttider i X klasser? = Voulez-vous vraiment effacer les horaires de départ de la catégorie X ? +Vill du verkligen radera tävlingen? = Sohaitez-vous supprimer la compétition ? +Vill du verkligen stänga MeOS? = Souhaitez-vous fermer MeOS ? +Vill du verkligen ta bort laget? = Souhaitez-vous supprimer l'équipe ? +Vill du verkligen ta bort löparen? = Souhaitez-vous supprimer le coureur ? +Visa = Afficher +Visa alla = Afficher tout +Visa avancerade funktioner = Afficher la configuration avancée +Visa en tabell över alla stämplingar = Afficher la table avec les poinçons +Visa klubbdatabasen = Afficher la base de données des clubs +Visa listan i fullskärm = Afficher la liste en plein écran +Visa löpardatabasen = Afficher la base de données des coureurs +Visa mellantider = Afficher les temps intermédiaires +Visa och hantera löpardatabasen = Afficher et gérer la base des coureurs +Visa senast inlästa deltagare = Afficher le coureur de la dernière lecture de puce +Visa startlistan = Afficher la liste des départs +Visa tillgängliga säkerhetskopior = Afficher les sauvegardes disponibles +Visa valda deltagare = Afficher les coureurs sélectionnés +Visar de X bästa = Affichage des X meilleurs +Visualisera startfältet = Visualisation des champs de départ +Vuxen = Adulte +Vuxenklasser = Catégories adultes +Vuxna = Adultes +Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad = Clicker sur pour enregistrer la puce. La lecture interactive n'est pas activée +Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad = Clicker sur pour enregistrer les puces. La lecture interactive est activée +Välj alla = Sélectionner tout +Välj alla klasser = Sélectionner toutes les catégories +Välj allt = Sélectionner tout +Välj automatiskt = Sélection automatique +Välj den etapp som föregår denna tävling = Sélectionner l'étape précdente +Välj den etapp som kommer efter denna tävling = Sélectionner l'étape suivante +Välj en vakant plats nedan = Choisissez une place vacante ci-dessous +Välj ingen = Désélectionner +Välj inget = Désélectionner +Välj klass = Sélectionner la catégorie +Välj klass och starttid nedan = Choisissez la catégorie et l'heure de départ ci-dessous +Välj klasser = Choisir les catégories +Välj klasser där alla löpare saknar starttid = Sélectionner les catégories où aucun coureur n'a d'heure de départ +Välj klasser där någon löpare saknar starttid = Sélectionner les catégories où des coureurs n'ont pas d'heure de départ +Välj kolumner = Choisir les colonnes +Välj kolumner att visa = Choisir les colonnes à afficher +Välj kolumner för tabellen X = Choisir les colonnes pour la table X +Välj lista = Sélectionner la liste +Välj lopp = Sélectionner la course +Välj löpare = Choisir un coureur +Välj löpare att prioritera bevakning för = Sélectionner les coureurs à privilégier +Välj löpare för sträcka X = Définir le coureur pour la variation X +Välj skrivare = Choisir une imprimante +Välj tävling = Choisir une compétition +Välj vilka klasser och kontroller du vill bevaka = Choisir les catégories et les postes que vous souhaitez observer +Välj vilka klasser och kontroller som bevakas = Sélectionner les catégories et les postes à observer +Välj vilka kolumner du vill visa = Choisr les colonnes à afficher +Välj vy = Choisir la vue +Välkommen till MeOS = Bienvenue dans MeOS +Vänligen betala senast = Merci de régler au plus tard le +Vänligen återlämna hyrbrickan = Merci de rendre votre puce de location +Växling = Changement +Webb = Document Web +Webbdokument = Document Web +Webbdokument (html) = Document Web (html) +Webben (html) = Le web (html) +X (Saknar e-post) = X (n'a pas de courriel) +X (Y deltagare, grupp Z, W) = X (Y coureurs, groupe Z, W) +X har startat = X est parti +X kontroller = X postes +X meter = X mètres +X poäng fattas = X points manquant +X rader kunde inte raderas = X lignes ne peuvent être effacées +X senaste = X derniers +X: Y. Tryck för att spara = X: Y. Appuyez sur pour sauver +Zooma in (Ctrl + '+') = Zoomer (Ctrl + '+') +Zooma ut (Ctrl + '-') = Dézoomer (Ctrl + '-') +[Bevaka] = [Observer] +[Flytta ner] = [Descendre] +[Bort] = [Supprimer] +[Klassens bana] = [De la catégorie] +[Uppdaterad anmälan] = [Mise à jour de l'inscription] +[VARNING] ingen/okänd = [ATTENTION] aucun/inconnu +[Återställ] = [Remise à zéro] +andra = seconde +ask:addpunches = Aucune puce n'a été lue pour ce coureur. Voulez-vous ajouter des poinçons manuellement ? +ask:changedclassfee = Le tarif a été modifié pour certaines catégories. Voulez-vous appliquer les nouveaux tarifs aux coureurs déjà présents dans ces catégories ?\n\nAttention: les frais d'inscription affectés manuellement seront écrasés. +ask:changedcmpfee = Les tarifs ont été modifiés. Voulez-vous appliquer les nouveaux tarifs aux coureurs et classes existantes ?\n\nAttention les frais d'inscription affectés manuellement seront écrasés. +ask:firstasstart = Il existe des coureurs ayant des résultats pour ce circuit. Si vous utilisez le premier poste comme départ, les heures de départ seront écrasées.\n\nSouhaitez-vous continuer ? +ask:kiosk = Quand vous démarrez la diffusion des résultats, vous mettez MeOS dans un mode où il est uniquement possible d'afficher les résultats. Aucune autre opération n'est autorisée jusqu'à ce que le programme soir redémarré. S'il y a un boîtier SI actif raccordé à l'ordinateur, MeOS affichera automatiquement les résultats pour la dernière puce lue.\n\nVous devriez penser à protéger la base de donnée avec un mot de passe, si la diffusion est rendue publique.\n\nVoulez-vous démarrer la difusion des résultats ? +ask:missingcourse = Des catégories (X) n'ont pas de circuit.\n\nMeOS utilise les circuits lors du tirage pour éviter que les coureurs ayant le même premier poste ne partent en même temps.\n\nVoulez-vous continuer tout de même ? +ask:overwrite_server = La compétition est déjà sur le serveur. Voulez-vous écraser la compétition présente sur le serveur ? +ask:overwriteconfirm = Vous avez choisi d'écraser la compétition. Vérifiez que personne d'autre n'est connecté.\n\nSouhaitez vous continuer ? +ask:repair = Effectuez une réparation de la base de données uniquement si vous rencontrez des problèmes.\n\nImportant:\n- Assurez-vous que personne d'autre n'est connecté à la base.\n- Si le serveur plante ou s'arrête pendant la réparation, vous devez le redémarrer et réessayer la réparation avant d'effectuer quoi que ce soit d'autre. Si vous faites d'autres opération avec la base de données toutes les données seront perdues.\n\nSouhaitez-vous essayer une réparation maintenant ? +backup = sauvegarde +c/o = Aux bon soins de +check (X) = Vérification de (X) +ej aktiv = inactif +elfte = onzième +elva = onzième +ett Mycket Enkelt OrienteringsSystem = un logiciel GEC bien plus simple +eventor:help = Si vous utilisez MeOS pour la CO en Suède, nous recommandons que vous utilisiez les fonctionnalités de connexion Eventor. +eventor:question = X\n\nSouhaitez-vous utiliser la connexion à Eventor ? +femma = cinquième +femte = cinquième +fjärde = quatrième +fritt att använda och du är välkommen att distribuera det under vissa villkor = gratuit, et vous êtes invités à le diffuser sous certaines conditions +fyra = quatrième +går i mål på X plats med tiden Y = termine X en Y +går i mål på X plats, efter Y, på tiden Z = termine X, derrière Y, en Z +går upp i delad ledning med tiden X = partage la tête de la course avec un temps de X +handskakning = authentification +har startat = a démarré +help:10000 = Un service dans MeOS est un petit programme qui, de temps à autre ou lorsque les données de la compétition changent, fait des choses automatiquement. +help:12138 = Choisr une catégorie à fusionner avec la catégorie choisie. Si le tirage des catégories a été effectué, vous devez refaire un tirage, car les coureurs conservent leur horaire de départ. +help:12290 = La compétition a été créée avec une autre version de MeOS et ne peut pas être ouverte depuis le serveur. Vous pouvez toutefois la compétition depuis un fichier. +help:12352 = Cette opération supprime le club que vous avez choisi (%s, id=%d) et déplace tous les coureurs de ce club vers le club que vous choisissez ci-dessous. L'opération ne peut être annulée. +help:12662 = Ajoutez des postes en ajoutant une séquence de numéros de postes. Vous ne devez pas préciser l'arrivée. Exemple: 31, 50, 36, 50, 37, 100. +help:14070 = Le port TCP est utilisé pour recevoir les poinçons par TCP depuis d'autres machines. Précisez le port utilisé. L'instant initial du protocole est 00:00:00. +help:14343 = Une liste avec la puce lue est affichée. Pour affecter un coureur à une autre puce, double cliquez sur la puce ou le coureur que vous souhaitez déplacer. +help:146122 = Vous pouvez étendre les connaissances de MeOS sur les coureurs, clubs et catégories en cherchant les bases de données au format MeOS ou IOF (xml).\n\nSouhaitez vous effectuer cette opération ? +help:14692 = Saisir le numéro de poste, le coureur (numéro de départ ou de puce) et l'heure (HH:MM:SS). Vous pouvez laisser le champ heure vide; l'heure du PC sera alors utilisée. Appuyez sur pour enregistrer. +help:15491 = Vous pouvez exporter les configurations ainsi que les bases de données des clubs et coureurs dans le répertoire de votre choix. Ces configurations et bases de données peuvent être importées sur un autre PC. +help:21576 = En cas d'erreur, cliquer sur le nom des coureurs pour modifier la saisie. Utiliser la page des coureurs pour supprimer les enregistrements. Pour voir une catégorie dans la liste ci-dessous, elle doit être marquée pour saisie rapide sur la page des catégories. +help:25041 = Ici vous déclarez vos circuits. Un circuit est alors lié à une ou plusieurs catégories (ou coureurs). Il est également possible d'importer des circuits depuis OCAD, Condes, ou tout autre logiciel d'élaboration de circuits. Si vous spécifiez le nombre de cartes, MeOS contrôlera le nombre de cartes disponibles dans le formulaire de saisie rapide. +help:26963 = Un ensemble de circuits est utilisé pour définir un ensemble de partiels pour une branche. Le circuit est affecté au compétiteur à l'arrivée sur la base des postes poinçonnés. Définissez les partiels dans le groupe en les ajoutant dans Circuits Multiples/Relais. Un [S] après la catégorie signifie que tous les compétiteurs ont un horaire de départ. +help:29191 = Vous pouvez installer les configurations, clubs et base de données des coureurs à partir d'un répertoire source spécifié. Vos configurations locales sont écrasées. MeOS devrait être redémarré après l'installation.\n\nLe bouton vous conduit à une page où vous pouvez exporter votre configuration courante. +help:29758 = Ici vous gérez les clubs et l'impression des factures. Vous pouvez définir un tarif prenant en compte le type de catégorie et la date d'inscription. Les clubs en double (mal orthographiés) peuvent être regroupés dans le club correct. Vous pouvez également mettre à jour les adresses de clubs à partir du tableau de comptes. +help:30750 = Vous pouvez créer un grand nombre de listes et rapports différents. Ceux-ci peuvent être visualisés à l'écran, imprimés, ou sauvés dans un format web. La liste est automatiquement mise à jour lorsque des données liées à la compétition changent. L'impression automatique des résultats s'obtient à partir de la page Services. Pour exporter les données de la compétition, par exemple les temps intermédiaires, aller à la page Compétition. +help:31661 = Un nouveau départ (en masse) est défini par une barrière horaire et une heure de reprise. A la barrière horaire les passages de relais sont terminés et aucun compétiteur n'est autorisé à partir en forêt. Les concurrents restants partent à l'heure de la barrière horaire. Il est possible de spécifier différents horaires pour des partiels précis, mais en utilisant cett efonction vous pouvez rapidement prendre en charge des catégories entières. +help:33940 = Importer les inscriptions en format texte libre. Spécifier le nom, le club, la catégorie et le numéro de puce (éventuellement l'heure de départ), de préférence séparés par des virgules, une personne (équipe) par ligne. Il est également possible de spécifier plusieurs compétiteurs dans le même club / catégorie en laissant partiellement vides ces champs. Il est également possible d'importer des données formatées par d'autres moyens. +help:41072 = Sélectionner un poinçon dans la liste pour le modifier ou le supprimer. Vous pouvez ajouter des poinçons manquants à partir du modèle de course. Si l'heure d'arrivée est manquante, le coureur obtient le statut . Si un poinçon est manquant, le statut est . Il est impossible d'assigner un statut incompatible avec les poinçons. S'il y a un poinçon d'arrivée, vous devez le modifier pour pouvoir définir manuellement l'heure d'arrivée. Le même principe s'applique au poinçon de départ. +help:41641 = Entrez un premier horaire de départ et un intervalle. Tirage Aléatoire affecte un ordre de départ totalement aléatoire. La Méthode de Tirage Suédoie utilise des règles spéciales pour répartir les coureurs d'un même club. Départ groupé signifie que la catégorie complète part par petits groupes pendant la durée spécifiée (Départ en masse étendu). Dans le champ Partiel vous pouvez spécifier quel partiel doit être tiré au hasard si la catégorie en a plusieurs. +help:425188 = Vous pouvez gérer automatiquement les compétiteurs qui ne sont pas partis en lisant les boîtiers SI (clear/check/start/controls) dans SIConfig. Sauvegarder les données lues en tant que fichier texte dont les colonnes sont séparées par des points-virgules, et importez ce fichier dans MeOS. Les compétiteurs figurant dans cet import reçoivent un enregistrement. Vous pouvez alors donner le statut DNS à tous les compétiteurs n'ayant pas d'enregistrement. Si ultérieurement vous importez d'autres coureurs, vous pouvez réinitialiser le statut (de DNS à Inconnu) sur les compétiteurs alors importés. +help:471101 = Activez le boîtier SI en sélectionnant son port COM ou en recherchant les boîtiers SI installés. Appuyez sur Information pour obtenir le statut du port sélectionné.\n\nLecture Interactive vous permet de gérer directement les problèmes tels qu'un numéro de puce erroné. N'utilisez pas cette possibilité quand les compétiteurs ayant des problèmes sont pris en charge séparément.\n\nLa base de données des compétiteurs est utilisée si vous voulez ajouter automatiquement de nouveaux compétiteurs. Les poinçons sont utilisés pour trouver (détecter) la bonne catégorie. +help:50431 = Vous êtes désormais connecté à un serveur. Pour ouvrir une compétition sur le serveur, sélectionnez le dans la liste et cliquer Ouvrir. Ajoutez une compétition au serveur, ouvrez la compétition en local et sélectionnez Télécharger. Quand vous aurez ouvert une compétition sur le serveur, vous pourrez voir tous les autres clients MeOS connectés. +help:52726 = Connectez vous à un serveur ci-dessous.\n\nInstallation\nTélécharger et installer MySQL 5 (Community Edition) depuis www.mysql.com. Vous pouvez utiliser la configuration par défaut. Il est uniquement nécessaire d'installer MySQL sur l'ordinateur servant de serveur. Quand MySQL est installé, démarrer MySQL Command Line Client et créez un compte utilisateur pour MeOS. Ecrire quelque chose du genre :\n\n> CREATE USER meos;\nGRANT ALL ON *.* TO meos;\n\nVous avez maintenant un utilisateur meos sans mot de passe. Entrez le nom du serveur ci-dessous (vous pouvez avoir à configurer les pare-feu pour laisser passer le traffic).\n\nComme alternative vous pouvez utiliser le compte root d'origine de MySQL. Le nom d'utilisateur est 'root' et le mot de passe est celui donné lors de l'installation de MySQL. +help:5422 = Pas de boîtier SI trouvé. Sont-ils connectés et démarrés ? +help:59395 = Dans ce formulaire, vous pouvez rapidement effectuer des réglages de base en une seule opération pour plusieurs catégories.\n\nDépart est le nom du départ tel qu'il apparaît sur les liste d'horaire de départ.\n\nUn Bloc est un nombre entre 0 et 100 qui peut fournir une distribution des compétiteurs encore plus fine. Les catégories dans le même bloc seront imprimées dans la même minute sur les horaires de départ. \n\nIndex est une clé de tri. Les catégories sont triées à l'aide de cette clé dans toutes les listes.\n\nLe circuit peut être défini pour les catégories ayant exactement un circuit; s'il y a plusieurs circuits possibles vous devez utiliser le formulaire standard de catégorie.\n\nSaisie rapide détermine si la catégorie accepte les inscriptions rapides. +help:59395_more = The class fees, which shows if you have activated Economy features, are used for new entries. If you change a fee, MeOS will ask if you wish to apply the change to existing competitors.\n\nFor bibs you have the options None, Consecutive and Manual. You can also type the first bib in the class, for example A100, or 50. Consecutive means that the last number of the preceeding class is used to define the first number in this class. Reserved bib numbers gives a gap (of the specified width) in the numbering between classes.\n\nMeOS updates bibs when you draw start times or change the settings. Manual means that MeOS will never automatically update bibs.\n\nFor classes with teams the setting Team member controls the relation between the team number and the bibs. It can be the same, increasing (100, 101, 102), leg dependent (100-1, 100-2, etc.) or completely independent. +help:7618 = Le nombre de compétiteurs dans l'équipe est défini dans la page Catégories. +help:7620 = Intervalle (secondes). Laisser le champ vide pour qu'il soit mis à jour quand la compétition évolue. +help:89064 = Pour chaque poste, vous devez spécifier un ou plusieurs numéro de code (codes SI). Dans un circuit, vous faites référence à un poste par son identifiant (ID). Habituellement vous n'avez pas besoin d'ajouter des postes manuellement puisque MeOS ajoute automatiquement tous les postes nécessaires.\n\nL'utilisation de plus d'un code SI est utile lorsque l'on veut remplacer un boîtier défectueux ou pour créer des fourches simples. Pour un poste ordinaire, il est exigé que le compétiteur poinçonne un des postes spécifiés. Si le statut du poste est , tous les postes spécifiés doivent être poinçonnés (dans un ordre quelconque). Si le statut est , le boîtier est ignoré.\n\nSi vous spécifiez un nom de poste, il est possible d'imprimer les résultats avec les temps intermédiaires aux postes nommés.\n\nUn réajustement de l'heure du poste peut être effectué s'il apparaît que le boîtier n'était pas à l'heure. Le format de l'heure est +/-MM:SS ou +/-HH:MM:SS.\n\nLe temps de partiel le plus court définit le temps le plus court possible sur ce partiel. Aucun concurrent n'aura un temps plus court pour aller à ce poste, aussi rapide soit-il. Cela peut être utilisé, par exemple, si une route dangereuse doit être traversée.\n\nLe statut signifie que le temps pour aller au poste est ignoré; le temps total sera le même quel que soit le temps réellement mis pour se rendre au poste. +help:9373 = Donnez un ou plusieurs numéro de postes (codes SI) utilisés pour ce poste.\nExemple: 31, 32, 33. +help:9615 = Aucune réponse reçue. Voulez-vous ouvrir le port en mode passif ? MeOS doit-il être à l'écoute de poinçons à venir ? +help:assignfee = MeOS va prendre en charge automatiquement pour vous les droits d'inscription dans la plupart des cas. Le tarif est basé sur l'âge et la date d'inscrition des compétiteurs (vous pouvez définir les limites dans Configuration de la compétition). Chaque catégorie définit un tarif. Vous fournissez une valeur par défaut pour différentes catégories dans Configuration de la Compétition, mais vous pouvez également reconfigurer la catégorie en utilisant Configuration Rapide pour cette catégorie.\n\nCette page vous permet d'utiliser différentes limites en âges et date limites d'inscription pour différents tarifs. Sur la page des Compétiteurs, vous pouvez ajuster manuellement le tarif pour chaque compétiteur en cas de besoin. +help:baudrate = Vitesse de transmission (baudrate) : utilisez 4800 ou 38400. +help:computer_voice = Un poinçon arrivant est mis en correspondance avec un numéro de départ et joue le fichier où N est le numéro de départ. Les fichiers sont situés dans le répertoire ci-dessous. Si le compétiteur/équipe a une nationalité NAT d'affectée, MeOS essaie en priorité de jouer le fichier , qui se doit de contenir le nombre dans la version de langue appropriée. +help:dbage = La base de donnée des compétiteurs dat ede plus de deux mois. Souhaitez vous télécharger une nouvelle base à partir d'Eventor ? +help:duplicate = Faire une copie locale de cette compétition. +help:eventorkey = Entrez la clef Eventor de votre club (spécial Suède). Vous pouvez obtenir la clef auprès de l'administrateur Eventor de votre club. +help:fullscreen = Vous pouvez ajuster la vitesse de défilement en utilisant Ctrl+M (augmente) et Ctrl+N (diminue). Pour sortir du mode plein écran, appuyez sur Esc. +help:import_entry_data = Vous pouvez importer des compétiteurs, des catégories, des clubs et des inscriptions à partir de divers formats texte et XML. Il n'est pas nécessaire de fournir tous les fichiers ci-dessous. Par exemple, un fichier CSV de OE avec les inscriptions contient les clubs et les catégories, aussi dans ce cas ces champs devraient-ils être laissés vides.\n\nSi le même compétiteur est importé plusieurs fois vous n'obtiendrez pas plusieurs copies de ce compétiteur, mais son inscription sera modifiée. Cela signifie qu'il est sans danger de ré-importer ou d'importer un fichier d'inscription qui a été étendu. +help:importcourse = Vous pouvez importer des circuits et des catégories à partir (par exemple) d'exports OCAD ou Condes. +help:ocad13091 = Si vous avez accès aux circuits (par exemple à partir d'OCAD ou Condes) vous pouvez fournir les fichiers contenant les circuits ici. Autrement, vous pourrez ajouter les circuits ultérieurement. +help:relaysetup = Utilisez le guide ci-dessous pour choisir parmis les formulaires de compétitions prédéfinis. Après avoir appliqué la configuration, il est possible d'adapter manuellement la configuration pour chaque partiel et configurer les circuits.\n\nQuelques explications :\n- Relais est utilisé pour différent type de relais.\n- Relais par paire signifie que deux compétiteurs forme une équipe et courent à tour de rôle.\n- Un relais en Co-compétition est parfois utilisé dans les catégories jeunes et permet d'avoir plus d'un compétiteur sur certains partiels. (le premier compétiteur change d'une fois à l'autre).\n- Une patrouille peut s'effectuer avec une ou deux puces.\n- Prologue et poursuite est une compétition individuelle mais constitué de deux courses.\n- Un pool de circuit signifie qu'il y a plusieurs variantes, mais qu'il n'est pas décidé à l'avance qui court sur quelle variante; la décision est prise automatiquement lorsque le coureur a terminé. +help:restore_backup = Choisissez une sauvegarde à restaurer en cliquant la date à laquelle la sauvegarde a été faite. +help:runnerdatabase = En important une base de donnée de clubs et de coureurs, MeOS reconnaitra automatiquement les coureurs inconnus (par leur numéro de puce), et vous aurez les adresses et numéros de téléphone du club. +help:save = MeOS sauve automatiquement toutes les configurations lorsque c'est nécessaire. +help:speaker_setup = Choisissez les catégories et circuits que vous voulez surveiller. +help:speakerprio = Cochez les coureurs/équipes que vous souhaitez surveiller dès le départ et tant que tout va bien. Mettre deux coches pour surveiller même si le résultat n'est plus très bon. Aucune coche signifie que la surveillance n'est activée que si le coureur/l'équipe a de bons résultats (donc pas forcément depuis le départ). +help:splitexport = Décidez si vous voulez exporter les résultats individuellement ou globalement pour chaque course. Si vous choisissez d'exporter toutes les courses, des fichiers numérotés seront créés. +help:startmethod = MeOS utilisera automatiquement la méthode de départ choisie. Quoi que vous choisissiez ici, vous pourez dans tous les cas changer la méthode de départ ou refaire le tirage plus tard. +help:winsplits_auto = Ce service sauvegarde les temps intermédiaires dans un fichier IOF (xml) à intervalles réguliers. Si vous ouvrez ce fichier dans WinSplits, les temps intermédiaires seront mis à jour en temps réel. +help:zero_time = Définissez l'heure zéro à une heure avant le premier départ prévu. +help:long_times = La date de compétition est la date à laquelle toutes les catégories commencent. L'heure zéro est à minuit. +help_autodraw = Fournit une première heure de départ (ordinaire), un intervalle minimal (pour une catégorie) et le pourcentage de vacants. Vous pouvez également choisir la méthode utilisée pour le tirage au sort et si les retardataires doivent partir avant ou après les autres coureurs. Le premier horaire de départ doit être postérieur l'heure zéro de la compétition.\n\nSi vous cliquez sur , MeOS vérifie toutes les catégories. Si la catégorie n'a pas eu de tirage celui-ci est effectué. S'il y a des retardataires sans horaires de départ dans une catégorie, leur horaire de départ sera tiré au sort.\n\nMeOS garantit que les coureurs ayant des circuits similaires ne partent pas simultanément, et de la place est réservée pour permettre l'accueil de retardataires dans les même conditions.\n\nSi au contraire vous cliquez sur vous pouvez contrôler exactement quelle catégories sont tirées au sort et avec quels paramètres. +help_draw = Le tirage au sort des horaire de départ se fait en deux temps. Premièrement vous choisissez les catégories et entrz quelques paramètres. Quand vous appuyez sur MeOS utilise vos paramètres pour attribuer les plages d'horaires entre les catégories. MeOS garantit que les catégories ayant des circuits similaires ne partent pas ne même temps en prenant en compte toutes les catégories ayant déjà eu un tirage. L'objectif est une répartition uniforme des partants.\n\nLa répartition calculée se présente sous la forme d'une table dans laquelle vous pouvez effectuer vos propres modifications, ou laisser MeOS mettre à jour sa répartition en prenant en compte vos modifications. Lorsque vous êtes satisfaits avec la répartition, vous laisser MeOS faire le tirage au sort des catégories sélectionnées.\n\nLes paramétrages que vous devez effectuer consistent à fournir l'heure du premier départ possible, et le plus petit intervalle de temps entre coureur autorisé. Le nombre maximal de départ en parallèle détermine combien de coureurs peuvent prendre le départ en même temps. Une valeur plus importante conduit à une durée de départ plus faible.\n\nLe pourcentage de vacants détermine le nombre d'horaires laissés disponibles. Si vous n'en voulez aucune, entrez 0%. Le nombre prévu de retardataires réserve de la place pour ces derniers dans la liste de départ, avec la garantie qu'aucun coureur prenant le départ au même moment n'aura un circuit identique. +info:multieventnetwork = Pour prendre en charge plus d'une étape vous devez travailler localement. Faite une copie de sauvergarde de la compétition, ouvrez-la en local et transferrez les résultats à l'étape suivante. Enfin, remontez l'étape suivante sur le serveur. +info:readout_action = X: Puce no. Y lue.\nDes actions manuelles sont requises. +info:readout_queue = X: Puce no. Y lue.\nLa puce a été mise en file d'attente. +inforestwarning = Aucun concurrent ne semble être encore en forêt. Comme les données qui ont servi à émettre cette conclusion peuvent être erronées, vous devez vérifier qu'aucun concurrent n'est encore en forêt par d'autres moyens. +kartor = carte +klar = établir +kontroll = poste +kontroll X (Y) = poste X (Y) +localhost = machine locale +lopp = course +mål = arrivée +målet = l'arrivée +målet (X) = l'arrivée (X) +nia = neuvième +nionde = neuvième +radio X = radio X +saknas = manquant +se license.txt som levereras med programmet = voir le fichier license.txt fourni avec le logiciel +serverbackup = sauvegarde du serveur +sexa = sixième +sjua = septième +sjunde = septième +sjätte = sixième +skicka stämplar = envoyer le spoinçons +sortering: X, antal rader: Y = ordre de tri: X, nombre de lignes: Y +starten (X) = le départ (X) +sträcka %d = variation %d +stämplade vid = a poinçonné +stämplar vid X som Y, på tiden Z = poinçonne à X en tant que Y, en Z +tar ledningen med tiden X = prend la tête en X +tia = dixième +till = à +tionde = dixième +tolfte = douzième +tolva = douzième +tooltip:analyze = Analyse les donnée et prévisualise les données importées. +tooltip:builddata = Etendre les connaissances de MeOS des coureurs, clubs et catégories en analysant les données de la compétition. +tooltip:import = Importer depuis un fichier. +tooltip:inforest = Liste des coureurs en forêt et des coureurs n'ayant pas pris le départ. +tooltip:paste = Coller depuis le presse papier. +tooltip:resultprint = Imprimer les résultats à l'écran +tooltip:voice = Synthèse vocale des pré-annonces. +trea = troisième +tredje = troisième +tvåa = second +väntas till X om någon minut = est attendu sous peu au poste X +väntas till X om någon minut, och kan i så fall ta en Y plats = est attendu au poste X dans la minute, et peut prendre la Y place. +väntas till X om någon minut, och kan i så fall ta ledningen = est attendu au poste X dans la minute, et peut prendre la tête de la course. +växeln = passage de relais +växlar på X plats med tiden Y = passage de relais au poste X avec un temps de Y +växlar på X plats, efter Y, på tiden Z = passage de relais à la X place, après Y, avec un temps de Z +växlar på delad X plats med tiden Y = devient X avec un temps de Y +warn:changedtimezero = Changer l'heure zéro d'une compétition ayant des résultats n'est pas recommandé.\n\nVoulez vous tout de même faire ce changement ? +warn:olddbversion = La base de donnée est utilisée par une version postérieure de MeOS. Une mise à jour est recommandée. +warning:dbproblem = ATTENTION. Problèmes rencontrés avec la connexion à la base: 'X'. La connexion sera automatiquement restaurée. Vous pouvez continuer à travailler normalement. +warning:drawresult = La catégorie a déjà des résultats, les heures de départ seront écrasées. Voulez-vous continuer ? +warning:has_entries = La catégorie a déjà des coureurs . Changer la réparition des variations à ce stade peut entraîner un eperte de données.\n\nVoulez-vous continuer ? +warning:has_results = La catégorie a déjà des résultats. Changer la réparition des variations à ce stade est inhabituel.\n\nVoulez-vous continuer ? +xml-data = données xml +Äldre protokoll = Protocole périmé +Ändra = Modifier +Ändra grundläggande inställningar och gör en ny fördelning = Modifier les configuration de base et faire une nouvelle répartition +Ändra inställningar = Modifier les configurations +Ändra klassinställningar = Modifier les configurations de catégorie +Ändra lag = Changer l'équipe +Ändra sträckindelning = Modifier la configuration des variations +Ändrad = Modifié +Ändrade avgift för X deltagare = Tarif modifié pour X coureur(s) +Åldersfilter = Filtrer suivant l'âge +Åldersgräns ungdom = Age minimal +Åldersgräns äldre = Age maximal +Åldersgränser, reducerad anmälningsavgift = Age limite pour tarif réduit +Ångra = Annuler la saisie +Återansluten mot databasen, tävlingen synkroniserad = Reconnecté à la base de donnée, compétition synchronisée +Återbud = Annuler l'inscription +Återgå = Retour +Återställ = Restaurer +Återställ / uppdatera klasstillhörighet = Réinitialiser / modifier la catégorie du coureur +Återställ löpare med registrering till = Passer le statut à pour les coureurs inscrits +Återställ säkerhetskopia = Restaurer la sauvegarde +Återställ tabeldesignen och visa allt = Restaurer la présentation de la table +ÅÅÅÅ-MM-DD = AAAA-MM-JJ +Öppen = Open +Öppen klass = Catégorie Open +Öppna = Ouvrir +Öppna fil = Ouvrir le fichier +Öppna från aktuell tävling = Ouvrir depuis cette compétition +Öppna föregående = Ouvrir le précédent +Öppna föregående etapp = Ouvrir l'étape précédente +Öppna i ett nytt fönster = Ouvrir dans une nouvelle fenêtre +Öppna klasser, ungdom = Ouvrir les catégories jeunes +Öppna klasser, vuxna = Ouvrir les catégories adultes +Öppna nästa = Ouvrir le sivant +Öppna nästa etapp = Ouvrir l'étape suivante +Öppna tävling = Ouvrir la compétition +Öppna vald tävling = Ouvrir la compétition sélectionnée +Öppnad tävling = Compétition ouverte +Överför anmälda = [Transfer entires] +Överför nya deltagare i ej valda klasser med status "deltar ej" = Transférer les nouveaux coureurs dans les catégories non sélectionnées avec le statut "Ne participe pas" +Överför resultat = Transférer les résultats +Överför resultat till X = Transfert des résultats à X +Överför resultat till nästa etapp = Transfert des résultats à l'étape suivante +Övre datumgräns = Date au plus tard +Övre gräns (år) = Date au plus tard (années) +Övre ålder = Age maxi +Övriga = Autre +är först i mål med tiden X = est premier à l'arrivée en X +är först vid X med tiden Y = est premier au poste X en Y +är först vid växeln med tiden X = est premier au passage de relais avec un temps de X +är inte godkänd = est disqualifié +återställd = restauré +åtta = huit +åttonde = huitième +Kopia (X) = Copier (X) +Tillåt samma bana inom basintervall = Autoriser le même circuit dans l'intervalle de base [within base interval] +Välj X = Selectionner X +Ett startblock spänner över flera starter: X/Y = Un bloc de départ couvre plus d'un départ: X/Y +Bricka X = Puce X +RunnerTimePerKM = Allure min/km +X är inget giltigt sträcknummer = X n'est pas un numéro de variation valide +Listan togs bort från tävlingen = La liste a été retirée de la compétition +Töm = Effacer +Status matchar inte deltagarnas status = Le statut ne correspond pas au statut du coureur. +Status matchar inte data i löparbrickan = Le statut ne correspond pas au donnée contenues dans la puce. +Döp om = Renommer +går upp i delad ledning vid X med tiden Y = partage la tête de la course au poste X, en Y +X:e = X:ème +tar ledningen vid X med tiden Y = prend la tête au poste X, en Y +Eventor server = Serveur Eventor +(har stämplat) = (a poinçonné) +documentation = meos_doc_eng.html +Hittar inte hjälpfilen, X = Documentation introuvable, X +X har redan ett resultat. Vi du fortsätta? = X a déjà un résultat. Souhaitez-vous continuer ? +Aktuell tid = Heure courante +Godkänd = OK +Nummerlapp, SI eller Namn = Dossard, puce ou nom +Utgått = Aband. +Manuell inmatning = Entrée manuelle +Tilldelad = Affecté +Eventors tider i UTC (koordinerad universell tid) = Heure UTC d'Eventor +Exportera tider i UTC = Heure UTC d'export +Tidszon = Fuseau horaire +RunnerAge = Age du coureur +RunnerBirthYear = Année de naissance du compétiteur +RunnerFee = Prix payé par le coureur +RunnerNationality = Nationalité du coureur +RunnerPhone = Numéro de téléphone du coureur +RunnerSex = Sexe du coureur +TeamFee = Prix payé par l'équipe +Varning: ändringar i X blev överskrivna = Attention: les changements dans X ont été écrasés +help:simulate = Ce service vous permet de simuler des lectures de puces. Des temps et des poinçons sont générés pour tous les participants. Même les postes radio peuvent être simulés.\n\nATTENTION: A n'utiliser que pour les tests. Si vous utilisez cette fonctionnalité sur une vraie course, elle sera corrompue. +Rogainingresultat - %s = Résultats de la course au score - %s +TeamPlaceDiff = Ecart de place de l'équipe (étape courante) +TeamTotalPlace = Place finale de l'équipe (toutes les étapes) +TeamTotalTime = Temps total de l'équipe (toutes les étapes) +TeamTotalTimeAfter = Retard total de l'équipe (toutes les étapes) +TeamTotalTimeDiff = Ecart total de l'équipe (étape courante) +TeamTotalTimeStatus = Temps total ou statut de l'équipe (toutes les étapes) +Vill du dumpa aktuellt tävling och skapa en testtävling? = Voulez vous faire un dump de la compétition courante et créer une compétition de test ? +Radera alla klubbar = Effacer tous les clubs +Radera alla klubbar och ta bort klubbtillhörighet = Effacer tous les clubs et les membres des clubs +Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa = Souhaitez-vous effacer tous les clubs de la compétition ? Aucune compétition n'aura de club. +Besökare = Visiteurs +Föregående kontroll = Poste précédent +Ja = Oui +Nej = Non +På banan = Sur le circuit +Stämpelkod = Code du poste +Tidpunkt = Temps +Antal deltagare = Competiteurs +Förekomst = Occurrence +Exporterar om = Export dans +Exportformat = Format d'export +Filnamnsprefix = Préfixe du nom de fichier +Mapp = Répertoire +Mappnamnet får inte vara tomt = Le nom du répertoire ne peut pas être vide +Onlineresultat = Résultats en ligne +Packa stora filer (zip) = Compresser les grands fichiers (zip) +Publicera resultat direkt på nätet = Publier les résultats directement sur le web +Resultat online = Résultats en ligne +Skicka till webben = Envoyer sur le web +Spara på disk = Sauver sur disque +Till exempel X = Par exemple X +Tävlingens ID-nummer = Identifiant de la compétition +URL = URL +URL måste anges = URL manquant +Tidsintervall (sekunder) = Intervalle de temps (secondes) +Antal skickade uppdateringar X (Y kb) = Nombre de mise à jour X (Y kb) +Filen finns redan: X = La destination existe déjà: X +Misslyckades med att ladda upp onlineresultat = Echec lors de la monté des résultats sur Internet +Onlineservern svarade felaktigt = Le serveur distant a fourni une réponse inattendue (Configuration incorrecte ?) +Onlineservern svarade: ZIP stöds ej = Réponse du serveur distant : ZIP non supporté. +Onlineservern svarade: Serverfel = Réponse du serveur distant: Erreur du serveur +Onlineservern svarade: Felaktigt lösenord = Réponse du serveur distant : Mot de passe incorrect +Onlineservern svarade: Felaktigt tävlings-id = Réponse du serveur distant : Identifiant de compétition incorrect +Online Results Error X = Erreur dans les résulatts en ligne X +PDF = PDF +ClassTeamLeg = Catégorie, équipe, relayeur +Okänd = Inconnu +Antal hämtade uppdateringar X (Y kb) = Nombre de mise à jour reçues X (Y kb) +Använd ROC-protokoll = Utiliser le protocole ROC +Definierade mappningar = [Defined mappings] +Funktion = Fonction +Hämta stämplingar m.m. från nätet = Retrouver des poinçons etc... depuis Internet. +Inmatning online = Saisie à distance +Kod = Code +Kontrollmappning = [Control Mapping] +Ogiltig funktion = Fonction invalide +Ogiltig kontrollkod = Code de poste invalide +Onlineinput = Saisie distante +Online Input Error X = Erreur de saisie distante X +Ekonomi = Comptabilité +Fakturainställningar = Configuration de la facturation +Hantera klubbar = Gestion des clubs +Spara som PDF = Sauver en tant que PDF +Avgifter och valuta ställer du in under = Les tarifs et les monnaies sont changés depuis +Fakturanummer = Numéro de facture +Formatering = Format +Första fakturanummer = Premier numéro de facture +Koordinater (mm) för adressfält = Coordonnées (mm) du champ d'adresse +Organisatör = Organisateur +Tilldela nya fakturanummer till alla klubbar? = Affecter un nouveau numéro de facture à tous les clubs ? +Exportera alla till PDF = Tout exporter en PDF +help:onlineresult = Le service est utilisé pour envoyer automatiquement les résultats et les listes de départ sur Internet pour publication immédiate dans des formulaires. Vous devez créer des configurations adaptées au service distant que vous voulez utiliser : le fournisseur du service distant vous fournira tous les détails utiles.\n\nSi vous voulez développer vos propres services, vous trouverez de la documentation et des exemples sur le site web de MeOS : www.melin.nu/meos. +help:onlineinput = Le service est utilisé pour recevoir les poinçons radio depuis Internet, par exemple un poste radio raccordé à l'aide d'un téléphone sans fil. Il est également possible de créer un formulaire en ligne où les numéros de dossard seront saisis manuellement au fur et à mesure des passages.\n\nLe protocole du service supporte également d'autres moyens de saisie, tels que les équipes [team line-up], des saisies directes, des changements de puce etc. Si vous voulez développer vos propres services, vous trouverez de la documentation et des exemples sur le site web de MeOS : www.melin.nu/meos. +Egna textrader = Ligne de texte personnalisée +Inga bommar registrerade = Aucune erreur de poste détectée +Inställningar sträcktidsutskrift = Configuration de l'impression des temps intermédiaires +Med km-tid = Inclure l'allure (min/km) +Tidsförluster (kontroll-tid) = Temps perdu (poste-temps) +Underlag saknas för bomanalys = Aucune donnée pour les erreurs de poste +min/km = min/km +X har redan bricknummer Y. Vill du ändra det? = X a déjà la puce Y. Voulez-vous la changer ? +Avmarkera 'X' för att hantera alla bricktildelningar samtidigt = Décocher 'X' pour gérer toutes les affectations de puces sur une seule page +Bricknr = Numéro de puce +Knyt automatiskt efter inläsning = Affectation automatique à la lecture de la puce +Knyt bricka / deltagare = Affecter une puce à un coureur +Nummerlapp, lopp-id eller namn = Dossard, identifiant de la course ou nom +Lopp-id = Identifiant de la course +Markera 'X' för att hantera deltagarna en och en = Cocher 'X' pour gérer les compétiteurs un par un +Installerbara listor = Listes pouvant être installées +Listor i tävlingen = Listes dans la compétition +Radera permanent = Suppression définitive +Tillgängliga listor = Listes disponibles +Vill du ta bort 'X'? = Voulez-vous supprimer 'X'? +classcourseresult = Résultats par catégorie et par circuit +Hantera egna listor = Gérer les listes personnalisées +Redigera = Editer +Skriver sträcktider när tävlingsdata ändras = Ecriture du fichier quand les données de la compétition changent +Bana med slingor = Circuits avec boucles +En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning = Un circuit avec des boucles autorise le coureur à effectuer les boucles dans n'importe quel ordre. +Varvningskontroll = Poste commun +warn:notextended = INFO: Programmez les boîtiers en protocole étendu avec SI.Config pour accélérer la lecture de puce. +help:DirectResult = - S'il n'y a pas de circuit, le statut est mis à OK sur le poinçon d'arrivé.\n\n- S'il y a des circuits, les poinçons radio sont utilisés comme postes. Aucune lecture de puce n'est nécessaire. +Resultat vid målstämpling = Résultat sur le poinçon d'arrivée +Stämpling = Poinçon +Skicka och ta emot snabb förhandsinformation om stämplingar och resultat = Envoyez et recevoir des pré-informations rapides sur les poinçons et résultats +Centrera = Centrer +Färg = Couleur +Höger = Droite +PunchControlCode = Numéro de poste +PunchControlNumber = Numéro de poinçon +PunchControlPlace = Place sur le partiel vers le poste +PunchControlPlaceAcc = Place après le poste +PunchLostTime = Temps perdu au poste +Slå ihop text med föregående = Fusionner avec le précédent +Textjustering = Ajustement du texte +Vänster = gauche +X (press Ctrl+Space to confirm) = X (Appuyez sur + pour confirmer) +Press Enter to continue = Appuyez sur pour continuer +ask:overwriteresult = X a déjà des résultats. Voulez-vous les écraser ? +Brickan används av X = La puce est utilisée par X +DATABASE ERROR = ERREUR DE BASE DE DONNEE +Lyssnar på X = Ecoute de X +vid kontroll X = au poste X +info:runnerdbonline = Comme vous êtes connecté à un serveur, il n'est pas possible d'étiter les bases de données club et compétiteurs manuellement. Effectuez les changements avant d'uploader la compétition sur un serveur. Il est également possible de remplacer la base de données existante sur le serveur en important une nouvelle base (à partir de IOF XML). +ask:cleardb = Voulez-vous effacer les données club et compétiteurs ? +Banan saknar rogainingkontroller = La compétition n'a pas de poste de type course au score +Banans kontroller ger för få poäng för att täcka poängkravet = Les postes de type course au score n'attribuent pas assez de points +CustomSort = Ordre personnalisé +Brickhantering = Gestion des poinçons +HTML med AutoRefresh = HTML avec rafraîchissement automatique +Importera laguppställningar = Alignement des équipes importées [Import Team Line-Ups] +MeOS Funktioner = Fonctionnalités MeOS +Målfil = Fichier de destination +Spara tid = Heure enregistrée [Save time] +Stämplingstid = Instant de poinçonnage +Data from result module (X) = Données fournies par le module de résultat (X) +Forkings = Variations [Forkings] +Forkings for X = Variations pour X +Gruppera = Groupe +Resultatuträkning = Calcul des résultats +RunnerRogainingPointTotal = Total des points du compétiteur +Show forking = Montrer les variations +Standard = Standard +TeamRogainingPointTotal = Total des points de l'équipe +The forking is fair = Les variations sont équitables +Underfilter = Sous filtre +Ogiltigt lag på rad X = Equipe invalide ligne X +Okänd klass på rad X = Catégorie inconnue ligne X +Klassen X är individuell = La catégorie X est individuelle +Använd befintliga deltagare = Utiliser les compétiteurs déjà inscrits +Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka) = Regrouper les compétiteurs existants à l'équipe (identifiés par le nom et/ou le numéro de puce) +Laguppställning = Constitution de l'équipe [Team Line-up] +Bakåt = Retour +Bibs = Dossards +Club and runner database = Base de donnée des clubs et compétiteurs +Clubs = Clubs +Economy and fees = Gestion et frais d'inscription +Forked individual courses = Circuit individuel avec variations +General = General +Manual point reductions and adjustments = Réduction des points et ajustements +Manual time penalties and adjustments = Pénalités en temps et ajustements +MeOS Features = Fonctionnalités de MeOS +MeOS – Funktioner = MeOS – Fonctionnalités +Patrols = Equipe +Prepare start lists = Preparation des listes de départ +Relays = Relais +Several MeOS Clients in a network = Plusieurs clients MeOS en réseau +Several races for a runner = Plusieurs compétitions pour un concurrent +Spara laguppställningar = Sauver l'alignement de l'équipe [Save Team Line-Ups] +Teams and forking = Equipes et variations +Track runners in forest = Suivi des coureurs en forêt +Vacancies and entry cancellations = Places disponibles et annulation des inscriptions +Banan saknas = Circuit manquant +Klassen saknas = Catégorie absente +Alla lopp som individuella = Toutes les courses sont individuelles +Exportera individuella lopp istället för lag = Exporter comme courses individuelles au lieu de par équipe +Exportera startlista = Exporter les horaires de départ +Exporttyp = Type d'export +Exportval, IOF-XML = Configuration de l'export, IOF-XML +Failed to read file = Echec lors de la lecture du fichier. +Klassval = Sélection de catégorie +The forking is not fair = Les variations ne sont pas équitables +Unfair control legs = Branche non équitable +Växel = Passage +help:teamlineup = Ici vous pouvez importer un alignement d'équipe à partir d'un fichier texte structuré qu'il est facile de produire manuellement à partir d'un tableur. Le fichier doit avoir le format suivant :\n\nCatégorie;Nom de l'équipe;[Club]\nCompétiteur 1;[No de puce];[Club];[Circuit];[Catégorie du compétiteur]\nCompétiteur 2;[No de puce];[Club];[Circuit];[Catégorie du compétiteur]\n...\nCatégorie;Nom de l'équipe;[Club]\n...\n\nLes champs marqués entre crochets [] sont optionnels. Notez que les catégories et circuits utilisées doivent exister, et que le nombre de branches dans la catégorie doit correspondre au nombre de ligne définissant les compétiteurs après la catégorie. Des lignes vides peuvent être utilisées s'il n'y a pas de compétiteur. L'option signifie que seulement les compétiteurs déjà inscrits à la compétition sont ajoutés à l'équipe; les autres compétiteurs spécifiés sont ignorés. +Poängjustering = Point d'ajustment +Use initials in names = Utiliser les initiales comme noms +Exportera klubbar (IOF-XML) = Export des clubs (IOF-XML) +Exportera personer (IOF-XML) = Export des personnes (IOF-XML) +Töm databasen = Effacement des données +Several stages = Plusieurs étapes +Assign courses and apply forking to X = Assigner un circuit et appliquer la variation à X +Assign selected courses to selected legs = Assigner les circuits sélectionnés aux branches sélectioonnées +Calculate and apply forking = Calculer et utiliser les variations +Clear selections = Effacer les sélections +Define forking = Definir les variations +Forking setup = Configuration des variations +Leg X: Do not modify = Branche X: Ne pas modifier +Legs = Branches +help:assignforking = Cette fonction calcule un jeu de variation optimal pour les circuits sélectionnés. Affecter un ou plusieurs circuits aux branches en sélectionnant les circuits et les branches à partir des listes ci-dessus. Tous les circuits peuvent avoir le même ensemble de circuits (même variation) ou bien utiliser divers jeux de circuits pour différentes variations. De même dans ce cas, MeOS va calculer les variations de ces circuits entre eux, si les circuits le permettent. +Leg X = Branche X +Leg X: Use Y = La branche X: utilise Y +Created X distinct forkings using Y courses = X variations distinctes ont été créées à partir de Y circuits +Clear Memory = Effacement de la mémoire +Create Competition = Creation de la compétition +Print Card Data = Imprimer les données de la puce +Print card data = Imprimer les données de la puce +help:analyzecard = Cette fonction vous permet d'imprimer les données de la puce sans utiliser une quelconque compétition, comme le ferait une borne d'impression autonome. Sélectionner 'Imprimer les temps intermédiaires' pour choisir et configurer l'imprimante.\n\nLes puces sont également conservées en mémoire (mais pas dans la compétition). Vous pouvez éditer le nom et le club pour une puce en cliquant le nom (ou 'inconnu'). Vous pouvez également sauver les puces dans un fichier (Enregistrer) ou créer une nouvelle compétition à partir des données des puces. Notez que si une compétition est ouverte, vous devez la fermer pour rendre cette option disponible. +Använd endast en bana i klassen = Utiliser uniquement un circuit pour la catégorie +Gafflade banor = Circuits avec variations +Unroll split times for loop courses = Dérouler les temps intermédiaires pour les circuits en boucle. +Löpare per klass = Compétiteurs par catégorie +Alla funktioner = Toutes les fonctionnalités +Anmäl inga deltagare nu = Aucune inscription +Datum (för första start) = Date (du premier départ) +Endast grundläggande = Fonctionnalités de base +Funktioner i MeOS = Fonctionnalités de MeOS +Första tillåtna starttid = Heure du premier départ possible +Importera anmälda = Importer les inscriptions +Individuell tävling = Compétition individuelle +Namn och tidpunkt = Nom et heure +Skapar tävling = Creation de la compétition +Tävling med lag = Compétition en équipe +Tävlingen måste avgöras mellan X och Y = La compétition doit se dérouler entre X et Y +Tävlingens namn = Nom de la compétition +Välj från lista = Sélection détaillée +Välj vilka funktioner du vill använda = Sélectionnez les fonctionnalités de MeOS dont vous avez besoin pour cette compétition +Individuellt, gafflat = Individuel, avec variations +Skapa tävlingen = Créer la compétition +newcmp:featuredesc = Selectionnez les fonctionnalités de MeOS dont vous avez besoin pour cette compétition. Vous pouvez ajouter ou supprimer des fonctionnalités à tout moment en sélectionnant sur la page Compétition. +Exportera till fil = Exporter dans un fichier +FilterPrelResult = Résultats prél. +FinishTimeReverse = Temps inversés (le dernier en premier) +Open a Copy = Ouvrir une copie +Point calculation for runner = Calcul du nombre de points pour un compétiteur +Point calculation for team = Calcul du nombre de points pour l'équipe +Result score calculation for runner = Détermination du score pour un compétiteur +Result score calculation for team = Détermination du score pour une équipe +ResultDescription = Nom du type de résultat +Skapa = Créer +Status calculation for runner = Détermination du status pour un compétiteur +Status calculation for team = Détermination du status pour une équipe +Support time from control = Temps depuis le poste [Support time from control] +Support time to control = Temps vers le poste [Support time to control] +Time calculation for runner = Calcul du temps pour un compétiteur +Time calculation for team = Calcul du temps pour une équipe +TimingFrom = Nom du point de départ +TimingTo = Nom du point d'arrivée +Applying rules to the current competition = Appliquer les règles à la compétition courante +Available symbols = Symboles disponibles +Cancel = Annuler +Description = Description +Edit Clubs = Edition des clubs +Edit Result Modules = Edition des modules de résultats +Edit rule for = Editer la règle pour +Name of result module = Nom du module de résultat +New Result Module = Nouveau modul ede résultat +New Set of Result Rules = Nouvel ensemble de règles de résultat +Result Calculation = Calcul du résultat +Result Module – X = Module résultat – X +Result module identifier = Identificateur de module de résultat +Result Modules = Modules de résultats +Save = Enregistrer +Save changes = Enregistrer les changements +Source code = Code source +Test Result Module = Module de test de résultat +Result score calculation for team = Calcul du score pour l'équipe +Time: X = Temps : X +Start: X = Départ : X +Index in X[index] = Index en X[index] +X är inget giltigt index = X n'est pas un index valide +ResultModuleNumber = Module de résultat : Nombre +ResultModuleTime = Module de résultat : Temps +ResultModuleNumberTeam = Module de résultat : Nombre (pour l'équipe) +ResultModuleTimeTeam = Module de résultat : Temps (pour l'équipe) +RunnerRogainingOvertime = Dépassement de temps pour le compétiteur (course au score) +RunnerRogainingReduction = Réduction du nombre de points du compétiteur +TeamRogainingOvertime = Dépassement de temps pour l'équipe (course au score) +TeamRogainingReduction = Réduction du nombre de points pour l'équipe +Automatic rogaining point reduction = Réduction automatique du nombre de points pour la course au score +Choose result module = Choisir un module de résultat +Deviation +/- from expected time on course leg = Ecart +/- par rapport au temps estimé sur le partiel +Leg number in team, zero indexed = Partiel en équipe, indexé à partir de zéro +Length of course = Longueur du circuit +Maximum allowed running time = Temps de course maximal autorisé +Place on course leg = Classement sur le partiel du circuit +Result Modules = Modules de résultat +Runner's card, matched control ids (-1 for unmatched punches) = La puce du compétiteur correspond aux n° de poste (-1 par poinçon différents) +Runner's card, punch codes = Puce du compétiteur, n° de poinçon +Runner's card, punch times = Puce du compétiteur, heure du poinçon +Runner's course = Circuit du compétiteur +Runner's split times = Temps intermédiaires du compétiteurs +Runner's total running time to control = Temps total du compétiteur jusqu'au poste +Runner/team fee = Droit d'inscription compétiteur/équipe +Runner/team finish time = Heure d'arrivée compétiteur/équipe +Runner/team input place = Place initiale compétiteur/équipe +Runner/team input points = Points initiaux compétiteur/équipe +Runner/team input running time = Temps de course initial compétiteur/équipe +Runner/team input status = Status initial compétiteur/équipe +Runner/team place = Place compétiteur/équipe +Runner/team rogaining overtime = Dépassement du temps pour compétiteur/équipe (course au score) +Runner/team rogaining points = Point compétiteur/équipe (course au score) +Runner/team rogaining points adjustment = Ajustement des points compétiteur/équipe (course au score) +Runner/team running time = Temps de course compétiteur/équipe +Runner/team start time = Heure de départ compétiteur/équipe +Runner/team status = Status compétiteur/équipe +Runner/team time adjustment = Ajustement du temps compétiteur/équipe +Runner/team total place = Place finale compétiteur/équipe +Runner/team total running time = Temps total de course compétiteur/équipe +Runner/team total status = Status final compétiteur/équipe +Shortest time in class = Meilleur temps de la catégorie +Status as computed by your status method = Status tel que calculé par votre méthode +Status code for a missing punch = Code de status pour un poinçon manquant +Status code for a time over the maximum = Code de status en cas de dépassement du temps +Status code for a valid result = Code de status pour un résultat valide +Status code for an unknown result = Code de status pour un résultat inconnu +Status code for disqualification = Code de status pour une disqualification +Status code for not competing = Code de status en cas d'absence +Status code for not finishing = Code de status en cas d'abandon +Status code for not starting = Code de status en cas de non prise de départ +Points as computed by your point method = Points tels que calculés par votre méthode +Time as computed by your time method = Temps tel que calculé par votre méthode +Time after leg winner = Temps après le vainqueur du partiel +Finish time for each team member = Heure d'arrivée pour chaque équipier +Matched control ids (-1 for unmatched) for each team member = Postes corrects pour chaque équipier (-1 en cas de différence) +Punch codes for each team member = No de poinçon pour chaque équipier +Punch times for each team member = Heure de poinçonnage pour chaque équipier +Result Modules = Modules résultat +Rogaining points for each team member = Points pour chaque équipier (course au score) +Runner's method output numbers = Méthode de génération de nombre pour les compétiteurs [Runner's method output numbers] +Runner's method output times = Méthode de génération des temps pour les compétiteurs [Runner's method output times] +Running time for each team member = Temps de course pour chaque équipier +Start time for each team member = Heure de départ pour chaque équipier +Status for each team member = Status de cahque équipier +Check: X = Vérification : X +Debug = Debug +Debug Output = Sortie de debug +Debug X for Y = Debug X pour Y +Do you want to clear the card memory? = Voulez vous effacer la puce ? +Portable Document Format (PDF) = Portable Document Format (PDF) +Poängavdrag = Réduction de point +RunnerPointAdjustment = Ajustement des points du compétiteur +RunnerTimeAdjustment = Ajustement du temps du compétiteur +Save changes in rule code? = Enregistrer les changements dans le code de la règle ? +Symboler = Symboles +TeamPointAdjustment = Ajustement des points de l'équipe +TeamTimeAdjustment = Ajustement du temps de l'équipe +Variabler = Variables +Check: X = Véfification : X +Choose result module = Choisir le module de résultat +Result Modules = Modules de résultat +Error in result module X, method Y (Z) = Erreur dans le module de résultat 'X', méthode 'Y'\n\nZ +Invalid operator X = Opérateur invalide X +Unknown symbol X = Symbole inconnu X +RunnerGlobal = Competiteur (catégories regroupées) +TeamGlobal = Equipe (catégories regroupées) +List Error: X = Erreur de liste : X +Rader markerade med (*) kommer från en lista i tävlingen = Les lignes avec une (*) proviennent d'une liste de la compétition +Resultatmodulen används i X = Le module de résultat est utilisé dans X +Valfri = Optionnel +Vill du sätta resultatet från tidigare etapper till ? = Voulez vous modifier le résultat des étapes précédentes en (Not taking part = absent)? +Hantera deltagare som bytt klass = Traitement des compétiteurs qui ont changé de catégorie +Välj klasser med nya anmälningar = Spécifiez les catégories pour lesquelles de nouvelles inscriptions sont autorisées +Byt till rätt klass (behåll eventuell starttid) = Basculer vers la bonne catégorie (conserver l'heure de départ) +Byt till vakansplats i rätt klass (om möjligt) = Déplacer vers un horaire vaquant dans la bonne catagorie (si possible) +Tillåt ny klass, behåll resultat från annan klass = Autoriser de nouvelles catégories et conserver les résultats des autres catégories +Tillåt ny klass, inget totalresultat = Autoriser de nouvelels catégories mais sans résultat global +tooltip_explain_status = - = Status inconnu (pas encore de résultat)\nOK = Résultat valide\nDNS = Did Not Start (non parti)\nMP = Missing Punch (poiçon manquant)\nDNF = Did Not Finish (abandon)\nDISQ = Disqualifié\nOMT = Over Maximum Time (dépassement du temps maxi)\nNTP = Not Taking Part (absent) +Placering = Place +Resultat från tidigare etapper = Résultats des étapes précédentes +Input Results = Saisir les résultats [Input Results] +Input Results - X = Saisir les résultats - X +Individuella resultat = Résultats individuels +Avdrag = Réduction +Team Rogaining = Course au score en équipe +Övertid = Dépassement en temps +Kunde inte öppna tävlingen = Ouverture de la compétition impossible +warn:opennewversion = La compétition a été créée avec MeOS X. Les données peuvent être perdues si vous continuez.\n\nVoulez vous continuer ? +District id number = Identifiants distincts +Kunde inte ladda X\n\n(Y) = Chargement impossible de X\n\n(Y) +Narrow Results = Réduire la liste des résultats +Club id number = Identifiant du club +User input number = Paramètre saisi par l'utilisateur +listinfo:singleclub = Créer une liste de résultats pour un seul club.\nUtilisez le paramètre de saisi pour spécifier l'identifiant du club. +listinfo:inputresults = Afficher les résultats initiaux depuis les étapes précédentes. +Ett värde vars tolkning beror på listan = Une valeur ayant une interprétation dépendant d'une liste +Listparameter = Paramètre de la liste +Individual results in a club = Résultats individuel au sein du club +OL-Skytte med tidstillägg = Orientation/Tir avec pénalité en temps +OL-Skytte utan tidstillägg = Orientation/Tir sans pénalité en temps +OL-Skytte stafettresultat = Relais Orientation/Tir +Sluttid = Temps final +olshooting:timepunishment = Liste de résultats Orientation/Tir avec pénalité en temps.\n\nActiver les support pour la course au score et les ajustements manuels de points. Utilisez ensuite la réduction de points sur la page Compétiteurs pour spécifier les pénalités sous la forme PPPLLSS, où PPP est l'erreur de position en millimètres, LL est le nombre de tirs ratés allongé et SS est le nombre de tirs ratés debout. Exemple 30201 signifie 3 mm d'erreur, 2 tirs allongés et 1 tir debout ratés. +olshooting:notimepunishment = Liste de résultats Orientation/Tir sans pénalité en temps.\n\nActiver les support pour la course au score et les ajustements manuels de points. Utilisez ensuite la réduction de points sur la page Compétiteurs pour spécifier les pénalités sous la forme LLSS, où LL est le nombre de tirs ratés allongé et SS est le nombre de tirs ratés debout. Exemple: 0201 signifie 2 tirs allongés et 1 tir debout ratés. +Namnet kan inte vara tomt = Le nom ne peut pas être vide +Ingen / okänd = Aucun / inconnu +Inget nummer = Aucun nombre +Stafettresultat = Résultats de relais +Döp om X = Renommer X +Gräns för maxtid = Barrière horaire (OMT) +Individual Example = Exemple de course individuelle +Long = Longue +MeOS Three Days Race X = Les 3 jours MeOS X +Medium = Moyenne +Open = Ouvrir +Open X = Ouvrir X +Prologue + Pursuit = Prologue + Poursuite +Relay Example = Exemple de relais +Short = Court +Ultra Long = Ultra Longue +Tillgängliga filer installerades. Starta om MeOS. = Les configurations ont été installées. Redémarrez MeOS S.V.P. +edit_in_forest = Gérer\nCompétiteurs en forêt +Latest Results = Résultats récents +warning:direct_result = Notez que l'utilisation de nécessite que tous les poinçons de tous les postes du circuit aient été transmis comme poste radio, ou que MeOS soit utilisé pour chronométrer uniquement sans tenir compte du circuit.\n\nUtiliser les résultats sur poinçon d'arrivée ? +Inställningar startbevis = Configuration de l'impression des tickets de départ +Skrivarinställningar = Configuration de l'impression +Skrivarinställningar för sträcktider och startbevis = Configuration de l'impression des tickets de temps intermédiaires et de départ +Startbevis = Ticket de départ +Startbevis X = Ticket de départ X +Skriv ut startbevis = Ticket de départ +Skriv ut startbevis för deltagaren = Imprimer le ticket de départ du coureur +Utskrift = Imprimer +Från klassen = de la catégorie +Tillsätt ytterligare vakans = Fill Another Vacancy +Överföring = Transférer +Anmäl till efterföljande etapper = Enter for subsequent stages +Totalt antal etapper = Nombre total d'étapes +Vill du använda den nya brickan till alla etapper? = +Avkortad banvariant = Course raccourcie +Avkortning = Raccourci +Hantera laget = Gérer l'équipe +Med avkortning = Avec raccourci +info_shortening = Sélectionnez un circuit existant qui raccourcit le circuit sélectionné. Plusieurs niveaux de raccourcissement sont possibles. +Tilldela starttider = Attribuer des heures de départ +Avkortar: X = Raccourcit: X +Vill du nollställa alla manuellt tilldelade banor? = Voulez-vous effacer tous les circuits manuellement attribués ? +Ange löpande numrering eller första nummer i klassen = Specify consecutive numbering between classes or specify first number in class +Ange relation mellan lagets och deltagarnas nummerlappar = Specify the relation between team's bib and team member's bibs +Lagmedlem = Membre de l'équipe +Löpande = Consécutif +Oberoende = Indépendant +Samma = Same +Ökande = Increasing +Manuell = Manuel +Vill du uppdatera alla nummerlappar? = Do you want to update all bibs? +Hela banan = Circuit entier +Ogiltigt maximalt intervall = Intervalle maximum invalide +Startintervallet får inte vara kortare än basintervallet = +Ett startintervall måste vara en multipel av basintervallet = A start interval must be a multiple of the base interval +Ogiltigt minimalt intervall = Intervalle minimum invalide +Ogiltigt basintervall = Intervalle de base invalide +Country = Pays +CourseShortening = Raccourcissement de course +Nationality = Nationalité +Number of shortenings = Nombre de raccourcissements +Längd = Distance +Redigera sträcklängder = Modifier les distances +Redigera sträcklängder för X = Modifier les distances du circuit 'X' +Oordnade parallella sträckor = Out of order parallel legs +Tillåt löpare inom en parallell grupp att springa gruppens banor i godtycklig ordning = Allow competitors within a parallel group to run the courses of the group in any order +Laguppställningen hade fel, som har rättats = The team line-up had errors, which have been corrected +ControlClasses = Control's classes +ControlCodes = Control's punch codes +ControlCourses = Control's courses +ControlMaxLostTime = Control, lost time, maximum +ControlMedianLostTime = Control, lost time, median +ControlMistakeQuotient = Control, quotient of runners with lost time +ControlName = Control's name +ControlPunches = Control's actual number of visitors +ControlRunnersLeft = Control's remaining number of visitors +ControlVisitors = Control's expected number of visitors +CourseClasses = Course's classes +CourseUsage = Course's number of required maps +CourseUsageNoVacant = Course's number of entries excluding vacant positions +Bomkvot = Quotient d'erreur +Control = Control +Control Statistics = Statistiques postes +Control Statistics - X = Statistiques poste - X +Course = Course +FilterSameParallel = Collect parallel legs +Kontrollrapport - X = Control Report - X +Maxbom = Erreur maximale +Control Overview = Control Overview +Medianbom = Erreur médiane +N.N. = X +Endast på obligatoriska sträckor = Only process non-optional legs. +Fyll obesatta sträckor i alla lag med anonyma tillfälliga lagmedlemmar (N.N.) = Fill vacant legs in all teams with anonymous temporary team members (X) +Skapa anonyma lagmedlemmar = Appoint Anonymous Team Members +Tillsätt tillfälliga anonyma lagmedlemmar = Appoint Anonymous Team Members +Tillsätt = Appoint +help:anonymous_team = Create and appoint (temporary) team members for all teams, to whom you can assign SI Card, Course etc. +Anonymt namn = Anonymous name +Med anmälningsavgift (lagets klubb) = With entry fee (for the team club) +Tar bort X = Removing X +Källa = Source +Ta bort eventuella avanmälda deltagare = Supprimer les inscriptions annulées si nécessaire +Verktyg = Tools +Automatisk = Automatic +Avstånd = Distance +Extra avstånd ovanför textblock = Extra distance above +FilterSameParallelNotFirst = Collect parallel legs, skip first +RunnerLeg = Competitor (specific leg) +Texten ska innehålla tecknet X, som byts ut mot tävlingsspecifik data = The text must include the symbol X, which is replaced by competition specific data +Tabellverktyg = Table tools +Antal reserverade nummerlappsnummer mellan klasser = Nombre de dossards réservés entre les catégories +help:bibs = You can handle bibs automatically or manually. Here you can assign bibs manually for a certain class by specifying the method Manual and provide the first number in the class.\n\nThe method automatic works in the same way, with the difference that MeOS will update the bibs of all classes at once. Although it is possible to make this setting here, it is better to use the Quick settings for classes to get an overview over all classes.\n\nUse the method Automatic together with the methods None or Consecutive, which means that the last number in the preceding class is used as first number. The number of reserved bibs specifies the jump made in the numbering between classes.\n\nFor team classes you can specify how the competitors´ bibs relate to the team´s bib. It can be the Same, Independent, Increasing (Team 1: 101, 102, 103, 104, Team 2: 111, 112, 113, 114 etc) or Leg (100-1, 100-2, 100-3 etc). +RunnerGeneralPlace = Competitor's team's or individual place +RunnerGeneralTimeAfter = Competitor's team's or individual time after +RunnerGeneralTimeStatus = Competitor's team's or individual time / status +open_error = Failed to open X.\n\nY. +open_error_locked = This competition is already open in MeOS.\n\nYou have to use a database to open more than one instance of the competition. +Ogiltigt bricknummer = Invalid card number +ask:updatelegs = Lengths of individual course legs may require an update after this change.\n\nDo you wish fix that now? +warn:updatelegs = Lengths of individual course legs may require an update after this change. +Ingen deltagare vald = No competitor selected +Från klubben = From the Club +Från laget = From the Team +Gafflingsnyckel X = Forking Key X +help:teamwork = The runners swap position. You can make a sequence of swaps to reach the new team line-up. +Ordnat = Ordered +Str. X = Leg X +Vill du att X går in i laget? = Do you want to put X in the team? +Vill du att X och Y byter sträcka? = Do you want X and Y to switch leg? +Vill du att X tar sträckan istället för Y? = Do you want X to run the leg instead of Y? +Ändra lagets gaffling = Change Team Forking +Deltagarens klass styrs av laget = The class is defined by the team +För att delta i en lagklass måste deltagaren ingå i ett lag = To participate in a team class you need to assign a team to the competitor +Dela upp = Split +Alla sträckor = All legs +Liveresultat, deltagare = Live Results, individual +Använd enhets-id istället för tävlings-id = Use Unit ID instead of competition ID +Enhetens ID-nummer (MAC) = Unit ID (MAC) +Antal deltagare: X = Number of competitors: X +Dela efter placering = Split by result +Dela efter tid = Split by time +Dela slumpmässigt = Random split +Jämna klasser (placering) = Make equal classes (result) +Jämna klasser (ranking) = Make equal classes (ranking) +Jämna klasser (tid) = Make equal classes (time) +Klass X = Class X +Not yet implemented = Not yet implemented +Tidstillägg = Pénalité (M:S) +help:seeding_info = Seeded start time allocation means that an earlier result or ranking controls the process in part. In the field seeding groups you may either enter a single group size, meaning that the entire class is partitioned into groups of this size. The group size "1" means that the seeding order is strictly used. You can also specify several group sizes. "15, 1000" would meen a seeded group with the 15 highest ranked runners and the remaining (at most 1000) runners are placed in a non-seeded group. +Ange en gruppstorlek (som repeteras) eller flera kommaseparerade gruppstorlekar = Supply one group size (to be repeated) or several comma separated sizes +Hindra att deltagare från samma klubb startar på angränsande tider = Prevent competitors from the same club to start on adjacent start times. +Låt de bästa start först = Let the highest ranked start first +Seedningsgrupper = Seeding groups +Seedningskälla = Seeding source +error:invalidmethod = The selected method gave no distribution. Source data is insufficient. +Ogiltig storlek på seedningsgrupper X = Invalid size of seeding groups: X +Bananvändning = Fréquentation des circuits +Antal banor = Number of courses +Could not load list 'X' = Could not load list 'X' +Från den här listan kan man skapa etiketter att klistra på kartor = From this list, you can create labels to stick on the maps +Gafflingar i tabellformat = Forkings in table format +Vakanser - X = Vacancies - X +Kopiera = Copy +Kopiera till urklipp = Copy to the clipboard +RunnerStartCond = Competitor's start time (if individual) +StartTimeForClassRange = Class start time range +TeamStartCond = Team's start time (if individual) +Liveresultat = Resultats live +Visa rullande tider mellan kontroller i helskärmsläge = Show rolling times between controls in full screen mode +help:liveresultat = This method starts a timer in full screen mode (large-screen) when a competitor in a selected class punches the control, and measures the time until the control is reached. Otherwise a top list with the best results is shown. Both controls need of course be online controls and if you use a network, make sure to activate to get a responsive timer. +Result at a control = Result at a control +Total/team result at a control = Total/team result at a control +prefsAccount = Numéro de compte par défaut +prefsAddress = Adresse par défaut +prefsAdvancedClassSettings = Afficher les paramètres avancés des catégories +prefsAutoSaveTimeOut = Intervalle de sauvegarde automatique (ms) +prefsCardFee = Default card fee +prefsClient = Name of client in a network +Vissa inställningar kräver omstart av MeOS för att ha effekt = Certains paramètres nécessitent le redémarrage de MeOS pour prendre effet +prefsAutoTie = Lier automatiquement coureur et puce +prefsControlFrom = Last from control +prefsControlTo = Last to control +prefsCurrencyFactor = Facteur d'échelle monétaire +prefsCurrencyPreSymbol = Placer le symbole monétaire en premier +prefsCurrencySeparator = Séparateur décimal monétaire +prefsCurrencySymbol = Symbole monétaire +prefsDatabase = Utiliser la base de données des coureurs +prefsDatabaseUpdate = Last runner database update +prefsDefaultDrawMethod = Default draw method +prefsDirectPort = Network port for advance punch data +prefsEMail = EMail +prefsEliteFee = Default elite fee +prefsEntryFee = Default entry fee +prefsEventorBase = URL to Eventor +prefsFirstInvoice = First invoice number +prefsFirstTime = First startup +prefsHomepage = Site web +prefsInteractive = Interactive card handling +prefsLateEntryFactor = Factor for late entry fee +prefsLiveResultFont = Font used for live results +prefsMIPURL = URL to MIP server +prefsMOPFolderName = Local MOP folder +prefsMOPURL = URL to MOP server +prefsManualInput = Use manual result input +prefsMaximumSpeakerDelay = Maximum delay in speaker update +prefsOrganizer = Organisateur +prefsPort = MySQL network port +prefsRentCard = Rent card +prefsSeniorAge = Upper age limit +prefsServer = Serveur réseau par défaut +prefsSpeakerShortNames = Use initials in names +prefsStreet = Organizer street address +prefsSynchronizationTimeOut = Network update timeout (ms) +prefsTextFont = Police utilisée par MeOS +prefsUseDirectSocket = Use advance punch data +prefsUseEventor = Utiliser Eventor +prefsUseEventorUTC = Use universal coordinated time with Eventor +prefsUseHourFormat = Use fromat HH:MM:SS instead of MMM:SS +prefsUserName = Identifiant MySQL +prefsYouthAge = Low age limit +prefsYouthFee = Reduced fee +prefsaddressxpos = Address x-coordinate +prefsaddressypos = Address y-coordinate +prefsclasslimit = Limit shown results per class +prefsintertime = Show intermediate times +prefspagebreak = Ajouter des sauts de page +prefssplitanalysis = Analyser les temps intermédiaires +Ändra MeOS lokala systemegenskaper = Paramètres de MeOS +true[boolean] = true +false[boolean] = false +Ändra X = Change X +Ingen parstart = Individual start +Parvis (två och två) = Pairwise (two by two) +X och Y[N by N] = X by Y +Lotta klasser med samma bana gemensamt = Draw classes with the same course together +Lotta starttider = Définir les horaires de départ +Lotta klasser med banan X = Définir les horaires de départ du circuit 'X' +MeOS Timing = MeOS Timing +Med resultat = Avec les résultats +Säkerhetskopiering = Sauvegarde périodique +Destination: X = Destination: X +Ogiltig destination X = Invalid destination X +Säkerhetskopierar om = Backing up in +Year of birth = Year of birth +Ogiltigt antal sekunder: X = Invalid number of seconds: X +Du kan använda en SI-enhet för att läsa in bricknummer = You can use an SI unit to read card the number +Ignorera startstämpling = Ignorer le poinçon de départ +Uppdatera inte starttiden vid startstämpling = Ne pas mettre à jour l'horaire de départ avec le poinçon de départ +Ändra lokala inställningar = Modifier les paramètres +Gafflingsnyckel = Forking key +Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD) = Incorrect date format 'X' (Use YYYY-MM-DD) +Felaktigt tidsformat 'X' (Använd TT:MM:SS) = Incorrect time format 'X' (Use HH:MM:SS) +Hämta inställningar från föregående lottning = Fetch settings from previous sessions +Ej startstämpling = Disregard start punch +Extraplatser = Extra places +Fritt = Free +Från lag = From team +Lag + sträcka = Team + leg +Nummerlappshantering = Bib managemant +Oordnade parallella = Unordered parallel +Spara starttider = Save start times +X platser. Startar Y = X places. Starts Y +övriga = other +RunnerStartZero = Competitor's relative start time (zero time) +TeamStartZero = Team's relative start time (zero time) +Datumfilter = Date filter +Inget filter = No filter +Inlästa stämplar = Read punches +Löpare saknas = No competitor +Klasserna X och Y har samma externa id. Använd tabelläget för att ändra id = The classes X and Y have the same external id. Use the table mode to correct the id +Vill du koppla isär X från inläst bricka Y? = Would you like to disconnect X from the read out card Y? +RunnerRogainingPointGross = Rogaining points before reduction +Samlade poäng = Collected points +Tidsavdrag = Deduction +X p = X p +Bricka X används också av = Card X is also used by +reused card = reused card +Varning: Brickan X används redan av Y = Warning: The card X is already used by Y +Invalid filter X = Invalid filter X +Invalid font X = Invalid font X +Aktivera stöd för tider över 24 timmar = Supporter les durées de course de plus de 24h. +Inkludera information om flera lopp per löpare = Include information about multiple races for a single runner. +Alla uthyrda brickor har bockats av = All rented cards are ticked off +Avbockade brickor = Ticked off cards +Avstämning hyrbrickor = Count returned hired cards +Brickor markerade som både uthyrda och egna: X = Cards used as both hired and owned: X +Nollställ = Clear +Nollställ minnet; markera alla brickor som icke avbockade = Clear memery; forget all ticked off cards +Rapport = Report +Totalt antal unika avbockade brickor: X = Number of unique ticked off cards: X +Uthyrda brickor som inte avbockats = Hired cards that are not ticked off +Uthyrda: X, Egna: Y, Avbockade uthyrda: Z = Hired Cards: X, Owned Cards: Y, Hired and Ticked Off: Z +Vill du göra om avbockningen från början igen? = Do you want to reset and begin all over again? +help:checkcards = Use this function to count and tick off hired cards to check that they all have been returned. Attach a SI unit (preferrably programmed as a control or finish, since that is faster than card read out), and punch all returned cards. Push the Report button to see if any card is missing.\n\n The check is done locally at this computer, and does not modify the competition. +Betalningsmetoder = Modes de paiement +help:paymentmodes = Vous pouvez définir des modes de paiement personnalisés, en complément des informations de facturation, afin de faciliter la comptabilité. +Betalsätt = Payment Mode +Förväntat antal besökare: X = Expected number of visitors: X +Starttiden är definerad genom klassen eller löparens startstämpling = The start time is defined through the class or through a start punch +sekunder = seconds +är X före Y = is X before Y +var först i mål med tiden X = was first to the finish with time X +var först vid X med tiden Y = was first at X with time Y +var först vid växeln med tiden X = was first to the changeover with time X +är nu på X plats med tiden Y = is now on a X place with time Y +är nu på delad X plats med tiden Y = is now on a shared X place with time Y +är X efter = is X behind +är X efter Y = is X behind Y +är X efter; har tappat Y = is X behind; has lost Y +är X efter; har tagit in Y = is X behind; as gained Y +leder med X; har tappat Y = leads with X; has lost Y +leder med X; sprang Y snabbare än de jagande = leads with X; ran Y faster than the others +leder med X = leads with X +delar placering med X = shares place with X +sekund = second +skickar ut X = sends out X +Import names as "surname, first name" = Importer les noms sous la forme "nom de famille, prénoms" +Use French Federation of Orienteering mapping = Utiliser le format de la Fédération Française de CO +Export language = Langue +Export Split Times = Exporter les temps intermédiaires +Filename OE (csv) with runners and clubs = Nom de fichier OE (csv) avec coureurs et clubs +Climb (m) = Dénivelée (m) +Utrymme: X = Taille: X +[Radera] = [Supprimer] +ClassTeamLegResult = Résultat par catégorie et relayeur +Databaskälla = Base de donnée source +Export split times = Exporter les temps intermédiaires +Filnamn IOF (xml) eller OE (csv) med löpare = Fichier IOF (xml) ou OE (csv) avec coureurs +Importinställning = Préférences d'importation +Längsta tid i sekunder att vänta med utskrift = Délai maximum d'attente de l'impression en seconde +Max antal brickor per sida = Nombre maximum de puces par page +Resultat efter sträcka X = Résultats après le partiel X +SortLastNameOnly = Nom de famille +Sträcktider i kolumner (f?r standardpapper) = Temps en colonnes (papier standard) +prefsExportCSVSplits = Inclure les temps intermédiaires dans l'export csv +prefsExportFormat = Format d'exportation par défaut +prefsImportOptions = Options d'importation par défaut +prefsNumSplitsOnePage = Nombre de puces par page +prefsPayModes = Modes de paiement +prefsSplitLateFees = Séparer les frais d'inscription en frais standards et frais d'inscription tardive pour l'exportation IOF XML +prefsSplitPrintMaxWait = Temps d'attente maximum lors de l'impression des temps intermédiaires +prefsWideSplitFormat = Imprimer les temps intermédiaires en grand format +sträcka X = Partiel X diff --git a/code/gdiconstants.h b/code/gdiconstants.h new file mode 100644 index 0000000..e0cfc0c --- /dev/null +++ b/code/gdiconstants.h @@ -0,0 +1,44 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#ifndef GDI_CONSTANTS +#define GDI_CONSTANTS + +#include "gdifonts.h" + +enum KeyCommandCode { + KC_NONE, + KC_COPY, + KC_PASTE, + KC_DELETE, + KC_INSERT, + KC_PRINT, + KC_FIND, + KC_FINDBACK, + KC_REFRESH, + KC_SPEEDUP, + KC_SLOWDOWN, + KC_AUTOCOMPLETE, +}; + +const int GDI_BUTTON_SPACING = 8; +#endif diff --git a/code/gdifonts.h b/code/gdifonts.h new file mode 100644 index 0000000..a5557de --- /dev/null +++ b/code/gdifonts.h @@ -0,0 +1,78 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2012 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#pragma once + +enum gdiFonts { + normalText=0, + boldText=1, + boldLarge=2, + boldHuge=3, + boldSmall=5, + + italicText = 6, + italicMediumPlus = 7, + monoText = 8, + + fontLarge=11, + fontMedium=12, + fontSmall=13, + fontMediumPlus=14, + + italicSmall = 15, + formatIgnore = 1000, +}; + +const int pageNewPage=100; +//const int pageReserveHeight=101; +const int pagePageInfo=102; + +const int textRight=256; +const int textCenter=512; +const int timerCanBeNegative=1024; +const int breakLines=2048; +const int fullTimeHMS = 4096; +const int timeWithTenth = 1<<13; +const int timeSeconds = 1<<14; +const int timerIgnoreSign = 1<<15; +const int Capitalize = 1<<16; + +enum GDICOLOR {colorBlack = RGB(0,0,0), + colorRed = RGB(128,0,0), + colorGreen = RGB(0,128,0), + colorDarkGrey = RGB(40,40,40), + colorDarkRed = RGB(64,0,0), + colorGreyBlue = RGB(92,92,128), + colorDarkBlue = RGB(0,0,92), + colorDarkGreen = RGB(0,64,0), + colorYellow = RGB(255, 230, 0), + colorLightBlue = RGB(240,240,255), + colorLightRed = RGB(255,230,230), + colorLightGreen = RGB(180, 255, 180), + colorLightYellow = RGB(255, 255, 200), + colorLightCyan = RGB(200, 255, 255), + colorLightMagenta = RGB(255, 200, 255), + colorMediumRed = RGB(255,200,200), + colorMediumDarkRed = RGB(240,120,120), + colorWindowBar = -2, + colorDefault = -1}; + diff --git a/code/gdiimpl.h b/code/gdiimpl.h new file mode 100644 index 0000000..796fe03 --- /dev/null +++ b/code/gdiimpl.h @@ -0,0 +1,76 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#pragma once + +class gdioutput; +struct FontInfo; + +class GDIImplFontSet { + HFONT Huge; + HFONT Large; + HFONT Medium; + HFONT Small; + + HFONT pfLarge; + HFONT pfMedium; + HFONT pfSmall; + HFONT pfMediumPlus; + HFONT pfMono; + + HFONT pfSmallItalic; + HFONT pfItalicMediumPlus; + HFONT pfItalic; + void deleteFonts(); + + string gdiName; + mutable vector avgWidthCache; + int charSet; +public: + static float baseSize(int format, float scale); + void getInfo(FontInfo &fi) const; + + GDIImplFontSet(); + virtual ~GDIImplFontSet(); + void init(double scale, int charSet, const string &font, const string &gdiName); + void selectFont(HDC hDC, int format) const; + HFONT getGUIFont() const {return pfMedium;} + HFONT getFont(int format) const; + double getAvgFontWidth(const gdioutput &gdi, gdiFonts font) const; +}; + +class GDIImplFontEnum { +private: + int width; + int height; + double relScale; + string face; +public: + GDIImplFontEnum(); + virtual ~GDIImplFontEnum(); + + const string &getFace() const {return face;} + double getRelScale() const {return relScale;} + + friend int CALLBACK enumFontProc(const LOGFONT* logFont, const TEXTMETRIC *metric, DWORD id, LPARAM lParam); +}; + diff --git a/code/gdioutput.cpp b/code/gdioutput.cpp new file mode 100644 index 0000000..166cc73 --- /dev/null +++ b/code/gdioutput.cpp @@ -0,0 +1,6544 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// gdioutput.cpp: implementation of the gdioutput class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "gdioutput.h" +#include "gdiconstants.h" +#include "meosException.h" + +#include "process.h" + +#include "meos.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "meos_util.h" +#include "Table.h" + +#define _USE_MATH_DEFINES +#include "math.h" + +#include "Localizer.h" + +#include "TabBase.h" +#include "toolbar.h" +#include "gdiimpl.h" +#include "Printer.h" +#include "recorder.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + +//Fulhack... +#ifndef IDC_HAND + #define IDC_HAND MAKEINTRESOURCE(32649) +#endif + +//#define DEBUGRENDER + +#ifdef DEBUGRENDER + static int counterRender = 0; + static bool breakRender = false; + static int debugDrawColor = 0; +#endif + + +GuiHandler &BaseInfo::getHandler() const { + if (handler == 0) + throw meosException("Handler not definied."); + return *handler; +} + +void GuiHandler::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) { + throw meosException("Handler not definied."); +} + +InputInfo::InputInfo() : hWnd(0), callBack(0), ignoreCheck(false), + isEditControl(true), bgColor(colorDefault), fgColor(colorDefault), + writeLock(false), updateLastData(0) {} + + +EventInfo::EventInfo() : callBack(0), keyEvent(KC_NONE) {} + +/** Return true if rendering text should be skipped for + this format. */ +bool gdioutput::skipTextRender(int format) { + format &= 0xFF; + return format == pageNewPage || + format == pagePageInfo; +} + +#ifndef MEOSDB + +gdioutput::gdioutput(const string &_tag, double _scale, FontEncoding encoding) : + recorder((Recorder *)0, false) { + tag = _tag; + fontEncoding = encoding; + po_default = new PrinterObject(); + tabs = 0; + hasAnyTimer = false; + constructor(_scale); + + isTestMode = false; +} + +gdioutput::gdioutput(double _scale, FontEncoding encoding, HWND hWnd, const PrinterObject &prndef) : + recorder((Recorder *)0, false) { + fontEncoding = encoding; + hasAnyTimer = false; + po_default = new PrinterObject(prndef); + tabs = 0; + setWindow(hWnd); + constructor(_scale); + + isTestMode = false; +} + +void gdioutput::constructor(double _scale) +{ + currentFontSet = 0; + commandLock = false; + commandUnlockTime = 0; + lockUpDown = false; + + Background = 0; + + toolbar = 0; + initCommon(_scale, "Arial"); + + OffsetY=0; + OffsetX=0; + + manualUpdate = false; + + itTL = TL.end(); + + hWndTarget = 0; + hWndToolTip = 0; + hWndAppMain = 0; + onClear = 0; + postClear = 0; + clearPage(true); + hasCleared = false; + highContrast = false; + hideBG = false; + fullScreen = false; + lockRefresh = 0; + autoSpeed = 0; + autoPos = 0; + lastSpeed = 0; + autoCounter = 0; +} + +#endif + +void gdioutput::setFont(int size, const string &font, FontEncoding enc) +{ + setEncoding(enc); + double s = 1+size*sqrt(double(size))*0.2; + initCommon(s, font); +} + +void gdioutput::setFontCtrl(HWND hWnd) { + SendMessage(hWnd, WM_SETFONT, (WPARAM) getGUIFont(), MAKELPARAM(TRUE, 0)); +} + +static void scaleWindow(HWND hWnd, double scale, int &w, int &h) { + RECT rc; + GetWindowRect(hWnd, &rc); + w = rc.right - rc.left; + h = rc.bottom - rc.top; + w = int(w * scale + 0.5); + h = int(h * scale + 0.5); +} + +int transformX(int x, double scale) { + if (x<40) + return int(x * scale + 0.5); + else + return int((x-40) * scale + 0.5) + 40; +} + +void gdioutput::scaleSize(double scale_) { + if (fabs(scale_ - 1.0) < 1e-4) + return; // No scaling + double ns = scale*scale_; + + if (ns + 1e-6 < 1.0 ) { + ns = 1.0; + scale_ = 1.0; + } + initCommon(ns, currentFont); + + for (list::iterator it = TL.begin(); it!=TL.end(); ++it) { + it->xlimit = int(it->xlimit * scale_ + 0.5); + it->xp = transformX(it->xp, scale_); + it->yp = int(it->yp * scale_ + 0.5); + } + int w, h; + OffsetY = int (OffsetY * scale_ + 0.5); + OffsetX = int (OffsetX * scale_ + 0.5); + + for (list::iterator it = BI.begin(); it!=BI.end(); ++it) { + if (it->fixedRightTop) + it->xp = int(scale_ * it->xp + 0.5); + else + it->xp = transformX(it->xp, scale_); + + it->yp = int(it->yp * scale_ + 0.5); + + if (it->isCheckbox) + scaleWindow(it->hWnd, 1.0, w, h); + else + scaleWindow(it->hWnd, scale_, w, h); + setFontCtrl(it->hWnd); + MoveWindow(it->hWnd, it->xp-OffsetX, it->yp-OffsetY, w, h, true); + } + + for (list::iterator it = II.begin(); it!=II.end(); ++it) { + it->xp = transformX(it->xp, scale_); + it->yp = int(it->yp * scale_ + 0.5); + it->height *= scale_; + it->width *= scale_; + setFontCtrl(it->hWnd); + MoveWindow(it->hWnd, it->xp-OffsetX, it->yp-OffsetY, int(it->width+0.5), int(it->height+0.5), true); + } + + for (list::iterator it = LBI.begin(); it!=LBI.end(); ++it) { + it->xp = transformX(it->xp, scale_); + it->yp = int(it->yp * scale_ + 0.5); + it->height *= scale_; + it->width *= scale_; + setFontCtrl(it->hWnd); + MoveWindow(it->hWnd, it->xp-OffsetX, it->yp-OffsetY, int(it->width+0.5), int(it->height+0.5), true); + } + + for (list::iterator it = Rectangles.begin(); it!=Rectangles.end(); ++it) { + it->rc.bottom = int(it->rc.bottom * scale_ + 0.5); + it->rc.top = int(it->rc.top * scale_ + 0.5); + it->rc.right = transformX(it->rc.right, scale_); + it->rc.left = transformX(it->rc.left, scale_); + } + + for (list::iterator it = Tables.begin(); it != Tables.end(); ++it) { + it->xp = transformX(it->xp, scale_); + it->yp = int(it->yp * scale_ + 0.5); + } + + MaxX = transformX(MaxX, scale_); + MaxY = int (MaxY * scale_ + 0.5); + CurrentX = transformX(CurrentX, scale_); + CurrentY = int (CurrentY * scale_ + 0.5); + SX = transformX(SX, scale_); + SY = int (SY * scale_ + 0.5); + + for (map::iterator it = restorePoints.begin(); it != restorePoints.end(); ++it) { + RestoreInfo &r = it->second; + r.sMX = transformX(r.sMX, scale_); + r.sMY = int (r.sMY * scale_ + 0.5); + r.sCX = transformX(r.sCX, scale_); + r.sCY = int (r.sCY * scale_ + 0.5); + r.sOX = transformX(r.sOX, scale_); + r.sOY = int (r.sOY * scale_ + 0.5); + + } + refresh(); +} + +void gdioutput::initCommon(double _scale, const string &font) +{ + dbErrorState = false; + currentFontSet = 0; + scale = _scale; + currentFont = font; + deleteFonts(); + enableTables(); + lineHeight = int(scale*14); + + Background=CreateSolidBrush(GetSysColor(COLOR_WINDOW)); + + fonts[currentFont].init(scale, getCharSet(), currentFont, ""); +} + +double getLocalScale(const string &fontName, string &faceName) { + double locScale = 1.0; + vector res; + split(fontName, ";", res); + + if (res.empty() || res.size() > 2) + throw meosException("Cannot load font: " + fontName); + if (res.size() == 2) { + locScale = atof(res[1].c_str()); + if (!(locScale>0.001 && locScale < 100)) + throw meosException("Cannot scale font with factor: " + res[1]); + } + faceName = res[0]; + return locScale; +} + +const GDIImplFontSet & gdioutput::loadFont(const string &font) { + currentFontSet = 0; + vector< pair > fontIx; + getEnumeratedFonts(fontIx); + double relScale = 1.0; + for (size_t k = 0; k < fontIx.size(); k++) { + if (stringMatch(fontIx[k].first, font)) { + relScale = enumeratedFonts[fontIx[k].second].getRelScale(); + } + } + /*vector res; + split(font, ";", res); + double locScale = 1.0; + if (res.empty() || res.size() > 2) + throw meosException("Cannot load font: " + font); + if (res.size() == 2) { + locScale = atof(res[1].c_str()); + if (!(locScale>0.001 && locScale < 100)) + throw meosException("Cannot scale font with factor: " + res[1]); + }*/ + string faceName; + double locScale = getLocalScale(font, faceName); + + if (faceName.empty()) + faceName = currentFont; + fonts[font].init(scale * relScale * locScale, getCharSet(), faceName, font); + return fonts[font]; +} + +void gdioutput::deleteFonts() { + if (Background) + DeleteObject(Background); + Background = 0; + + currentFontSet = 0; + fonts.clear(); +} + +#ifndef MEOSDB + +gdioutput::~gdioutput() +{ + while(!timers.empty()) { + KillTimer(hWndTarget, (UINT_PTR)&timers.back()); + timers.back().parent = 0; + timers.pop_back(); + } + + deleteFonts(); + + if (toolbar) + delete toolbar; + toolbar = 0; + //delete table; + while(!Tables.empty()){ + Tables.front().table->releaseOwnership(); + Tables.pop_front(); + } + + if (tabs) { + delete tabs; + tabs = 0; + } + + initRecorder(0); + + delete po_default; + po_default = 0; +} +#endif + + +FixedTabs &gdioutput::getTabs() { +#ifndef MEOSDB + if (!tabs) + tabs = new FixedTabs(); +#endif + + return *tabs; +} + + + +void gdioutput::fetchPrinterSettings(PrinterObject &po) const { + po = *po_default; +} + + +void gdioutput::drawBackground(HDC hDC, RECT &rc) +{ + GRADIENT_RECT gr[1]; + + SelectObject(hDC, GetStockObject(NULL_PEN)); + SelectObject(hDC, Background); + + if (highContrast) { + Rectangle(hDC, -1, -1, rc.right + 1, rc.bottom + 1); + + HFONT hInfo = CreateFont(min(30, int(scale*22)), 0, 900, 900, FW_LIGHT, false, false, false, getCharSet(), + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, + DEFAULT_PITCH|FF_ROMAN, "Arial"); + + SelectObject(hDC, hInfo); + RECT rc; + rc.left = 0; + rc.right = 0; + rc.top = 0; + rc.bottom = 0; + DrawText(hDC, listDescription.c_str(), listDescription.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + int height = rc.right + rc.right / 3; + SetBkMode(hDC, TRANSPARENT); + + for (int k = height; k < MaxY; k += height) { + RECT rc; + rc.left = 5 - OffsetX; + rc.right = 1000; + rc.top = k - OffsetY; + rc.bottom = MaxY; + SetTextColor(hDC, RGB(192, 192, 192)); + + DrawText(hDC, listDescription.c_str(), listDescription.length(), &rc, DT_LEFT|DT_NOCLIP|DT_NOPREFIX); + rc.top -= 1; + rc.left -= 1; + SetTextColor(hDC, RGB(92, 32, 32)); + + DrawText(hDC, listDescription.c_str(), listDescription.length(), &rc, DT_LEFT|DT_NOCLIP|DT_NOPREFIX); + + } + SelectObject(hDC, GetStockObject(ANSI_FIXED_FONT)); + DeleteObject(hInfo); + return; + } + if (!hideBG) { + Rectangle(hDC, -1, -1, rc.right-OffsetX+1, 10-OffsetY+1); + Rectangle(hDC, -1, -1, 11-OffsetX, rc.bottom+1); + Rectangle(hDC, MaxX+10-OffsetX, 0, rc.right+1, rc.bottom+1); + Rectangle(hDC, 10-OffsetX, MaxY+13-OffsetY, MaxX+11-OffsetX, rc.bottom+1); + } + if (dbErrorState) { + SelectObject(hDC, GetStockObject(DC_BRUSH)); + SetDCBrushColor(hDC, RGB(255, 100, 100)); + Rectangle(hDC, -1, -1, rc.right+1, rc.bottom+1); + + HFONT hInfo = CreateFont(30, 0, 900, 900, FW_BOLD, false, false, false, getCharSet(), + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, + DEFAULT_PITCH|FF_ROMAN, "Arial"); + + string err = lang.tl("DATABASE ERROR"); + SelectObject(hDC, hInfo); + RECT mrc; + mrc.left = 0; + mrc.right = 0; + mrc.top = 0; + mrc.bottom = 0; + DrawText(hDC, err.c_str(), err.length(), &mrc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + int width = mrc.bottom + mrc.bottom / 4; + int height = mrc.right + mrc.right / 4; + SetBkMode(hDC, TRANSPARENT); + SetTextColor(hDC, RGB(64, 0, 0)); + + for (int k = height; k < max(MaxY, rc.bottom + height); k += height) { + RECT mrc; + mrc.left = rc.right - 50 - OffsetX; + mrc.right = mrc.left + 1000; + mrc.top = k - OffsetY; + mrc.bottom = MaxY; + DrawText(hDC, err.c_str(), err.length(), &mrc, DT_LEFT|DT_NOCLIP|DT_NOPREFIX); + mrc.left -= width; + mrc.top -= height / 2; + DrawText(hDC, err.c_str(), err.length(), &mrc, DT_LEFT|DT_NOCLIP|DT_NOPREFIX); + } + SelectObject(hDC, GetStockObject(ANSI_FIXED_FONT)); + DeleteObject(hInfo); + } + + DWORD c=GetSysColor(COLOR_3DFACE); + double red = double(GetRValue(c)) *0.9; + double green = double(GetGValue(c)) * 0.85; + double blue = min(255.0, double(GetBValue(c)) * 1.05); + + if (blue<100) { + //Invert + red = 255-red; + green = 255-green; + blue = 255-blue; + } + + double blue1=min(255., blue*1.3); + double green1=min(255., green*1.3); + double red1=min(255., red*1.3); + + + TRIVERTEX vert[2]; + if (hideBG) { + vert [0] .x = 0; + vert [0] .y = 0; + } + else { + vert [0] .x = 10-OffsetX; + vert [0] .y = 10-OffsetY; + } + vert [0] .Red = 0xff00&DWORD(red1*256); + vert [0] .Green = 0xff00&DWORD(green1*256); + vert [0] .Blue = 0xff00&DWORD(blue1*256); + vert [0] .Alpha = 0x0000; + + if (hideBG) { + vert [1] .x = rc.right + 1; + vert [1] .y = rc.bottom + 1; + } + else { + vert [1] .x = MaxX+10-OffsetX; + vert [1] .y = MaxY+13-OffsetY; + } + vert [1] .Red = 0xff00&DWORD(red*256); + vert [1] .Green = 0xff00&DWORD(green*256); + vert [1] .Blue = 0xff00&DWORD(blue*256); + vert [1] .Alpha = 0x0000; + + gr[0].UpperLeft=0; + gr[0].LowerRight=1; + + + if (MaxY>max(800, MaxX) || hideBG) + GradientFill(hDC,vert, 2, gr, 1,GRADIENT_FILL_RECT_H); + else + GradientFill(hDC,vert, 2, gr, 1,GRADIENT_FILL_RECT_V); + + if (!hideBG) { + SelectObject(hDC, GetSysColorBrush(COLOR_3DSHADOW)); + + Rectangle(hDC, vert[0].x+3, vert[1].y, vert[1].x+1, vert[1].y+3); + Rectangle(hDC, vert[1].x, vert[0].y+3, vert[1].x+3, vert[1].y+3); + + SelectObject(hDC, GetStockObject(NULL_BRUSH)); + SelectObject(hDC, GetStockObject(DC_PEN)); + SetDCPenColor(hDC, RGB(DWORD(red*0.4), DWORD(green*0.4), DWORD(blue*0.4))); + Rectangle(hDC, vert[0].x, vert[0].y, vert[1].x, vert[1].y); + } +} + +void gdioutput::setDBErrorState(bool state) { + if (dbErrorState != state) { + dbErrorState = state; + refresh(); + } +} + +void gdioutput::draw(HDC hDC, RECT &rc, RECT &drawArea) +{ +#ifdef DEBUGRENDER + if (debugDrawColor) { + string ds = "DebugDraw" + itos(drawArea.left) + "-" + itos(drawArea.right) + ", " + itos(drawArea.top) + "-" + itos(drawArea.bottom) + "\n"; + OutputDebugString(ds.c_str()); + SelectObject(hDC,GetStockObject(DC_BRUSH)); + SetDCBrushColor(hDC, debugDrawColor); + Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom); + return; + } +#endif + if (highContrast) + drawBackground(hDC, drawArea); + else + drawBackground(hDC, rc); + + if (drawArea.left > MaxX - OffsetX + 15) { + drawBoxes(hDC, rc); + return; + } + + list::iterator rit; + SelectObject(hDC,GetStockObject(DC_BRUSH)); + + for(rit=Rectangles.begin();rit!=Rectangles.end(); ++rit){ + if (rit->drawBorder) + SelectObject(hDC, GetStockObject(BLACK_PEN)); + else + SelectObject(hDC, GetStockObject(NULL_PEN)); + SetDCBrushColor(hDC, rit->color); + + RECT rect_rc=rit->rc; + OffsetRect(&rect_rc, -OffsetX, -OffsetY); + Rectangle(hDC, rect_rc.left, rect_rc.top, rect_rc.right, rect_rc.bottom); + } + + if (useTables) + for(list::iterator tit=Tables.begin();tit!=Tables.end(); ++tit){ + tit->table->draw(*this, hDC, tit->xp, tit->yp, rc); + } + + resetLast(); + TIList::iterator it; + + int BoundYup=OffsetY-100 + drawArea.top; + int BoundYdown=OffsetY+ drawArea.bottom + 2; + + if (!renderOptimize || itTL == TL.end()) { +#ifdef DEBUGRENDER + //if (breakRender) + // DebugBreak(); + OutputDebugString(("Raw render" + itos(size_t(this)) + "\n").c_str()); +#endif + for(it=TL.begin();it!=TL.end(); ++it){ + TextInfo &ti=*it; + if ( ti.yp > BoundYup && ti.yp < BoundYdown) + RenderString(*it, hDC); + } + } + else { + #ifdef DEBUGRENDER + OutputDebugString((itos(++counterRender) + " opt render " + itos(size_t(this)) + "\n").c_str()); + #endif + + while( itTL != TL.end() && itTL->yp < BoundYup) + ++itTL; + + if (itTL!=TL.end()) + while( itTL != TL.begin() && itTL->yp > BoundYup) + --itTL; + + it=itTL; + while( it != TL.end() && it->yp < BoundYdown) { + RenderString(*it, hDC); + ++it; + } + } + + updateStringPosCache(); + drawBoxes(hDC, rc); +} + +void gdioutput::renderRectangle(HDC hDC, RECT *clipRegion, const RectangleInfo &ri) { + if (ri.drawBorder) + SelectObject(hDC, GetStockObject(BLACK_PEN)); + else + SelectObject(hDC, GetStockObject(NULL_PEN)); + SetDCBrushColor(hDC, ri.color); + + RECT rect_rc=ri.rc; + OffsetRect(&rect_rc, -OffsetX, -OffsetY); + Rectangle(hDC, rect_rc.left, rect_rc.top, rect_rc.right, rect_rc.bottom); +} + +void gdioutput::updateStringPosCache() { + RECT rc; + GetClientRect(hWndTarget, &rc); + int BoundYup = OffsetY-100; + int BoundYdown = OffsetY+rc.bottom+10; + shownStrings.clear(); + TIList::iterator it; + + if (!renderOptimize || itTL == TL.end()) { + for (it=TL.begin();it!=TL.end(); ++it) { + TextInfo &ti=*it; + if ( ti.yp > BoundYup && ti.yp < BoundYdown) { + if (ti.textRect.top != ti.yp - OffsetY) { + int diff = it->textRect.top - (ti.yp - OffsetY); + ti.textRect.top -= diff; + ti.textRect.bottom -= diff; + } + shownStrings.push_back(&ti); + } + } + } + else { + TIList::iterator itC = itTL; + + while( itC != TL.end() && itC->yp < BoundYup) + ++itC; + + if (itC!=TL.end()) + while( itC != TL.begin() && itC->yp > BoundYup) + --itC; + + it=itC; + while( it != TL.end() && it->yp < BoundYdown) { + shownStrings.push_back(&*it); + if (it->textRect.top != it->yp - OffsetY) { + int diff = it->textRect.top - (it->yp - OffsetY); + it->textRect.top -= diff; + it->textRect.bottom -= diff; + } + ++it; + } + } +} + +TextInfo &gdioutput::addTimer(int yp, int xp, int format, DWORD zeroTime, int xlimit, + GUICALLBACK cb, int timeOut, const char *fontFace) { + hasAnyTimer = true; + DWORD zt=GetTickCount()-1000*zeroTime; + string text=getTimerText(zeroTime, format); + + addStringUT(yp, xp, format, text, xlimit, cb, fontFace); + TextInfo &ti=TL.back(); + ti.hasTimer=true; + ti.zeroTime=zt; + + if (timeOut != NOTIMEOUT) + ti.timeOut = ti.zeroTime + timeOut*1000; + + return ti; +} + +TextInfo &gdioutput::addTimeout(int TimeOut, GUICALLBACK cb) { + addStringUT(0, 0, 0, "", 0, cb); + TextInfo &ti=TL.back(); + ti.hasTimer=true; + ti.zeroTime=GetTickCount(); + if (TimeOut!=NOTIMEOUT) + ti.timeOut=ti.zeroTime+(TimeOut)*1000; + return ti; +} + +void CALLBACK gdiTimerProc(HWND hWnd, UINT a, UINT_PTR ptr, DWORD b) { + string msg; + KillTimer(hWnd, ptr); + TimerInfo *it = (TimerInfo *)ptr; + try { + if (it->parent) { + it->parent->timerProc(*it, b); + } + } + catch(std::exception &ex) { + msg=ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg="Unexpected error"; + } + + if (!msg.empty()) { + MessageBox(hWnd, msg.c_str(), "MeOS", MB_OK|MB_ICONEXCLAMATION); + } +} + +void gdioutput::timerProc(TimerInfo &timer, DWORD timeout) { + if (timer.handler) + timer.handler->handle(*this, timer, GUI_TIMER); + else if (timer.callBack) + timer.callBack(this, GUI_TIMER, &timer); + + for (list::iterator it = timers.begin(); it != timers.end(); ++it) { + if (&*it == &timer) { + timers.erase(it); + return; + } + } +} + +void gdioutput::removeTimeoutMilli(const string &id) { + for (list::iterator it = timers.begin(); it != timers.end(); ++it) { + if (it->id == id) { + UINT_PTR ptr = (UINT_PTR)&*it; + KillTimer(hWndTarget, ptr); + timers.erase(it); + return; + } + } +} + +TimerInfo &gdioutput::addTimeoutMilli(int timeOut, const string &id, GUICALLBACK cb) +{ + removeTimeoutMilli(id); + timers.push_back(TimerInfo(this, cb)); + timers.back().id = id; + timers.back().data = 0; + SetTimer(hWndTarget, (UINT_PTR)&timers.back(), timeOut, gdiTimerProc); + return timers.back(); +} + +TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const string &text, + int xlimit, GUICALLBACK cb, const char *fontFace) +{ + TextInfo TI; + TI.format=format; + TI.xp=xp; + TI.yp=yp; + TI.text=text; + TI.xlimit=xlimit; + TI.callBack=cb; + if (fontFace) + TI.font = fontFace; + if (!skipTextRender(format)) { + HDC hDC=GetDC(hWndTarget); + + if (hWndTarget && !manualUpdate) + RenderString(TI, hDC); + else + calcStringSize(TI, hDC); + + if (xlimit == 0 || (format & (textRight|textCenter)) == 0) { + updatePos(TI.textRect.right+OffsetX, TI.yp, scaleLength(10), + TI.textRect.bottom - TI.textRect.top + scaleLength(2)); + } + else { + updatePos(TI.xp, TI.yp, TI.realWidth + scaleLength(10), + TI.textRect.bottom - TI.textRect.top + scaleLength(2)); + } + + ReleaseDC(hWndTarget, hDC); + + if (renderOptimize && !TL.empty()) { + if (TL.back().yp > TI.yp) + renderOptimize=false; + } + } + else { + TI.textRect.left = xp; + TI.textRect.right = xp; + TI.textRect.bottom = yp; + TI.textRect.top = yp; + } + + TL.push_back(TI); + itTL=TL.begin(); + + return TL.back(); +} + +TextInfo &gdioutput::addString(const char *id, int yp, int xp, int format, const string &text, + int xlimit, GUICALLBACK cb, const char *fontFace) +{ + TextInfo TI; + TI.format=format; + TI.xp=xp; + TI.yp=yp; + TI.text=lang.tl(text); + if ( (format & Capitalize) == Capitalize && lang.capitalizeWords()) + capitalizeWords(TI.text); + TI.id=id; + TI.xlimit=xlimit; + TI.callBack=cb; + if (fontFace) + TI.font = fontFace; + + if (!skipTextRender(format)) { + HDC hDC=GetDC(hWndTarget); + + if (hWndTarget && !manualUpdate) + RenderString(TI, hDC); + else + calcStringSize(TI, hDC); + + if (xlimit == 0 || (format & (textRight|textCenter)) == 0) { + updatePos(TI.textRect.right+OffsetX, yp, scaleLength(10), + TI.textRect.bottom - TI.textRect.top + scaleLength(2)); + } + else { + updatePos(TI.xp, TI.yp, TI.realWidth + scaleLength(10), + TI.textRect.bottom - TI.textRect.top + scaleLength(2)); + } + ReleaseDC(hWndTarget, hDC); + + if (renderOptimize && !TL.empty()) { + if (TL.back().yp > TI.yp) + renderOptimize=false; + } + } + else { + TI.textRect.left = xp; + TI.textRect.right = xp; + TI.textRect.bottom = yp; + TI.textRect.top = yp; + } + + TL.push_back(TI); + itTL=TL.begin(); + + return TL.back(); +} + +TextInfo &gdioutput::addString(const string &id, int format, const string &text, GUICALLBACK cb) { + return addString(id.c_str(), CurrentY, CurrentX, format, text, 0, cb); +} + +TextInfo &gdioutput::addString(const string &id, int yp, int xp, int format, const string &text, + int xlimit, GUICALLBACK cb, const char *fontFace) { + return addString(id.c_str(), yp, xp, format, text, xlimit, cb, fontFace); +} + +TextInfo &gdioutput::addString(const char *id, int format, const string &text, GUICALLBACK cb) +{ + return addString(id, CurrentY, CurrentX, format, text, 0, cb); +} + +TextInfo &gdioutput::addStringUT(int format, const string &text, GUICALLBACK cb) +{ + return addStringUT(CurrentY, CurrentX, format, text, 0, cb); +} + + +ButtonInfo &gdioutput::addButton(const string &id, const string &text, GUICALLBACK cb, + const string &tooltip) +{ + return addButton(CurrentX, CurrentY, id, text, cb, tooltip); +} + +ButtonInfo &gdioutput::addButton(int x, int y, const string &id, const string &text, GUICALLBACK cb, + const string &tooltip) +{ + SIZE size; + + HDC hDC=GetDC(hWndTarget); + SelectObject(hDC, getGUIFont()); + string ttext = lang.tl(text); + if (lang.capitalizeWords()) + capitalizeWords(ttext); + GetTextExtentPoint32(hDC, ttext.c_str(), ttext.length(), &size); + ReleaseDC(hWndTarget, hDC); + int width = size.cx+scaleLength(30); + if (text != "...") + width = max(width, scaleLength(75)); + ButtonInfo &bi=addButton(x, y, width, id, text, cb, tooltip, false, false); + + return bi; +} + +ButtonInfo &ButtonInfo::setDefault() +{ + flags |= 1; + storedFlags |= 1; + //SetWindowLong(hWnd, i, GetWindowLong(hWnd, i)|BS_DEFPUSHBUTTON); + return *this; +} + +int gdioutput::getButtonHeight() const { + return int(scale * 24)+0; +} + +void ButtonInfo::moveButton(gdioutput &gdi, int nxp, int nyp) { + /*WINDOWPLACEMENT wpl; + GetWindowPlacement(hWnd, &wpl); + wpl. + + SetWindowPos*/ + //SetWindowPos(hWnd, NULL, xp, yp, 0, 0, + xp = nxp; + yp = nyp; + int w, h; + getDimension(gdi, w, h); + MoveWindow(hWnd, xp, yp, w, h, true); + gdi.updatePos(xp, yp, w, h); +} + +void ButtonInfo::getDimension(gdioutput &gdi, int &w, int &h) { + RECT rc; + GetWindowRect(hWnd, &rc); + w = rc.right - rc.left + gdi.scaleLength(GDI_BUTTON_SPACING); + h = rc.bottom - rc.top; +} + +ButtonInfo &gdioutput::addButton(int x, int y, int w, const string &id, + const string &text, GUICALLBACK cb, const string &tooltip, + bool AbsPos, bool hasState) +{ + int style = hasState ? BS_CHECKBOX|BS_PUSHLIKE : BS_PUSHBUTTON; + ButtonInfo bi; + string ttext = lang.tl(text); + if (lang.capitalizeWords()) + capitalizeWords(ttext); + int height = getButtonHeight(); + if (AbsPos){ + if (ttext.find_first_of('\n') != string::npos) { + style |= BS_MULTILINE; + height *= 2; + } + bi.hWnd=CreateWindow("BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD|style|BS_NOTIFY, + x-OffsetX, y, w, height, hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + } + else { + bi.hWnd=CreateWindow("BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD|style|BS_NOTIFY, + x-OffsetX, y-OffsetY-1, w, height, hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + } + + if (getEncoding() != ANSI) { + const wstring &output = toWide(ttext); + SetWindowTextW(bi.hWnd, output.c_str()); + } + + SendMessage(bi.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0); + + if (!AbsPos) + updatePos(x, y, w+scaleLength(GDI_BUTTON_SPACING), height+5); + + bi.xp=x; + bi.yp=y; + bi.width = w; + bi.text=ttext; + bi.id=id; + bi.callBack=cb; + bi.AbsPos=AbsPos; + + if (tooltip.length()>0) + addToolTip(id, tooltip, bi.hWnd); + + BI.push_back(bi); + biByHwnd[bi.hWnd] = &BI.back(); + + FocusList.push_back(bi.hWnd); + return BI.back(); +} + +static int checkBoxCallback(gdioutput *gdi, int type, void *data) { + if (type == GUI_LINK) { + TextInfo *ti = (TextInfo *)data; + string cid = ti->id.substr(1); + gdi->check(cid, !gdi->isChecked(cid), true); + ButtonInfo &bi = ((ButtonInfo &)gdi->getBaseInfo(cid.c_str())); + if (bi.callBack || bi.hasEventHandler()) + gdi->sendCtrlMessage(cid); + //gdi->getBaseInfo(cid); + } + return 0; +} + +void gdioutput::enableCheckBoxLink(TextInfo &ti, bool enable) { + bool needRefresh = false; + if (enable) { + needRefresh = ti.callBack == 0; + ti.callBack = checkBoxCallback; + ti.setColor(colorDefault); + } + else { + needRefresh = ti.callBack != 0; + ti.callBack = 0; + ti.setColor(colorDarkGrey); + } + if (needRefresh) + InvalidateRect(hWndTarget, &ti.textRect, true); +} + +ButtonInfo &gdioutput::addCheckbox(const string &id, const string &text, + GUICALLBACK cb, bool Checked, const string &tooltip) +{ + return addCheckbox(CurrentX, CurrentY, id, text, cb, Checked, tooltip); +} + +ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const string &text, + GUICALLBACK cb, bool Checked, const string &tooltip, bool AbsPos) +{ + ButtonInfo bi; + SIZE size; + + string ttext = lang.tl(text); + HDC hDC=GetDC(hWndTarget); + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + GetTextExtentPoint32(hDC, "M", 1, &size); + + int ox=OffsetX; + int oy=OffsetY; + + if (AbsPos) { + ox=0; + oy=0; + } + + /* + bi.hWnd=CreateWindowEx(0,"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE| + WS_CHILD|BS_AUTOCHECKBOX|BS_NOTIFY, + x-ox, y-oy, size.cx+30, size.cy+5, hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + */ + int h = size.cy; + SelectObject(hDC, getGUIFont()); + GetTextExtentPoint32(hDC, ttext.c_str(), ttext.length(), &size); + ReleaseDC(hWndTarget, hDC); + + bi.hWnd=CreateWindowEx(0,"BUTTON", "", WS_TABSTOP|WS_VISIBLE| + WS_CHILD|BS_AUTOCHECKBOX|BS_NOTIFY, + x-ox, y-oy + (size.cy-h)/2, h, h, hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + + TextInfo &desc = addStringUT(y , x + (3*h)/2, 0, ttext, 0, checkBoxCallback); + desc.id = "T" + id; + + SendMessage(bi.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0); + + if (Checked) + SendMessage(bi.hWnd, BM_SETCHECK, BST_CHECKED, 0); + + bi.checked = Checked; + + if (!AbsPos) + updatePos(x, y, size.cx+int(30*scale), size.cy+int(scale * 12)+3); + + if (tooltip.length()>0) { + addToolTip(id, tooltip, bi.hWnd); + addToolTip(desc.id, tooltip, 0, &desc.textRect); + } + bi.isCheckbox = true; + bi.xp=x; + bi.yp=y; + bi.width = desc.textRect.right - (x-ox); + bi.text=ttext; + bi.id=id; + bi.callBack=cb; + bi.AbsPos=AbsPos; + bi.originalState = Checked; + bi.isEdit(true); + BI.push_back(bi); + biByHwnd[bi.hWnd] = &BI.back(); + + FocusList.push_back(bi.hWnd); + return BI.back(); +} + +bool gdioutput::isChecked(const string &id) +{ + list::iterator it; + for(it=BI.begin(); it != BI.end(); ++it) + if (it->id==id) + return SendMessage(it->hWnd, BM_GETCHECK, 0, 0)==BST_CHECKED; + + return false; +} + +void gdioutput::check(const string &id, bool state, bool keepOriginalState){ + list::iterator it; + for(it=BI.begin(); it != BI.end(); ++it) { + if (it->id==id){ + SendMessage(it->hWnd, BM_SETCHECK, state ? BST_CHECKED:BST_UNCHECKED, 0); + it->checked = state; + it->synchData(); + if (!keepOriginalState) + it->originalState = state; + return; + } + } + + #ifdef _DEBUG + string err = string("Internal Error, identifier not found: X#") + id; + throw std::exception(err.c_str()); + #endif +} + +InputInfo &gdioutput::addInput(const string &id, const string &text, int length, GUICALLBACK cb, const string &Explanation, const string &Help) +{ + return addInput(CurrentX, CurrentY, id, text, length, cb, Explanation, Help); +} + +HFONT gdioutput::getGUIFont() const +{ + if (scale==1) + return (HFONT)GetStockObject(DEFAULT_GUI_FONT); + else + return getCurrentFont().getGUIFont(); +} + +InputInfo &gdioutput::addInput(int x, int y, const string &id, const string &text, int length, GUICALLBACK cb, const string &Explanation, const string &Help) +{ + if (Explanation.length()>0) { + addString(id + "_label", y, x, 0, Explanation); + y+=lineHeight; + } + + InputInfo ii; + SIZE size; + + HDC hDC=GetDC(hWndTarget); + SelectObject(hDC, getGUIFont()); + GetTextExtentPoint32(hDC, "M", 1, &size); + ReleaseDC(hWndTarget, hDC); + + int ox=OffsetX; + int oy=OffsetY; + + ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", text.c_str(), + WS_TABSTOP|WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | WS_BORDER, + x-ox, y-oy, length*size.cx+scaleLength(8), size.cy+scaleLength(6), + hWndTarget, NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + + updatePos(x, y, length*size.cx+scaleLength(12), size.cy+scaleLength(10)); + + SendMessage(ii.hWnd, WM_SETFONT, + (WPARAM) getGUIFont(), 0); + + ii.xp=x; + ii.yp=y; + ii.width = length*size.cx+scaleLength(8); + ii.height = size.cy+scaleLength(6); + ii.text = text; + ii.original = text; + ii.focusText = text; + ii.id=id; + ii.callBack=cb; + + II.push_back(ii); + iiByHwnd[ii.hWnd] = &II.back(); + if (Help.length() > 0) + addToolTip(id, Help, ii.hWnd); + + FocusList.push_back(ii.hWnd); + + if (II.size() == 1) { + SetFocus(ii.hWnd); + currentFocus = ii.hWnd; + } + + return II.back(); +} + +InputInfo &gdioutput::addInputBox(const string &id, int width, int height, const string &text, + GUICALLBACK cb, const string &Explanation) +{ + return addInputBox(id, CurrentX, CurrentY, width, height, text, cb, Explanation); +} + +InputInfo &gdioutput::addInputBox(const string &id, int x, int y, int width, int height, + const string &text, GUICALLBACK cb, const string &Explanation) +{ + if (Explanation.length()>0) { + addString("", y, x, 0, Explanation); + y+=lineHeight; + } + + InputInfo ii; + + int ox=OffsetX; + int oy=OffsetY; + + ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", text.c_str(), WS_HSCROLL|WS_VSCROLL| + WS_TABSTOP|WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER, + x-ox, y-oy, width, height, hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + + updatePos(x, y, width, height); + + SendMessage(ii.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0); + + ii.xp=x; + ii.yp=y; + ii.width = width; + ii.height = height; + ii.text = text; + ii.original = text; + ii.focusText = text; + ii.id=id; + ii.callBack=cb; + + II.push_back(ii); + + iiByHwnd[ii.hWnd] = &II.back(); + //if (Help.length() > 0) + // addToolTip(Help, ii.hWnd); + + FocusList.push_back(ii.hWnd); + return II.back(); +} + + +ListBoxInfo &gdioutput::addListBox(const string &id, int width, int height, GUICALLBACK cb, const string &Explanation, const string &Help, bool multiple) +{ + return addListBox(CurrentX, CurrentY, id, width, height, cb, Explanation, Help, multiple); +} + +LRESULT CALLBACK GetMsgProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { + ListBoxInfo *lbi = (ListBoxInfo *)(GetWindowLongPtr(hWnd, GWL_USERDATA)); + if (!lbi) { + throw std::exception("Internal GDI error"); + } + + LPARAM res = CallWindowProc(lbi->originalProc, hWnd, iMsg, wParam, lParam); + if (iMsg == WM_VSCROLL || iMsg == WM_MOUSEWHEEL || iMsg == WM_KEYDOWN) { + int topIndex = CallWindowProc(lbi->originalProc, hWnd, LB_GETTOPINDEX, 0, 0); + if (lbi->lbiSync) { + ListBoxInfo *other = lbi->lbiSync; + CallWindowProc(other->originalProc, other->hWnd, LB_SETTOPINDEX, topIndex, 0); + } + } + return res; +} + +void gdioutput::synchronizeListScroll(const string &id1, const string &id2) +{ + ListBoxInfo *a = 0, *b = 0; + list::iterator it; + for (it = LBI.begin(); it != LBI.end(); ++it) { + if (it->id == id1) + a = &*it; + else if (it->id == id2) + b = &*it; + } + if (!a || !b) + throw std::exception("Not found"); + + a->lbiSync = b; + b->lbiSync = a; + SetWindowLongPtr(a->hWnd, GWL_USERDATA, LONG_PTR(a)); + SetWindowLongPtr(b->hWnd, GWL_USERDATA, LONG_PTR(b)); + + a->originalProc = WNDPROC(GetWindowLongPtr(a->hWnd, GWL_WNDPROC)); + b->originalProc = WNDPROC(GetWindowLongPtr(b->hWnd, GWL_WNDPROC)); + + SetWindowLongPtr(a->hWnd, GWL_WNDPROC, LONG_PTR(GetMsgProc)); + SetWindowLongPtr(b->hWnd, GWL_WNDPROC, LONG_PTR(GetMsgProc)); +} + +ListBoxInfo &gdioutput::addListBox(int x, int y, const string &id, int width, int height, GUICALLBACK cb, const string &Explanation, const string &Help, bool multiple) +{ + if (Explanation.length()>0) { + addString(id+"_expl", y, x, 0, Explanation); + y+=lineHeight; + } + ListBoxInfo lbi; + int ox=OffsetX; + int oy=OffsetY; + + DWORD style=WS_TABSTOP|WS_VISIBLE|WS_CHILD|WS_BORDER|LBS_USETABSTOPS|LBS_NOTIFY|WS_VSCROLL; + + if (multiple) + style|=LBS_MULTIPLESEL; + + lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "", style, + x-ox, y-oy, int(width*scale), int(height*scale), hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); +/* + if (id == "Punches") { + winHandle = WNDPROC(GetWindowLong(lbi.hWnd, GWL_WNDPROC)); + SetWindowLong(lbi.hWnd, GWL_WNDPROC, LONG(GetMsgProc)); + }*/ + + updatePos(x, y, int(scale*(width+5)), int(scale * (height+2))); + SendMessage(lbi.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0); + + lbi.IsCombo=false; + lbi.multipleSelection = multiple; + lbi.xp=x; + lbi.yp=y; + lbi.width = scale*width; + lbi.height = scale*height; + lbi.id=id; + lbi.callBack=cb; + LBI.push_back(lbi); + lbiByHwnd[lbi.hWnd] = &LBI.back(); + if (Help.length() > 0) + addToolTip(id, Help, lbi.hWnd); + + FocusList.push_back(lbi.hWnd); + return LBI.back(); +} + +void gdioutput::setSelection(const string &id, const set &selection) +{ + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it){ + if (it->id==id && !it->IsCombo) { + list::const_iterator cit; + + if (selection.count(-1)==1) + SendMessage(it->hWnd, LB_SETSEL, 1, -1); + else { + int count=SendMessage(it->hWnd, LB_GETCOUNT, 0,0); + SendMessage(it->hWnd, LB_SETSEL, 0, -1); + for(int i=0;ihWnd, LB_GETITEMDATA, i, 0); + + if (selection.count(d)==1) + SendMessage(it->hWnd, LB_SETSEL, 1, i); + } + return; + } + } + } +} + +void gdioutput::getSelection(const string &id, set &selection) { + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it){ + if (it->id==id && !it->IsCombo) { + selection.clear(); + int count=SendMessage(it->hWnd, LB_GETCOUNT, 0,0); + for(int i=0;ihWnd, LB_GETSEL, i, 0); + if (s) { + int d=SendMessage(it->hWnd, LB_GETITEMDATA, i, 0); + selection.insert(d); + } + } + return; + } + } + + #ifdef _DEBUG + string err = string("Internal Error, identifier not found: X#") + id; + throw std::exception(err.c_str()); + #endif +} + +ListBoxInfo &gdioutput::addSelection(const string &id, int width, int height, GUICALLBACK cb, const string &Explanation, const string &Help) +{ + return addSelection(CurrentX, CurrentY, id, width, height, cb, Explanation, Help); +} + +ListBoxInfo &gdioutput::addSelection(int x, int y, const string &id, int width, int height, GUICALLBACK cb, const string &Explanation, const string &Help) +{ + if (Explanation.length()>0) { + addString("", y, x, 0, Explanation); + y+=lineHeight; + } + + ListBoxInfo lbi; + + int ox = OffsetX; + int oy = OffsetY; + + lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "", WS_TABSTOP|WS_VISIBLE | WS_CHILD |WS_BORDER|CBS_DROPDOWNLIST|WS_VSCROLL , + x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + + updatePos(x, y, int(scale*(width+5)), int(scale*30)); + + SendMessage(lbi.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0); + + lbi.IsCombo=true; + lbi.xp=x; + lbi.yp=y; + lbi.width = scale*width; + lbi.height = scale*height; + lbi.id=id; + lbi.callBack=cb; + + LBI.push_back(lbi); + lbiByHwnd[lbi.hWnd] = &LBI.back(); + + if (Help.length() > 0) + addToolTip(id, Help, lbi.hWnd); + + FocusList.push_back(lbi.hWnd); + return LBI.back(); +} + + + +ListBoxInfo &gdioutput::addCombo(const string &id, int width, int height, GUICALLBACK cb, const string &Explanation, const string &Help) +{ + return addCombo(CurrentX, CurrentY, id, width, height, cb, Explanation, Help); +} + +ListBoxInfo &gdioutput::addCombo(int x, int y, const string &id, int width, int height, GUICALLBACK cb, const string &Explanation, const string &Help) +{ + if (Explanation.length()>0) { + addString("", y, x, 0, Explanation); + y+=lineHeight; + } + + ListBoxInfo lbi; + int ox=OffsetX; + int oy=OffsetY; + + lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "", WS_TABSTOP|WS_VISIBLE | WS_CHILD |WS_BORDER|CBS_DROPDOWN |CBS_AUTOHSCROLL, + x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL, + (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); + + updatePos(x, y, int(scale * (width+5)), getButtonHeight()+scaleLength(5)); + + SendMessage(lbi.hWnd, WM_SETFONT, (WPARAM) getGUIFont(), 0); + + lbi.IsCombo=true; + lbi.xp=x; + lbi.yp=y; + lbi.width = scale*width; + lbi.height = scale*height; + lbi.id=id; + lbi.callBack=cb; + + LBI.push_back(lbi); + lbiByHwnd[lbi.hWnd] = &LBI.back(); + + if (Help.length() > 0) + addToolTip(id, Help, lbi.hWnd); + + FocusList.push_back(lbi.hWnd); + return LBI.back(); +} + +bool gdioutput::addItem(const string &id, const string &text, size_t data) +{ + list::reverse_iterator it; + for (it=LBI.rbegin(); it != LBI.rend(); ++it) { + if (it->id==id) { + if (it->IsCombo) { + int index=SendMessage(it->hWnd, CB_ADDSTRING, 0, LPARAM(text.c_str())); + SendMessage(it->hWnd, CB_SETITEMDATA, index, data); + it->data2Index[data] = index; + } + else { + int index=SendMessage(it->hWnd, LB_INSERTSTRING, -1, LPARAM(text.c_str())); + SendMessage(it->hWnd, LB_SETITEMDATA, index, data); + it->data2Index[data] = index; + } + return true; + } + } + return false; +} + +bool gdioutput::addItem(const string &id, const vector< pair > &items) +{ + list::reverse_iterator it; + for (it=LBI.rbegin(); it != LBI.rend(); ++it) { + if (it->id==id) { + if (it->IsCombo) { + SendMessage(it->hWnd, CB_RESETCONTENT, 0, 0); + SendMessage(it->hWnd, CB_INITSTORAGE, items.size(), 48); + it->data2Index.clear(); + + for (size_t k = 0; khWnd, CB_ADDSTRING, 0, LPARAM(items[k].first.c_str())); + SendMessage(it->hWnd, CB_SETITEMDATA, index, items[k].second); + it->data2Index[items[k].second] = index; + } + } + else { + SendMessage(it->hWnd, LB_RESETCONTENT, 0, 0); + SendMessage(it->hWnd, LB_INITSTORAGE, items.size(), 48); + it->data2Index.clear(); + for (size_t k = 0; khWnd, LB_INSERTSTRING, -1, LPARAM(items[k].first.c_str())); + SendMessage(it->hWnd, LB_SETITEMDATA, index, items[k].second); + it->data2Index[items[k].second] = index; + } + } + return true; + } + } + return false; +} + +void gdioutput::filterOnData(const string &id, const stdext::hash_set &filter) { + list::iterator it; + for (it=LBI.begin(); it != LBI.end(); ++it) { + if (it->id==id) { + if (it->IsCombo) { + } + else { + const HWND &hWnd = it->hWnd; + int count = SendMessage(hWnd, LB_GETCOUNT, 0, 0); + for (int ix = count - 1; ix>=0; ix--) { + int ret = SendMessage(hWnd, LB_GETITEMDATA, ix, 0); + if (ret != LB_ERR && filter.count(ret) == 0) + SendMessage(hWnd, LB_DELETESTRING, ix, 0); + } + return; + } + } + } + assert(false); +} + +bool gdioutput::clearList(const string &id) +{ + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it){ + if (it->id==id) { + it->original = ""; + it->originalIdx = -1; + if (it->IsCombo) + SendMessage(it->hWnd, CB_RESETCONTENT , 0, 0); + else + SendMessage(it->hWnd, LB_RESETCONTENT , 0, 0); + return true; + } + } + + return false; +} + +bool gdioutput::getSelectedItem(const string &id, ListBoxInfo &lbi) { + lbi = ListBoxInfo(); + list::iterator it; + for (it=LBI.begin(); it != LBI.end(); ++it) { + if (it->id==id) { + bool ret = getSelectedItem(*it); + it->copyUserData(lbi); + return ret; + } + } + return false; +} + +pair gdioutput::getSelectedItem(const string &id) { + ListBoxInfo lbi; + bool ret = getSelectedItem(id, lbi); + return make_pair(lbi.data, ret); +} + +pair gdioutput::getSelectedItem(const char *id) { + string ids = id; + return getSelectedItem(ids); +} + +void ListBoxInfo::copyUserData(ListBoxInfo &dest) const { + dest.data = data; + dest.text = text; + dest.id = id; + dest.extra = extra; + dest.index = index; + dest.IsCombo = IsCombo; +} + +bool gdioutput::getSelectedItem(ListBoxInfo &lbi) { + if (lbi.IsCombo) { + int index=SendMessage(lbi.hWnd, CB_GETCURSEL, 0, 0); + + if (index == CB_ERR) { + char bf[256]; + GetWindowText(lbi.hWnd, bf, 256); + lbi.text=bf; + lbi.data=-1; + lbi.index=index; + return false; + } + lbi.data=SendMessage(lbi.hWnd, CB_GETITEMDATA, index, 0); + char bf[1024]; + if (SendMessage(lbi.hWnd, CB_GETLBTEXT, index, LPARAM(bf)) != CB_ERR) + lbi.text=bf; + } + else { + int index=SendMessage(lbi.hWnd, LB_GETCURSEL, 0, 0); + + if (index==LB_ERR) + return false; + + lbi.data=SendMessage(lbi.hWnd, LB_GETITEMDATA, index, 0); + lbi.index=index; + + char bf[1024]; + if (SendMessage(lbi.hWnd, LB_GETTEXT, index, LPARAM(bf))!=LB_ERR) + lbi.text=bf; + } + return true; +} + +int gdioutput::getItemDataByName(const char *id, const char *name) const{ + list::const_iterator it; + for(it = LBI.begin(); it != LBI.end(); ++it){ + if (it->id==id) { + if (it->IsCombo) { + int ix = SendMessage(it->hWnd, CB_FINDSTRING, -1, LPARAM(name)); + if (ix >= 0) { + return SendMessage(it->hWnd, CB_GETITEMDATA, ix, 0); + } + return -1; + } + else { + int ix = SendMessage(it->hWnd, LB_FINDSTRING, -1, LPARAM(name)); + if (ix >= 0) { + return SendMessage(it->hWnd, LB_GETITEMDATA, ix, 0); + } + return -1; + } + } + } + return -1; +} + +bool gdioutput::selectItemByData(const char *id, int data) +{ + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it){ + if (it->id==id) { + if (it->IsCombo) { + + if (data==-1) { + SendMessage(it->hWnd, CB_SETCURSEL, -1, 0); + it->data = 0; + it->text = ""; + it->original = ""; + it->originalIdx = -1; + return true; + } + else { + int count = SendMessage(it->hWnd, CB_GETCOUNT, 0, 0); + + for (int m = 0; m < count; m++) { + int ret = SendMessage(it->hWnd, CB_GETITEMDATA, m, 0); + if (ret == data) { + SendMessage(it->hWnd, CB_SETCURSEL, m, 0); + it->data = data; + it->originalIdx = data; + char bf[1024]; + if (SendMessage(it->hWnd, CB_GETLBTEXT, m, LPARAM(bf))!=CB_ERR) { + it->text = bf; + it->original = bf; + } + return true; + } + } + } + return false; + } + else { + if (data==-1) { + SendMessage(it->hWnd, LB_SETCURSEL, -1, 0); + it->data=0; + it->text = ""; + it->original = ""; + it->originalIdx = -1; + return true; + } + else { + int count = SendMessage(it->hWnd, LB_GETCOUNT, 0, 0); + for (int m = 0; m < count; m++) { + int ret = SendMessage(it->hWnd, LB_GETITEMDATA, m, 0); + + if (ret == data) { + SendMessage(it->hWnd, LB_SETCURSEL, m, 0); + it->data = data; + it->originalIdx = data; + char bf[1024]; + if (SendMessage(it->hWnd, LB_GETTEXT, m, LPARAM(bf)) != LB_ERR) { + it->text = bf; + it->original = bf; + } + return true; + } + } + } + return false; + } + } + } + return false; +} + +bool gdioutput::autoGrow(const char *id) { + list::iterator it; + int size = 0; + TextInfo TI; + TI.format=0; + TI.xp=0; + TI.yp=0; + TI.id=""; + TI.xlimit=0; + TI.callBack=0; + HDC hDC=GetDC(hWndTarget); + + for(it=LBI.begin(); it != LBI.end(); ++it){ + if (it->id==id) { + if (it->IsCombo) { + int count = SendMessage(it->hWnd, CB_GETCOUNT, 0, 0); + for (int m = 0; m < count; m++) { + char bf[1024]; + if (SendMessage(it->hWnd, CB_GETLBTEXT, m, LPARAM(bf))!=CB_ERR) { + TI.text = bf; + calcStringSize(TI, hDC); + size = max(size, TI.textRect.right - TI.textRect.left); + } + m++; + } + + ReleaseDC(hWndTarget, hDC); + + size += scaleLength(20); + if (size > it->width) { + it->width = size; + SetWindowPos(it->hWnd, 0, 0, 0, (int)it->width, (int)it->height, SWP_NOZORDER|SWP_NOCOPYBITS|SWP_NOMOVE); + updatePos(it->xp, it->yp, (int)it->width + int(scale*5), (int)it->height); + return true; + } + return false; + } + else { + int count = SendMessage(it->hWnd, LB_GETCOUNT, 0, 0); + for (int m = 0; m < count; m++) { + char bf[1024]; + int len = SendMessage(it->hWnd, LB_GETTEXT, m, LPARAM(bf)); + if (len!=LB_ERR) { + if (it->lastTabStop == 0) + TI.text = bf; + else { + int pos = len; + while(pos > 0) { + if (bf[pos-1] == '\t') { + break; + } + pos--; + } + TI.text = &bf[pos]; + } + calcStringSize(TI, hDC); + size = max(size, TI.realWidth + it->lastTabStop); + } + } + + ReleaseDC(hWndTarget, hDC); + size += scaleLength(20); + if (size > it->width) { + it->width = size; + SetWindowPos(it->hWnd, 0, 0, 0, (int)it->width, (int)it->height, SWP_NOZORDER|SWP_NOCOPYBITS|SWP_NOMOVE); + updatePos(it->xp, it->yp, (int)it->width+int(scale*5), (int)it->height); + return true; + } + return false; + } + } + } + + ReleaseDC(hWndTarget, hDC); + return false; +} + + +void gdioutput::removeSelected(const char *id) +{ +} + +LRESULT gdioutput::ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam) +{ + string msg; + try { + return ProcessMsgWrp(iMessage, lParam, wParam); + } + catch(std::exception &ex) { + msg=ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg="Ett okänt fel inträffade."; + } + + + if (!msg.empty()) { + alert(msg); + setWaitCursor(false); + } + return 0; +} + +void gdioutput::processButtonMessage(ButtonInfo &bi, DWORD wParam) +{ + WORD hwParam = HIWORD(wParam); + + switch (hwParam) { + case BN_CLICKED: { + string cmd; + if (getRecorder().recording()) { + if (bi.isExtraString()) { + cmd = "press(\"" + bi.id + "\", \"" + bi.getExtra() + "\"); //" + bi.text; + } + else { + int arg = int(bi.extra); + if (arg > 1000000 || arg < -1000000 || arg == 0) + cmd = "press(\"" + bi.id + "\"); //" + bi.text; + else + cmd = "press(\"" + bi.id + "\", " + itos(bi.getExtraInt()) + "); //" + bi.text; + } + } + if (bi.isCheckbox) + bi.checked = SendMessage(bi.hWnd, BM_GETCHECK, 0, 0)==BST_CHECKED; + bi.synchData(); + if (bi.callBack || bi.handler) { + setWaitCursor(true); + if (!bi.handleEvent(*this, GUI_BUTTON) && bi.callBack) + bi.callBack(this, GUI_BUTTON, &bi); //it may be destroyed here... + + setWaitCursor(false); + } + getRecorder().record(cmd); + break; + } + case BN_SETFOCUS: + if (currentFocus.hWnd != bi.hWnd) { +// if (currentF ocus.wasTabbed) +// Button_SetState(currentFocus.hWnd, false); + currentFocus = bi.hWnd; + } + break; + case BN_KILLFOCUS: + if (currentFocus.hWnd == bi.hWnd) { +// if (currentFocus.wasTabbed) +// Button_SetState(currentFocus.hWnd, false); + } + break; + } +} + +void gdioutput::processEditMessage(InputInfo &bi, DWORD wParam) +{ + WORD hwParam = HIWORD(wParam); + + switch (hwParam) { + case EN_CHANGE: + if (bi.writeLock) + return; + getWindowText(bi.hWnd, bi.text); + if (bi.handler) + bi.handler->handle(*this, bi, GUI_INPUTCHANGE); + else if (bi.callBack) + bi.callBack(this, GUI_INPUTCHANGE, &bi); //it may be destroyed here... + + break; + + case EN_KILLFOCUS: { + string old = bi.focusText; + getWindowText(bi.hWnd, bi.text); + bi.synchData(); + bool equal = old == bi.text; + string cmd = "input(\"" + bi.id + "\", \"" + bi.text + "\");"; + if (bi.handler) + bi.handler->handle(*this, bi, GUI_INPUT); + else if (bi.callBack) + bi.callBack(this, GUI_INPUT, &bi); + if (!equal) + getRecorder().record(cmd); + break; + } + case EN_SETFOCUS: + currentFocus = bi.hWnd; + getWindowText(bi.hWnd, bi.text); + bi.synchData(); + bi.focusText = bi.text; + if (bi.handler) + bi.handler->handle(*this, bi, GUI_FOCUS); + else if (bi.callBack) + bi.callBack(this, GUI_FOCUS, &bi); + break; + } +} + +void gdioutput::processComboMessage(ListBoxInfo &bi, DWORD wParam) +{ + WORD hwParam = HIWORD(wParam); + int index; + switch (hwParam) { + case CBN_SETFOCUS: + currentFocus = bi.hWnd; + lockUpDown = true; + break; + case CBN_KILLFOCUS: + lockUpDown = false; + + char bf[1024]; + index=SendMessage(bi.hWnd, CB_GETCURSEL, 0, 0); + + if (index != CB_ERR) { + if (SendMessage(bi.hWnd, CB_GETLBTEXT, index, LPARAM(bf)) != CB_ERR) { + bi.text = bf; + bi.data=SendMessage(bi.hWnd, CB_GETITEMDATA, index, 0); + if (bi.handler) + bi.handler->handle(*this, bi, GUI_COMBO); + else if (bi.callBack) + bi.callBack(this, GUI_COMBO, &bi); //it may be destroyed here... + } + } + else { + GetWindowText(bi.hWnd, bf, sizeof(bf)-1); + bi.data = -1; + bi.text = bf; + string cmd = "input(\"" + bi.id + "\", \"" + bi.text + "\");"; + if (bi.handler) + bi.handler->handle(*this, bi, GUI_COMBO); + else if (bi.callBack) + bi.callBack(this, GUI_COMBO, &bi); //it may be destroyed here... + getRecorder().record(cmd); + } + break; + + case CBN_EDITCHANGE: { + if (bi.writeLock) + return; + getWindowText(bi.hWnd, bi.text); + if (bi.handler) + bi.handler->handle(*this, bi, GUI_COMBOCHANGE); + else if (bi.callBack) + bi.callBack(this, GUI_COMBOCHANGE, &bi); //it may be destroyed here... + break; + } + case CBN_SELCHANGE: + index=SendMessage(bi.hWnd, CB_GETCURSEL, 0, 0); + + if (index != CB_ERR) { + bi.data=SendMessage(bi.hWnd, CB_GETITEMDATA, index, 0); + + char bf[1024]; + if (SendMessage(bi.hWnd, CB_GETLBTEXT, index, LPARAM(bf)) != CB_ERR) + bi.text=bf; + string cmd = "select(\"" + bi.id + "\", " + itos(bi.data) + ");"; + internalSelect(bi); + getRecorder().record(cmd); + } + break; + } +} + +#ifndef MEOSDB + +void gdioutput::keyCommand(KeyCommandCode code) { + if (hasCommandLock()) + return; + + if (code == KC_SLOWDOWN) + autoSpeed *= 0.9; + else if (code == KC_SPEEDUP) + autoSpeed *= 1.0/0.9; + + string msg; + try { + list::iterator tit; + if (useTables) { + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->keyCommand(*this, code)) + return; + } + + for (list::iterator it = Events.begin(); it != Events.end(); ++it) { + if (it->getKeyCommand() == code) { + it->setData("", 0); + it->setExtra(0); + if (!it->handleEvent(*this, GUI_EVENT) && it->callBack) { + it->callBack(this, GUI_EVENT, &*it); //it may be destroyed here... + } + return; + } + } + } + catch(std::exception &ex) { + msg = ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + + if (!msg.empty()) + alert(msg); +} + +#endif + +void gdioutput::processListMessage(ListBoxInfo &bi, DWORD wParam) +{ + WORD hwParam = HIWORD(wParam); + int index; + + switch (hwParam) { + case LBN_SETFOCUS: + currentFocus = bi.hWnd; + lockUpDown = true; + break; + case LBN_KILLFOCUS: + lockUpDown = false; + break; + case LBN_SELCHANGE: + case LBN_DBLCLK: + + index=SendMessage(bi.hWnd, LB_GETCURSEL, 0, 0); + + if (index!=LB_ERR) { + bi.data = SendMessage(bi.hWnd, LB_GETITEMDATA, index, 0); + + char bf[1024]; + if (SendMessage(bi.hWnd, LB_GETTEXT, index, LPARAM(bf)) != LB_ERR) + bi.text = bf; + + string cmd; + if (hwParam == LBN_SELCHANGE) + cmd = "select(\"" + bi.id + "\", " + itos(bi.data) + ");"; + else + cmd = "dblclick(\"" + bi.id + "\", " + itos(bi.data) + ");"; + + if (bi.callBack || bi.handler) { + setWaitCursor(true); + if (hwParam == LBN_SELCHANGE) { + if (bi.handler) + bi.handler->handle(*this, bi, GUI_LISTBOX); + else + bi.callBack(this, GUI_LISTBOX, &bi); //it may be destroyed here... + } + else { + if (bi.handler) + bi.handler->handle(*this, bi, GUI_LISTBOXSELECT); + else + bi.callBack(this, GUI_LISTBOXSELECT, &bi); //it may be destroyed here... + } + setWaitCursor(false); + } + getRecorder().record(cmd); + } + break; + } +} + + +LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam) +{ + if (iMessage==WM_COMMAND) { + WORD hwParam = HIWORD(wParam); + HWND hWnd=(HWND)lParam; + if (hwParam==EN_CHANGE) { + list::iterator tit; + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->inputChange(*this, hWnd)) + return 0; + } + + { + //list::iterator it; + //for (it=BI.begin(); it != BI.end(); ++it) { + stdext::hash_map::iterator it = biByHwnd.find(HWND(lParam)); + + // if (it->hWnd==hWnd) { + if ( it != biByHwnd.end() ) { + ButtonInfo &bi = *it->second; + processButtonMessage(bi, wParam); + return 0; + } + //} + } + + { + stdext::hash_map::iterator it = iiByHwnd.find(HWND(lParam)); + if (it != iiByHwnd.end()) { + InputInfo &ii = *it->second; + processEditMessage(ii, wParam); + return 0; + } + //list::iterator it; + /*for (it=II.begin(); it != II.end(); ++it) { + if (it->hWnd==hWnd) { + processEditMessage(*it, wParam); + return 0; + } + }*/ + } + + { + //list::iterator it; + //for(it=LBI.begin(); it != LBI.end(); ++it) { + stdext::hash_map::iterator it = lbiByHwnd.find(HWND(lParam)); + if (it != lbiByHwnd.end()) { + ListBoxInfo &lbi = *it->second; + if (lbi.IsCombo) + processComboMessage(lbi, wParam); + else + processListMessage(lbi, wParam); + return 0; + } + } + } + else if (iMessage==WM_MOUSEMOVE) { + POINT pt; + pt.x=(signed short)LOWORD(lParam); + pt.y=(signed short)HIWORD(lParam); + + list::iterator tit; + + bool GotCapture=false; + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + GotCapture = tit->table->mouseMove(*this, pt.x, pt.y) || GotCapture; + + if (GotCapture) + return 0; + + list::iterator it=IBox.begin(); + + + while (it != IBox.end()) { + if (PtInRect(&it->TextRect, pt) && (it->callBack || it->hasEventHandler())) { + SetCursor(LoadCursor(NULL, IDC_HAND)); + + HDC hDC=GetDC(hWndTarget); + drawBoxText(hDC, it->TextRect, *it, true); + ReleaseDC(hWndTarget, hDC); + SetCapture(hWndTarget); + GotCapture=true; + it->HasTCapture=true; + } + else { + if (it->HasTCapture) { + HDC hDC=GetDC(hWndTarget); + drawBoxText(hDC, it->TextRect, *it, false); + ReleaseDC(hWndTarget, hDC); + if (!GotCapture) + ReleaseCapture(); + it->HasTCapture=false; + } + } + + if (it->HasCapture) { + if (GetCapture()!=hWndTarget) { + HDC hDC=GetDC(hWndTarget); + drawCloseBox(hDC, it->Close, false); + ReleaseDC(hWndTarget, hDC); + if (!GotCapture) ReleaseCapture(); + it->HasCapture=false; + } + else if (!PtInRect(&it->Close, pt)) { + HDC hDC=GetDC(hWndTarget); + drawCloseBox(hDC, it->Close, false); + ReleaseDC(hWndTarget, hDC); + } + else { + HDC hDC=GetDC(hWndTarget); + drawCloseBox(hDC, it->Close, true); + ReleaseDC(hWndTarget, hDC); + } + } + ++it; + } + + for (size_t k=0;k::iterator it=IBox.begin(); + + POINT pt; + pt.x=(signed short)LOWORD(lParam); + pt.y=(signed short)HIWORD(lParam); + + list::iterator tit; + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->mouseLeftDown(*this, pt.x, pt.y)) + return 0; + + while(it!=IBox.end()) { + if (PtInRect(&it->Close, pt)) { + HDC hDC=GetDC(hWndTarget); + drawCloseBox(hDC, it->Close, true); + ReleaseDC(hWndTarget, hDC); + SetCapture(hWndTarget); + it->HasCapture=true; + } + ++it; + } + + + //Handle links + for (size_t k=0;k::iterator tit; + + list::iterator it=IBox.begin(); + + POINT pt; + pt.x=(signed short)LOWORD(lParam); + pt.y=(signed short)HIWORD(lParam); + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->mouseLeftUp(*this, pt.x, pt.y)) + return 0; + + while (it!=IBox.end()) { + if (it->HasCapture) { + HDC hDC=GetDC(hWndTarget); + drawCloseBox(hDC, it->Close, false); + ReleaseDC(hWndTarget, hDC); + ReleaseCapture(); + it->HasCapture=false; + + if (PtInRect(&it->Close, pt)) { + IBox.erase(it); + refresh(); + return 0; + } + } + else if (it->HasTCapture) { + ReleaseCapture(); + it->HasTCapture=false; + + if (PtInRect(&it->TextRect, pt)) { + if (!it->handleEvent(*this, GUI_INFOBOX) && it->callBack) + it->callBack(this, GUI_INFOBOX, &*it); //it may be destroyed here... + return 0; + } + } + ++it; + } + + //Handle links + for (size_t k=0;k::iterator tit; + POINT pt; + pt.x=(signed short)LOWORD(lParam); + pt.y=(signed short)HIWORD(lParam); + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->mouseLeftDblClick(*this, pt.x, pt.y)) + return 0; + + } + else if (iMessage == WM_CHAR) { + /*list::iterator tit; + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->character(*this, int(wParam), lParam & 0xFFFF)) + return 0;*/ + } + else if (iMessage == WM_CTLCOLOREDIT) { + //for (list::const_iterator it = II.begin(); it != II.end(); ++it) { + // if (it->hWnd == HWND(lParam)) { + stdext::hash_map::iterator it = iiByHwnd.find(HWND(lParam)); + if (it != iiByHwnd.end()) { + InputInfo &ii = *it->second; + if (ii.bgColor != colorDefault || ii.fgColor != colorDefault) { + if (ii.bgColor != colorDefault) { + SetDCBrushColor(HDC(wParam), ii.bgColor); + SetBkColor(HDC(wParam), ii.bgColor); + } + else { + SetDCBrushColor(HDC(wParam), GetSysColor(COLOR_WINDOW)); + SetBkColor(HDC(wParam), GetSysColor(COLOR_WINDOW)); + } + if (ii.fgColor != colorDefault) + SetTextColor(HDC(wParam), ii.fgColor); + return LRESULT(GetStockObject(DC_BRUSH)); + } + } + + return 0; + } + + return 0; +} + +void gdioutput::TabFocus(int direction) +{ + list::iterator tit; + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->tabFocus(*this, direction)) + return; + + if (FocusList.empty()) + return; + + list::iterator it=FocusList.begin(); + + while(it!=FocusList.end() && *it != currentFocus.hWnd) + ++it; + + //if (*it==CurrentFocus) + if (it!=FocusList.end()) { + if (direction==1){ + ++it; + if (it==FocusList.end()) it=FocusList.begin(); + while(!IsWindowEnabled(*it) && *it != currentFocus.hWnd){ + ++it; + if (it==FocusList.end()) it=FocusList.begin(); + } + } + else{ + if (it==FocusList.begin()) it=FocusList.end(); + + it--; + while(!IsWindowEnabled(*it) && *it != currentFocus.hWnd){ + if (it==FocusList.begin()) it=FocusList.end(); + it--; + } + + } + + // if (currentFocus.wasTabbed) + // Button_SetState(currentFocus.hWnd, false); + + HWND hWT = *it; + //SetFocus(0); + SetFocus(hWT); + currentFocus = hWT; + //currentFocus = *it; + /*if (biByHwnd.find(currentFocus.hWnd) != biByHwnd.end()) { + currentFocus.wasTabbed = true; + Button_SetState(currentFocus.hWnd, true); + }*/ + } + else{ + SetFocus(currentFocus.hWnd); + currentFocus=*FocusList.begin(); + + } +} + +bool gdioutput::isInputChanged(const string &exclude) +{ + for(list::iterator it=II.begin(); it != II.end(); ++it) { + if (it->id!=exclude) { + if (it->changed() && !it->ignoreCheck) + return true; + } + } + + for (list::iterator it = LBI.begin(); it != LBI.end(); ++it) { + getSelectedItem(*it); + if (it->changed() && !it->ignoreCheck) + return true; + } + + for (list::iterator it = BI.begin(); it != BI.end(); ++it) { + bool checked = SendMessage(it->hWnd, BM_GETCHECK, 0, 0)==BST_CHECKED; + if (it->originalState != checked) + return true; + } + + return false; +} + +InputInfo *gdioutput::replaceSelection(const char *id, const string &text) +{ + for(list::iterator it=II.begin(); it != II.end(); ++it) + if (it->id==id) { + SendMessage(it->hWnd, EM_REPLACESEL, TRUE, LPARAM(text.c_str())); + return &*it; + } + + return 0; +} + +BaseInfo *gdioutput::setInputFocus(const string &id, bool select) +{ + for(list::iterator it=II.begin(); it != II.end(); ++it) + if (it->id==id) { + scrollTo(it->xp, it->yp); + BaseInfo *bi = SetFocus(it->hWnd)!=NULL ? &*it: 0; + if (bi) { + if (select) + PostMessage(it->hWnd, EM_SETSEL, it->text.length(), 0); + } + return bi; + } + + for(list::iterator it=LBI.begin(); it!=LBI.end();++it) + if (it->id==id) { + scrollTo(it->xp, it->yp); + return SetFocus(it->hWnd)!=NULL ? &*it: 0; + } + + for(list::iterator it=BI.begin(); it!=BI.end();++it) + if (it->id==id) { + scrollTo(it->xp, it->yp); + return SetFocus(it->hWnd)!=NULL ? &*it: 0; + } + + return 0; +} + +InputInfo *gdioutput::getInputFocus() +{ + HWND hF=GetFocus(); + + if (hF) { + list::iterator it; + + for(it=II.begin(); it != II.end(); ++it) + if (it->hWnd==hF) + return &*it; + } + return 0; +} + +void gdioutput::Enter() +{ + if (hasCommandLock()) + return; + + string msg; + try { + doEnter(); + } + catch(std::exception &ex) { + msg = ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + + if (!msg.empty()) + alert(msg); +} + +void gdioutput::doEnter() +{ + list::iterator tit; + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->enter(*this)) + return; + + HWND hWnd=GetFocus(); + + for (list::iterator it=BI.begin(); it!=BI.end(); ++it) + if (it->isDefaultButton() && (it->callBack || it->handler)) { + if (it->handler) + it->handleEvent(*this, GUI_BUTTON); + else + it->callBack(this, GUI_BUTTON, &*it); + return; + } + + list::iterator it; + + for(it=II.begin(); it != II.end(); ++it) + if (it->hWnd==hWnd && (it->callBack || it->handler)){ + char bf[1024]; + GetWindowText(hWnd, bf, 1024); + it->text=bf; + if (it->handler) + it->handleEvent(*this, GUI_INPUT); + else + it->callBack(this, GUI_INPUT, &*it); + return; + } +} + +bool gdioutput::UpDown(int direction) +{ + string msg; + try { + return doUpDown(direction); + } + catch(std::exception &ex) { + msg = ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + + if (!msg.empty()) + alert(msg); + return false; +} + + +bool gdioutput::doUpDown(int direction) +{ + list::iterator tit; + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + if (tit->table->UpDown(*this, direction)) + return true; + + return false; +} + +void gdioutput::Escape() +{ + if (hasCommandLock()) + return; + string msg; + try { + doEscape(); + } + catch(std::exception &ex) { + msg = ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + + if (!msg.empty()) + alert(msg); +} + + +void gdioutput::doEscape() +{ + if (fullScreen) { + PostMessage(hWndTarget, WM_CLOSE, 0,0); + } + + list::iterator tit; + + if (useTables) + for (tit=Tables.begin(); tit!=Tables.end(); ++tit) + tit->table->escape(*this); + + for (list::iterator it=BI.begin(); it!=BI.end(); ++it) { + if (it->isCancelButton() && (it->callBack || it->handler) ) { + if (it->handler) + it->handleEvent(*this, GUI_BUTTON); + else + it->callBack(this, GUI_BUTTON, &*it); + return; + } + } +} + +void gdioutput::clearPage(bool autoRefresh, bool keepToolbar) { + lockUpDown = false; + hasAnyTimer = false; + enableTables(); + #ifndef MEOSDB + if (toolbar && !keepToolbar) + toolbar->hide(); + #endif + + while(!timers.empty()) { + KillTimer(hWndTarget, (UINT_PTR)&timers.back()); + timers.back().parent = 0; + timers.pop_back(); + } + + restorePoints.clear(); + shownStrings.clear(); + onClear=0; + FocusList.clear(); + currentFocus = 0; + TL.clear(); + itTL=TL.end(); + listDescription.clear(); + + if (hWndTarget && autoRefresh) + InvalidateRect(hWndTarget, NULL, true); + + fillDown(); + + hasCleared = true; + + for (ToolList::iterator it = toolTips.begin(); it != toolTips.end(); ++it) { + if (hWndToolTip) { + SendMessage(hWndToolTip, TTM_DELTOOL, 0, (LPARAM) &it->ti); + } + } + toolTips.clear(); + + { + list::iterator it; + for(it=BI.begin(); it != BI.end(); ++it) { + it->callBack = 0; + it->setHandler(0); + DestroyWindow(it->hWnd); + } + biByHwnd.clear(); + BI.clear(); + } + { + list::iterator it; + for(it=II.begin(); it != II.end(); ++it) { + it->callBack = 0; + it->setHandler(0); + DestroyWindow(it->hWnd); + } + iiByHwnd.clear(); + II.clear(); + } + + { + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it) { + it->callBack = 0; + it->setHandler(0); + DestroyWindow(it->hWnd); + if (it->writeLock) + hasCleared = true; + } + lbiByHwnd.clear(); + LBI.clear(); + } + + //delete table; + //table=0; + while(!Tables.empty()){ + Table *t=Tables.front().table; + Tables.front().table=0; + Tables.pop_front(); + t->hide(*this); + t->releaseOwnership(); + } + + DataInfo.clear(); + FocusList.clear(); + Events.clear(); + + Rectangles.clear(); + + MaxX=40; + MaxY=100; + + CurrentX=40; + CurrentY=START_YP; + + OffsetX=0; + OffsetY=0; + + renderOptimize=true; + + setRestorePoint(); + + if (autoRefresh) + updateScrollbars(); + + try { + if (postClear) + postClear(this, GUI_POSTCLEAR, 0); + } + catch(const std::exception &ex) { + if (isTestMode) + throw ex; + + string msg(ex.what()); + alert(msg); + } + postClear = 0; + + manualUpdate=!autoRefresh; +} + +void gdioutput::getWindowText(HWND hWnd, string &text) +{ + char bf[1024]; + char *bptr=bf; + + int len=GetWindowTextLength(hWnd); + + if (len>1023) + bptr=new char[len+1]; + + GetWindowText(hWnd, bptr, len+1); + text=bptr; + + if (len>1023) + delete[] bptr; +} + +BaseInfo &gdioutput::getBaseInfo(const char *id) const { + for(list::const_iterator it=II.begin(); + it != II.end(); ++it){ + if (it->id==id){ + return const_cast(*it); + } + } + + for(list::const_iterator it=LBI.begin(); + it != LBI.end(); ++it){ + if (it->id==id){ + return const_cast(*it); + } + } + + for(list::const_iterator it=BI.begin(); + it != BI.end(); ++it){ + if (it->id==id) { + return const_cast(*it); + } + } + + for(list::const_iterator it=TL.begin(); + it != TL.end(); ++it){ + if (it->id==id) { + return const_cast(*it); + } + } + + string err = string("Internal Error, identifier not found: X#") + id; + throw std::exception(err.c_str()); +} + +const string &gdioutput::getText(const char *id, bool acceptMissing) const +{ + char bf[1024]; + char *bptr=bf; + + for(list::const_iterator it=II.begin(); + it != II.end(); ++it){ + if (it->id==id){ + int len=GetWindowTextLength(it->hWnd); + + if (len>1023) + bptr=new char[len+1]; + + GetWindowText(it->hWnd, bptr, len+1); + const_cast(it->text)=bptr; + + if (len>1023) + delete[] bptr; + + return it->text; + } + } + + for(list::const_iterator it=LBI.begin(); + it != LBI.end(); ++it){ + if (it->id==id && it->IsCombo){ + if (!it->writeLock) { + GetWindowText(it->hWnd, bf, 1024); + const_cast(it->text)=bf; + } + return it->text; + } + } + + for(list::const_iterator it=TL.begin(); + it != TL.end(); ++it){ + if (it->id==id) { + return it->text; + } + } + +#ifdef _DEBUG + if (!acceptMissing) { + string err = string("Internal Error, identifier not found: X#") + id; + throw std::exception(err.c_str()); + } +#endif + return _EmptyString; +} + +bool gdioutput::hasField(const string &id) const +{ + for(list::const_iterator it=II.begin(); + it != II.end(); ++it){ + if (it->id==id) + return true; + } + + for(list::const_iterator it=LBI.begin(); + it != LBI.end(); ++it){ + if (it->id==id) + return true; + } + + for(list::const_iterator it=BI.begin(); + it != BI.end(); ++it){ + if (it->id==id) + return true; + } + + return false; +} + +int gdioutput::getTextNo(const char *id, bool acceptMissing) const +{ + const string &t = getText(id, acceptMissing); + return atoi(t.c_str()); +} + +BaseInfo *gdioutput::setTextTranslate(const char *id, + const string &text, + bool update) { + return setText(id, lang.tl(text), update); +} + +BaseInfo *gdioutput::setTextTranslate(const string &id, + const string &text, + bool update) { + return setText(id, lang.tl(text), update); +} + +BaseInfo *gdioutput::setTextTranslate(const char *id, + const char *text, + bool update) { + return setText(id, lang.tl(text), update); +} + + + +BaseInfo *gdioutput::setText(const char *id, int number, bool Update) +{ + char bf[16]; + sprintf_s(bf, 16, "%d", number); + return setText(id, bf, Update); +} + +BaseInfo *gdioutput::setTextZeroBlank(const char *id, int number, bool Update) +{ + if (number!=0) + return setText(id, number, Update); + else + return setText(id, "", Update); +} + +BaseInfo *gdioutput::setText(const char *id, const string &text, bool Update) +{ + for (list::iterator it=II.begin(); + it != II.end(); ++it) { + if (it->id==id) { + bool oldWR = it->writeLock; + it->writeLock = true; + SetWindowText(it->hWnd, text.c_str()); + it->writeLock = oldWR; + it->text = text; + it->synchData(); + it->original = text; + it->focusText = text; + return &*it; + } + } + + for (list::iterator it=LBI.begin(); + it != LBI.end(); ++it) { + if (it->id==id && it->IsCombo) { + SetWindowText(it->hWnd, text.c_str()); + it->text = text; + it->original = text; + return &*it; + } + } + + for (list::iterator it=BI.begin(); + it != BI.end(); ++it) { + if (it->id==id) { + SetWindowText(it->hWnd, text.c_str()); + it->text=text; + return &*it; + } + } + + for(list::iterator it=TL.begin(); + it != TL.end(); ++it){ + if (it->id==id) { + RECT rc=it->textRect; + + it->text=text; + calcStringSize(*it); + + rc.right=max(it->textRect.right, rc.right); + rc.bottom=max(it->textRect.bottom, rc.bottom); + + bool changed = updatePos(0, 0, it->textRect.right, it->textRect.bottom); + + if (Update && hWndTarget) { + if (changed) + InvalidateRect(hWndTarget, 0, true); + else + InvalidateRect(hWndTarget, &rc, true); + } + return &*it; + } + } + return 0; +} + +bool gdioutput::insertText(const string &id, const string &text) +{ + for (list::iterator it=II.begin(); + it != II.end(); ++it) { + if (it->id==id) { + SetWindowText(it->hWnd, text.c_str()); + it->text = text; + + if (it->handler) + it->handleEvent(*this, GUI_INPUT); + else if (it->callBack) + it->callBack(this, GUI_INPUT, &*it); + + return true; + } + } + return false; +} + +void gdioutput::setData(const string &id, DWORD data) +{ + void *pd = (void *)(data); + setData(id, pd); +} + +void gdioutput::setData(const string &id, void *data) +{ + list::iterator it; + for(it=DataInfo.begin(); it != DataInfo.end(); ++it){ + if (it->id==id){ + it->data = data; + return; + } + } + + DataStore ds; + ds.id=id; + ds.data=data; + + DataInfo.push_front(ds); + return; +} + +bool gdioutput::getData(const string &id, DWORD &data) const +{ + list::const_iterator it; + for(it=DataInfo.begin(); it != DataInfo.end(); ++it){ + if (it->id==id){ + data=DWORD(it->data); + return true; + } + } + + data=0; + return false; +} + +void *gdioutput::getData(const string &id) const { + list::const_iterator it; + for (it = DataInfo.begin(); it != DataInfo.end(); ++it){ + if (it->id == id){ + return it->data; + } + } + + throw meosException("Data X not found#" + id); +} + +bool gdioutput::hasData(const char *id) const { + DWORD dummy; + return getData(id, dummy); +} + + +bool gdioutput::updatePos(int x, int y, int width, int height) { + int ox=MaxX; + int oy=MaxY; + + MaxX=max(x+width, MaxX); + MaxY=max(y+height, MaxY); + bool changed = (ox!=MaxX || oy!=MaxY); + + if (changed && hWndTarget && !manualUpdate) { + RECT rc; + if (ox == MaxX) { + rc.top = oy - CurrentY - 5; + rc.bottom = MaxY - CurrentY + scaleLength(50); + rc.right = 10000; + rc.left = 0; + InvalidateRect(hWndTarget, &rc, true); + } + else { + InvalidateRect(hWndTarget, 0, true); + } + GetClientRect(hWndTarget, &rc); + + if (MaxX>rc.right || MaxY>rc.bottom) //Update scrollbars + SendMessage(hWndTarget, WM_SIZE, 0, MAKELONG(rc.right, rc.bottom)); + + } + + if (Direction==1) { + CurrentY=max(y+height, CurrentY); + } + else if (Direction==0) { + CurrentX=max(x+width, CurrentX); + } + return changed; +} + +void gdioutput::adjustDimension(int width, int height) +{ + int ox = MaxX; + int oy = MaxY; + + MaxX = width; + MaxY = height; + + if ((ox!=MaxX || oy!=MaxY) && hWndTarget && !manualUpdate) { + RECT rc; + if (ox == MaxX) { + rc.top = oy - CurrentY - 5; + rc.bottom = MaxY - CurrentY + scaleLength(50); + rc.right = 10000; + rc.left = 0; + InvalidateRect(hWndTarget, &rc, true); + } + else { + InvalidateRect(hWndTarget, 0, true); + } + GetClientRect(hWndTarget, &rc); + + if (MaxX>rc.right || MaxY>rc.bottom) //Update scrollbars + SendMessage(hWndTarget, WM_SIZE, 0, MAKELONG(rc.right, rc.bottom)); + + } +} + + +void gdioutput::alert(const string &msg) const +{ + if (isTestMode) { + if (!cmdAnswers.empty()) { + string ans = cmdAnswers.front(); + cmdAnswers.pop_front(); + if (ans == "ok") + return; + } + throw meosException(msg + "-- ok"); + } + + HWND hFlt = getToolbarWindow(); + if (hasToolbar()) { + EnableWindow(hFlt, false); + } + refreshFast(); + SetForegroundWindow(hWndAppMain); + setCommandLock(); + try { + MessageBoxW(hWndAppMain, toWide(lang.tl(msg)).c_str(), L"MeOS", MB_OK|MB_ICONINFORMATION); + if (hasToolbar()) { + EnableWindow(hFlt, true); + } + liftCommandLock(); + } + catch (...) { + liftCommandLock(); + throw; + } +} + +bool gdioutput::ask(const string &s) +{ + if (isTestMode) { + if (!cmdAnswers.empty()) { + string ans = cmdAnswers.front(); + cmdAnswers.pop_front(); + if (ans == "yes") + return true; + else if (ans == "no") + return false; + } + throw meosException(s + "--yes/no"); + } + + setCommandLock(); + SetForegroundWindow(hWndAppMain); + bool yes; + try { + yes = MessageBoxW(hWndAppMain, toWide(lang.tl(s)).c_str(), L"MeOS", MB_YESNO|MB_ICONQUESTION)==IDYES; + liftCommandLock(); + } + catch (...) { + liftCommandLock(); + throw; + } + + return yes; +} + +gdioutput::AskAnswer gdioutput::askCancel(const string &s) +{ + if (isTestMode) { + if (!cmdAnswers.empty()) { + string ans = cmdAnswers.front(); + cmdAnswers.pop_front(); + if (ans == "cancel") + return AnswerCancel; + else if (ans == "yes") + return AnswerYes; + else if (ans == "no") + return AnswerNo; + } + throw meosException(s + "--yes/no/cancel"); + } + + setCommandLock(); + SetForegroundWindow(hWndAppMain); + int a = MessageBoxW(hWndAppMain, toWide(lang.tl(s)).c_str(), L"MeOS", MB_YESNOCANCEL|MB_ICONQUESTION); + liftCommandLock(); + if (a == IDYES) + return AnswerYes; + else if (a == IDNO) + return AnswerNo; + else + return AnswerCancel; +} + + +void gdioutput::setTabStops(const string &Name, int t1, int t2) +{ + DWORD array[2]; + int n=1; + LONG bu=GetDialogBaseUnits(); + int baseunitX=LOWORD(bu); + array[0]=(t1 * 4) / baseunitX ; + array[1]=(t2 * 4) / baseunitX ; + int lastTabStop = 0; + if (t2>0) { + n=2; + lastTabStop = t2; + } + else { + lastTabStop = t1; + } + + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it){ + if (it->id==Name){ + if (!it->IsCombo) { + SendMessage(it->hWnd, LB_SETTABSTOPS, n, LPARAM(array)); + it->lastTabStop = lastTabStop; + } + return; + } + } +} + +void gdioutput::setInputStatus(const char *id, bool status, bool acceptMissing) { + bool hit = false; + for(list::iterator it=II.begin(); it != II.end(); ++it) + if (it->id==id) { + EnableWindow(it->hWnd, status); + hit = true; + } + for(list::iterator it=LBI.begin(); it != LBI.end(); ++it) + if (it->id==id) { + EnableWindow(it->hWnd, status); + hit = true; + } + for(list::iterator it=BI.begin(); it != BI.end(); ++it) + if (it->id==id) { + EnableWindow(it->hWnd, status); + if (it->isCheckbox) { + string tid = "T" + it->id; + for(list::iterator tit=TL.begin(); tit != TL.end(); ++tit){ + if (tit->id == tid) { + enableCheckBoxLink(*tit, status); + break; + } + } + } + + hit = true; + if (status==false) { + it->storedFlags |= it->flags; + it->flags = 0; //Remove default status etc. + } + else { + // Restore flags + it->flags |= it->storedFlags; + } + } + + if (acceptMissing) + return; +#ifdef _DEBUG + if (!hit) { + string err = string("Internal Error, identifier not found: X#") + id; + throw std::exception(err.c_str()); + } +#endif +} + +void gdioutput::refresh() const { +#ifdef DEBUGRENDER + OutputDebugString("### Full refresh\n"); +#endif + if (hWndTarget) { + updateScrollbars(); + InvalidateRect(hWndTarget, NULL, true); + UpdateWindow(hWndTarget); + } + screenXYToString.clear(); + stringToScreenXY.clear(); +} + +void gdioutput::refreshFast() const { +#ifdef DEBUGRENDER + OutputDebugString("Fast refresh\n"); +#endif + if (hWndTarget) { + InvalidateRect(hWndTarget, NULL, true); + UpdateWindow(hWndTarget); + } + screenXYToString.clear(); + stringToScreenXY.clear(); +} + + +void gdioutput::takeShownStringsSnapshot() { +#ifdef DEBUGRENDER + OutputDebugString("** Take snapshot\n"); +#endif + + screenXYToString.clear(); + stringToScreenXY.clear(); + snapshotMaxXY.first = MaxX; + snapshotMaxXY.second = MaxY - OffsetY; +#ifdef DEBUGRENDER + OutputDebugString(("ymax:" + itos(MaxY-OffsetY) + "\n").c_str()); +#endif + for (size_t k = 0; k < shownStrings.size(); k++) { + if (shownStrings[k]->hasTimer) + continue; //Ignore + int x = shownStrings[k]->xp - OffsetX; + int y = shownStrings[k]->yp - OffsetY; + const string &str = shownStrings[k]->text; +#ifdef DEBUGRENDER + //OutputDebugString((itos(k) + ":" + itos(shownStrings[k]->xp) + "," + itos(shownStrings[k]->yp) + "," + str + "\n").c_str()); +#endif + screenXYToString.insert(make_pair(make_pair(x, y), ScreenStringInfo(shownStrings[k]->textRect, str))); + if (stringToScreenXY.count(str) == 0) + stringToScreenXY.insert(make_pair(str,make_pair(x, y))); + } + + RECT rc; + GetClientRect(hWndTarget, &rc); + int BoundYup = OffsetY; + int BoundYdown = OffsetY+rc.bottom; + for (list::iterator it = Rectangles.begin(); it != Rectangles.end(); ++it) { + if (it->rc.top <= BoundYdown && it->rc.bottom >= BoundYup) { + string r = "[R]"; + RECT rect_rc = it->rc; + OffsetRect(&rect_rc, -OffsetX, -OffsetY); + screenXYToString.insert(make_pair(make_pair(rect_rc.left, rect_rc.top), ScreenStringInfo(rect_rc, r))); + } + } +} + +void updateScrollInfo(HWND hWnd, gdioutput &gdi, int nHeight, int nWidth); + +void gdioutput::refreshSmartFromSnapshot(bool allowMoveOffset) { +#ifdef DEBUGRENDER + OutputDebugString("Smart refresh\n"); +#endif + + RECT clientRC; + GetClientRect(hWndTarget, &clientRC); + + updateStringPosCache(); + + vector changedStrings; + bool updateScroll = false; + if (allowMoveOffset) { + map< pair, int> offsetCount; + int misses = 0, hits = 0; + for (size_t k = 0; k < shownStrings.size(); k++) { + if (shownStrings[k]->hasTimer) + continue; //Ignore + int x = shownStrings[k]->xp - OffsetX; + int y = shownStrings[k]->yp - OffsetY; + const string &str = shownStrings[k]->text; + map >::const_iterator found = stringToScreenXY.find(str); + if (found != stringToScreenXY.end()) { + hits++; + int ox = found->second.first - x; + int oy = found->second.second - y; + ++offsetCount[make_pair(ox, oy)]; + if (hits > 30) + break; + } + else { + misses++; + if (misses > 20) + break; + } + } + + // Choose dominating offset, if dominating enough + pair offset(0,0); + int maxVal = 10; // Require at least 10 hits + for(map< pair, int>::iterator it = offsetCount.begin(); it != offsetCount.end(); ++it) { + if (it->second > maxVal) { + maxVal = it->second; + offset = it->first; + } + } + + int maxOffsetY=max(GetPageY()-clientRC.bottom, 0); + int maxOffsetX=max(GetPageX()-clientRC.right, 0); + int noy = OffsetY - offset.second; + int nox = OffsetX - offset.first; + if ((offset.first != 0 && nox>0 && nox0 && noyhasTimer) + continue; //Ignore + + int x = shownStrings[k]->xp - OffsetX; + int y = shownStrings[k]->yp - OffsetY; + const string &str = shownStrings[k]->text; +#ifdef DEBUGRENDER + //OutputDebugString((itos(k) + ":" + itos(shownStrings[k]->xp) + "," + itos(shownStrings[k]->yp) + "," + str + "\n").c_str()); +#endif + map, ScreenStringInfo>::iterator res = screenXYToString.find(make_pair(x,y)); + if (res != screenXYToString.end()) { + res->second.reached = true; + if (str != res->second.str) { + if (res->second.rc.bottom >= 0 && res->second.rc.top <= clientRC.bottom) { + changedStrings.push_back(k); + invalidRect.top = min(invalidRect.top, res->second.rc.top); + invalidRect.bottom = max(invalidRect.bottom, res->second.rc.bottom); + invalidRect.left = min(invalidRect.left, res->second.rc.left); + invalidRect.right = max(invalidRect.right, res->second.rc.right); + } + } + } + else + changedStrings.push_back(k); + } + + RECT rc; + GetClientRect(hWndTarget, &rc); + int BoundYup = OffsetY; + int BoundYdown = OffsetY+rc.bottom; + for (list::iterator it = Rectangles.begin(); it != Rectangles.end(); ++it) { + if (it->rc.top <= BoundYdown && it->rc.bottom >= BoundYup) { + RECT rect_rc = it->rc; + OffsetRect(&rect_rc, -OffsetX, -OffsetY); + + map, ScreenStringInfo>::iterator res = screenXYToString.find(make_pair(rect_rc.left, rect_rc.top)); + bool add = false; + if (res != screenXYToString.end()) { + res->second.reached = true; + if (!EqualRect(&rect_rc, &res->second.rc)) { + add = true; + invalidRect.top = min(invalidRect.top, res->second.rc.top); + invalidRect.bottom = max(invalidRect.bottom, res->second.rc.bottom); + invalidRect.left = min(invalidRect.left, res->second.rc.left); + invalidRect.right = max(invalidRect.right, res->second.rc.right); + } + } + else + add = true; + + if (add) { + invalid = true; + invalidRect.top = min(invalidRect.top, rect_rc.top); + invalidRect.bottom = max(invalidRect.bottom, rect_rc.bottom); + invalidRect.left = min(invalidRect.left, rect_rc.left); + invalidRect.right = max(invalidRect.right, rect_rc.right); + } + } + } + + for (map, ScreenStringInfo>::iterator it = screenXYToString.begin(); it != screenXYToString.end(); ++it) { + if (!it->second.reached) { + invalid = true; + invalidRect.top = min(invalidRect.top, it->second.rc.top); + invalidRect.bottom = max(invalidRect.bottom, it->second.rc.bottom); + invalidRect.left = min(invalidRect.left, it->second.rc.left); + invalidRect.right = max(invalidRect.right, it->second.rc.right); + } + } + + screenXYToString.clear(); + stringToScreenXY.clear(); + + if (snapshotMaxXY.second != MaxY - OffsetY) { + // We added (or removed) a row. Add result to list is typical case. + int currentMaxP = (MaxY - OffsetY); + int oldMaxP = snapshotMaxXY.second; + bool bottomVisible = ((currentMaxP < clientRC.bottom + 15) && currentMaxP > -15) || + ((oldMaxP < clientRC.bottom + 15) && oldMaxP > -15); + if (bottomVisible && !highContrast && oldMaxP != currentMaxP) { + invalid = true; + invalidRect.top = min(invalidRect.top, oldMaxP-15); + invalidRect.top = min(invalidRect.top, currentMaxP-15); + + invalidRect.bottom = max(invalidRect.bottom, oldMaxP+15); + invalidRect.bottom = max(invalidRect.bottom, currentMaxP+15); + + invalidRect.left = 0; + invalidRect.right = clientRC.right; + #ifdef DEBUGRENDER + OutputDebugString("Extend Y\n"); + #endif + } + updateScroll = true; + } + + if (snapshotMaxXY.first != MaxX) { + // This almost never happens + invalidRect = clientRC; + invalid = true; + updateScroll; + } + + if (updateScroll) { + bool hc = highContrast; + highContrast = false; + updateScrollInfo(hWndTarget, *this, clientRC.bottom, clientRC.right); // No throw + highContrast = hc; + } + if (changedStrings.empty() && !invalid) { + #ifdef DEBUGRENDER + //breakRender = true; + OutputDebugString("*** NO CHANGE\n"); + #endif + + return; + } + + for (size_t k = 0; k< changedStrings.size(); k++) { + TextInfo &ti = *shownStrings[changedStrings[k]]; + invalidRect.top = min(invalidRect.top, ti.textRect.top); + invalidRect.bottom = max(invalidRect.bottom, ti.textRect.bottom); + invalidRect.left = min(invalidRect.left, ti.textRect.left); + invalidRect.right = max(invalidRect.right, ti.textRect.right); + } + + + if (invalidRect.bottom<0 || invalidRect.right < 0 + || invalidRect.top > clientRC.bottom || invalidRect.left > clientRC.right) { + + #ifdef DEBUGRENDER + //breakRender = true; + OutputDebugString("*** EMPTY CHANGE\n"); + #endif + + return; + } + + if (hWndTarget) { + //InvalidateRect(hWndTarget, &invalidRect, true); + //UpdateWindow(hWndTarget); + HDC hDC = GetDC(hWndTarget); + IntersectClipRect(hDC, invalidRect.left, invalidRect.top, invalidRect.right, invalidRect.bottom); + //debugDrawColor = RGB((30*counterRender)%256,0,0); + draw(hDC, clientRC, invalidRect); + //debugDrawColor = 0; + + ReleaseDC(hWndTarget, hDC); + } +} + + +void gdioutput::removeString(string id) +{ + list::iterator it; + for (it=TL.begin(); it != TL.end(); ++it) { + if (it->id==id) { + HDC hDC=GetDC(hWndTarget); + //TextOut( + RECT rc; + rc.left=it->xp; + rc.top=it->yp; + + DrawText(hDC, it->text.c_str(), -1, &rc, DT_CALCRECT|DT_NOPREFIX); + SelectObject(hDC, GetStockObject(NULL_PEN)); + SelectObject(hDC, Background); + Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom); + ReleaseDC(hWndTarget, hDC); + TL.erase(it); + shownStrings.clear(); + return; + } + } +} + +bool gdioutput::selectFirstItem(const string &id) +{ + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it) + if (it->id==id) { + bool ret; + if (it->IsCombo) + ret = SendMessage(it->hWnd, CB_SETCURSEL, 0,0)>=0; + else + ret = SendMessage(it->hWnd, LB_SETCURSEL, 0,0)>=0; + getSelectedItem(*it); + it->original = it->text; + it->originalIdx = it->data; + } + + return false; +} + +void gdioutput::setWindowTitle(const string &title) +{ + if (title.length()>0) { + string titlea=MakeDash(title + " - MeOS"); + wstring titlew = toWide(titlea); + SetWindowTextW(hWndAppMain, titlew.c_str()); + } + else SetWindowText(hWndAppMain, "MeOS"); +} + +void gdioutput::setWaitCursor(bool wait) +{ + if (wait) + SetCursor(LoadCursor(NULL, IDC_WAIT)); + else + SetCursor(LoadCursor(NULL, IDC_ARROW)); +} + +struct FadeInfo +{ + TextInfo ti; + DWORD Start; + DWORD End; + HWND hWnd; + COLORREF StartC; + COLORREF EndC; +}; + +void TextFader(void *f) +{ + FadeInfo *fi=(FadeInfo *)f; + HDC hDC=GetDC(fi->hWnd); + + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(hDC, TRANSPARENT); + + double p=0; + + double r1=GetRValue(fi->StartC); + double g1=GetGValue(fi->StartC); + double b1=GetBValue(fi->StartC); + + double r2=GetRValue(fi->EndC); + double g2=GetGValue(fi->EndC); + double b2=GetBValue(fi->EndC); + + while(p<1) + { + p=double(GetTickCount()-fi->Start)/double(fi->End-fi->Start); + + if (p>1) p=1; + + p=1-(p-1)*(p-1); + + int red=int((1-p)*r1+(p)*r2); + int green=int((1-p)*g1+(p)*g2); + int blue=int((1-p)*b1+(p)*b2); + //int green=int((p-1)*GetGValue(fi->StartC)+(p)*GetGValue(fi->EndC)); + //int blue=int((p-1)*GetBValue(fi->StartC)+(p)*GetBValue(fi->EndC)); + + SetTextColor(hDC, RGB(red, green, blue)); + TextOut(hDC, fi->ti.xp, fi->ti.yp, fi->ti.text.c_str(), fi->ti.text.length()); + Sleep(30); + //char bf[10]; + //fi->ti.text=fi->ti.text+itoa(red, bf, 16); + } + + ReleaseDC(fi->hWnd, hDC); + delete fi; +} + +void gdioutput::fadeOut(string Id, int ms) +{ + list::iterator it; + for(it=TL.begin(); it != TL.end(); ++it){ + if (it->id==Id){ + FadeInfo *fi=new FadeInfo; + fi->Start=GetTickCount(); + fi->End=fi->Start+ms; + fi->ti=*it; + fi->StartC=RGB(0, 0, 0); + fi->EndC=GetSysColor(COLOR_WINDOW); + fi->hWnd=hWndTarget; + _beginthread(TextFader, 0, fi); + TL.erase(it); + return; + } + } +} + +void gdioutput::RenderString(TextInfo &ti, HDC hDC) +{ + if (skipTextRender(ti.format)) + return; + + if (ti.hasTimer && ti.xp == 0) + return; + + HDC hThis=0; + + if (!hDC){ + assert(hWndTarget!=0); + hDC=hThis=GetDC(hWndTarget); + } + RECT rc; + rc.left=ti.xp-OffsetX; + rc.top=ti.yp-OffsetY; + rc.right = rc.left; + rc.bottom = rc.top; + + formatString(ti, hDC); + int format=ti.format&0xFF; + + if (format != 10 && (breakLines&ti.format) == 0){ + if (ti.xlimit==0){ + if (ti.format&textRight) { + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_NOPREFIX); + int dx = rc.right - rc.left; + ti.realWidth = dx; + rc.right-=dx; + rc.left-=dx; + ti.textRect=rc; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_RIGHT|DT_NOCLIP|DT_NOPREFIX); + } + else if (ti.format&textCenter) { + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CENTER|DT_CALCRECT|DT_NOPREFIX); + int dx = rc.right - rc.left; + ti.realWidth = dx; + rc.right-=dx/2; + rc.left-=dx/2; + ti.textRect=rc; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CENTER|DT_NOCLIP|DT_NOPREFIX); + } + else{ + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + ti.textRect=rc; + ti.realWidth = rc.right - rc.left; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_LEFT|DT_NOCLIP|DT_NOPREFIX); + } + } + else{ + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_NOPREFIX); + ti.realWidth = rc.right - rc.left; + if (ti.format&textRight) { + rc.right = rc.left + ti.xlimit - (rc.bottom - rc.top)/2; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_RIGHT|DT_NOPREFIX); + } + else if (ti.format&textCenter) { + rc.right = rc.left + ti.xlimit - (rc.bottom - rc.top)/2; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CENTER|DT_NOPREFIX); + } + else { + rc.right=rc.left+ti.xlimit; + DrawText(hDC, ti.text.c_str(), -1, &rc, DT_LEFT|DT_NOPREFIX); + } + ti.textRect=rc; + } + } + else { + memset(&rc, 0, sizeof(rc)); + int width = scaleLength( (breakLines&ti.format) ? ti.xlimit : 450 ); + rc.right = width; + int dx = (breakLines&ti.format) ? 0 : scaleLength(20); + ti.realWidth = width + dx; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); + ti.textRect=rc; + ti.textRect.right+=ti.xp+dx; + ti.textRect.left+=ti.xp; + ti.textRect.top+=ti.yp; + ti.textRect.bottom+=ti.yp+dx; + + if (ti.format == 10) { + DWORD c=GetSysColor(COLOR_INFOBK); + double red=GetRValue(c); + double green=GetGValue(c); + double blue=GetBValue(c); + + double blue1=min(255., blue*0.8); + double green1=min(255., green*1.05); + double red1=min(255., red*1.05); + + TRIVERTEX vert[2]; + vert [0] .x = ti.xp-OffsetX; + vert [0] .y = ti.yp-OffsetY; + vert [0] .Red = 0xff00&DWORD(red1*256); + vert [0] .Green = 0xff00&DWORD(green1*256); + vert [0] .Blue = 0xff00&DWORD(blue1*256); + vert [0] .Alpha = 0x0000; + + vert [1] .x = ti.xp+rc.right+dx-OffsetX; + vert [1] .y = ti.yp+rc.bottom+dx-OffsetY; + vert [1] .Red = 0xff00&DWORD(red*256); + vert [1] .Green = 0xff00&DWORD(green*256); + vert [1] .Blue = 0xff00&DWORD(blue*256); + vert [1] .Alpha = 0x0000; + + GRADIENT_RECT gr[1]; + gr[0].UpperLeft=0; + gr[0].LowerRight=1; + + GradientFill(hDC,vert, 2, gr, 1,GRADIENT_FILL_RECT_H); + SelectObject(hDC, GetStockObject(NULL_BRUSH)); + SelectObject(hDC, GetStockObject(DC_PEN)); + SetDCPenColor(hDC, RGB(DWORD(red*0.5), + DWORD(green*0.5), + DWORD(blue*0.5))); + + Rectangle(hDC, vert[0].x, vert[0].y, vert[1].x, vert[1].y); + + SetDCPenColor(hDC, RGB(DWORD(min(255., red*1.1)), + DWORD(min(255., green*1.2)), + DWORD(min(255., blue)))); + POINT pt; + MoveToEx(hDC, vert[0].x-1, vert[1].y, &pt); + LineTo(hDC, vert[0].x-1, vert[0].y-1); + LineTo(hDC, vert[1].x, vert[0].y-1); + + SetDCPenColor(hDC, RGB(DWORD(min(255., red*0.4)), + DWORD(min(255., green*0.4)), + DWORD(min(255., blue*0.4)))); + + MoveToEx(hDC, vert[1].x+0, vert[0].y, &pt); + LineTo(hDC, vert[1].x+0, vert[1].y+0); + LineTo(hDC, vert[0].x, vert[1].y+0); + + } + dx/=2; + rc.top=ti.yp+dx-OffsetY; + rc.left=ti.xp+dx-OffsetX; + rc.bottom+=ti.yp+dx-OffsetY; + rc.right=ti.xp+dx+width-OffsetX; + + SetTextColor(hDC, GetSysColor(COLOR_INFOTEXT)); + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); + } + + if (hThis) + ReleaseDC(hWndTarget, hDC); +} + +void gdioutput::RenderString(TextInfo &ti, const string &text, HDC hDC) +{ + if (skipTextRender(ti.format)) + return; + + RECT rc; + rc.left=ti.xp-OffsetX; + rc.top=ti.yp-OffsetY; + rc.right = rc.left; + rc.bottom = rc.top; + + int format=ti.format&0xFF; + assert(format!=10); + formatString(ti, hDC); + + if (ti.xlimit==0){ + if (ti.format&textRight) { + DrawText(hDC, text.c_str(), text.length(), &rc, DT_CALCRECT|DT_NOPREFIX); + int dx=rc.right-rc.left; + rc.right-=dx; + rc.left-=dx; + ti.textRect=rc; + DrawText(hDC, text.c_str(), text.length(), &rc, DT_RIGHT|DT_NOCLIP|DT_NOPREFIX); + } + else if (ti.format&textCenter) { + DrawText(hDC, text.c_str(), text.length(), &rc, DT_CENTER|DT_CALCRECT|DT_NOPREFIX); + int dx=rc.right-rc.left; + rc.right-=dx/2; + rc.left-=dx/2; + ti.textRect=rc; + DrawText(hDC, text.c_str(), text.length(), &rc, DT_CENTER|DT_NOCLIP|DT_NOPREFIX); + } + else{ + DrawText(hDC, text.c_str(), text.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + ti.textRect=rc; + DrawText(hDC, text.c_str(), text.length(), &rc, DT_LEFT|DT_NOCLIP|DT_NOPREFIX); + } + } + else{ + if (ti.format&textRight) { + DrawText(hDC, text.c_str(), text.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + rc.right = rc.left + ti.xlimit; + ti.textRect = rc; + DrawText(hDC, text.c_str(), text.length(), &rc, DT_RIGHT|DT_NOPREFIX); + } + else { + DrawText(hDC, text.c_str(), text.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + rc.right=rc.left+ti.xlimit; + DrawText(hDC, text.c_str(), text.length(), &rc, DT_LEFT|DT_NOPREFIX); + ti.textRect=rc; + } + } +} + +void gdioutput::resetLast() const { + lastFormet = -1; + lastActive = false; + lastHighlight = false; + lastColor = -1; + lastFont.clear(); +} + +void gdioutput::getFontInfo(const TextInfo &ti, FontInfo &fi) const { + if (ti.font.empty()) { + fi.name = 0; + fi.bold = fi.normal = fi.italic = 0; + } + else { + fi.name = &ti.font; + getFont(ti.font).getInfo(fi); + } +} + + +void gdioutput::formatString(const TextInfo &ti, HDC hDC) const +{ + int format=ti.format&0xFF; + + if (lastFormet == format && + lastActive == ti.active && + lastHighlight == ti.highlight && + lastColor == ti.color && + ti.font == lastFont) + return; + + if (ti.font.empty()) { + getCurrentFont().selectFont(hDC, format); + lastFont.clear(); + } + else { + getFont(ti.font).selectFont(hDC, format); + lastFont = ti.font; + } + + SetBkMode(hDC, TRANSPARENT); + + if (ti.active) + SetTextColor(hDC, RGB(255,0,0)); + else if (ti.highlight) + SetTextColor(hDC, RGB(64,64,128)); + else + SetTextColor(hDC, ti.color); +} + +void gdioutput::calcStringSize(TextInfo &ti, HDC hDC_in) const +{ + HDC hDC=hDC_in; + + if (!hDC) { + assert(hWndTarget!=0); + hDC=GetDC(hWndTarget); + } + RECT rc; + rc.left=ti.xp-OffsetX; + rc.top=ti.yp-OffsetY; + rc.right = rc.left; + rc.bottom = rc.top; + + resetLast(); + formatString(ti, hDC); + int format=ti.format&0xFF; + + if (format != 10 && (breakLines&ti.format) == 0) { + if (ti.xlimit==0){ + if (ti.format&textRight) { + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_NOPREFIX); + int dx=rc.right-rc.left; + ti.realWidth = dx; + rc.right-=dx; + rc.left-=dx; + ti.textRect=rc; + } + else if (ti.format&textCenter) { + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CENTER|DT_CALCRECT|DT_NOPREFIX); + int dx=rc.right-rc.left; + ti.realWidth = dx; + rc.right-=dx/2; + rc.left-=dx/2; + ti.textRect=rc; + } + else{ + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + ti.realWidth = rc.right - rc.left; + ti.textRect=rc; + } + } + else { + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_LEFT|DT_CALCRECT|DT_NOPREFIX); + ti.realWidth = rc.right - rc.left; + rc.right=rc.left+ti.xlimit; + ti.textRect=rc; + } + } + else { + memset(&rc, 0, sizeof(rc)); + rc.right = scaleLength( (breakLines&ti.format) ? ti.xlimit : 450 ); + int dx = (breakLines&ti.format) ? 0 : scaleLength(20); + ti.realWidth = rc.right + dx; + DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); + ti.textRect=rc; + ti.textRect.right+=ti.xp+dx; + ti.textRect.left+=ti.xp; + ti.textRect.top+=ti.yp; + ti.textRect.bottom+=ti.yp+dx; + } + + if (!hDC_in) + ReleaseDC(hWndTarget, hDC); +} + + +void gdioutput::updateScrollbars() const +{ + RECT rc; + GetClientRect(hWndTarget, &rc); + SendMessage(hWndTarget, WM_SIZE, 0, MAKELONG(rc.right, rc.bottom)); +} + + +void gdioutput::updateObjectPositions() +{ + { + list::iterator it; + for(it=BI.begin(); it != BI.end(); ++it) + { + //MoveWindow(it->hWnd, it-> + if (!it->AbsPos) + SetWindowPos(it->hWnd, 0, it->xp-OffsetX, it->yp-OffsetY, 0,0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOCOPYBITS); + } + } + { + list::iterator it; + for(it=II.begin(); it != II.end(); ++it) + SetWindowPos(it->hWnd, 0, it->xp-OffsetX, it->yp-OffsetY, 0,0, SWP_NOSIZE|SWP_NOZORDER); + } + + { + list::iterator it; + for(it=LBI.begin(); it != LBI.end(); ++it) + SetWindowPos(it->hWnd, 0, it->xp-OffsetX, it->yp-OffsetY, 0,0, SWP_NOSIZE|SWP_NOZORDER); + + } +} + +void gdioutput::addInfoBox(string id, string text, int TimeOut, GUICALLBACK cb) +{ + InfoBox Box; + + Box.id=id; + Box.callBack=cb; + Box.text=lang.tl(text); + + if (TimeOut>0) + Box.TimeOut=GetTickCount()+TimeOut; + + IBox.push_back(Box); + refresh(); +} + +void gdioutput::drawBox(HDC hDC, InfoBox &Box, RECT &pos) +{ + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(hDC, TRANSPARENT); + + //Calculate size. + RECT testrect; + + memset(&testrect, 0, sizeof(RECT)); + DrawText(hDC, Box.text.c_str(), Box.text.length(), &testrect, DT_CALCRECT|DT_LEFT|DT_NOPREFIX|DT_SINGLELINE); + + if (testrect.right>250 || Box.text.find_first_of('\n')!=string::npos) + { + testrect.right=250; + DrawText(hDC, Box.text.c_str(), Box.text.length(), &testrect, DT_CALCRECT|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); + } + else if (testrect.right<80) + testrect.right=80; + + pos.left=pos.right-(testrect.right+22); + pos.top=pos.bottom-(testrect.bottom+20); + + DWORD c=GetSysColor(COLOR_INFOBK); + double red=GetRValue(c); + double green=GetGValue(c); + double blue=GetBValue(c); + + double blue1=min(255., blue*1.1); + double green1=min(255., green*1.1); + double red1=min(255., red*1.1); + + TRIVERTEX vert[2]; + vert [0] .x = pos.left; + vert [0] .y = pos.top; + vert [0] .Red = 0xff00&DWORD(red*256); + vert [0] .Green = 0xff00&DWORD(green*256); + vert [0] .Blue = 0xff00&DWORD(blue*256); + vert [0] .Alpha = 0x0000; + + vert [1] .x = pos.right; + vert [1] .y = pos.bottom; + vert [1] .Red = 0xff00&DWORD(red1*256); + vert [1] .Green = 0xff00&DWORD(green1*256); + vert [1] .Blue = 0xff00&DWORD(blue1*256); + vert [1] .Alpha = 0x0000; + + GRADIENT_RECT gr[1]; + + gr[0].UpperLeft=0; + gr[0].LowerRight=1; + + //if (MaxY>500) + GradientFill(hDC,vert, 2, gr, 1,GRADIENT_FILL_RECT_V); + + SelectObject(hDC, GetStockObject(NULL_BRUSH)); + SelectObject(hDC, GetStockObject(BLACK_PEN)); + Rectangle(hDC, pos.left, pos.top, pos.right, pos.bottom); + Box.BoundingBox=pos; + //Close Box + RECT Close; + Close.top=pos.top+3; + Close.bottom=Close.top+11; + Close.right=pos.right-3; + Close.left=Close.right-11; + + Box.Close=Close; + drawCloseBox(hDC, Close, false); + + RECT tr=pos; + + tr.left+=10; + tr.right-=10; + tr.top+=15; + tr.bottom-=5; + + drawBoxText(hDC, tr, Box, false); + + Box.TextRect=tr; + +} + +void gdioutput::drawBoxes(HDC hDC, RECT &rc) +{ + RECT pos; + pos.right=rc.right; + pos.bottom=rc.bottom; + + list::iterator it=IBox.begin(); + int maxNumBox = 10; + while(it!=IBox.end() && --maxNumBox > 0) { + drawBox(hDC, *it, pos); + pos.bottom=pos.top; + ++it; + } +} + +void gdioutput::drawCloseBox(HDC hDC, RECT &Close, bool pressed) +{ + if (!pressed) { + SelectObject(hDC, GetStockObject(WHITE_BRUSH)); + SelectObject(hDC, GetStockObject(BLACK_PEN)); + } + else { + SelectObject(hDC, GetStockObject(LTGRAY_BRUSH)); + SelectObject(hDC, GetStockObject(BLACK_PEN)); + } + //Close Box + Rectangle(hDC, Close.left, Close.top, Close.right, Close.bottom); + + MoveToEx(hDC, Close.left+2, Close.top+2, 0); + LineTo(hDC, Close.right-2, Close.bottom-2); + + MoveToEx(hDC, Close.right-2, Close.top+2, 0); + LineTo(hDC, Close.left+2, Close.bottom-2); +} + +void gdioutput::drawBoxText(HDC hDC, RECT &tr, InfoBox &Box, bool highligh) +{ + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(hDC, TRANSPARENT); + + if (highligh) { + SetTextColor(hDC, 0x005050FF); + } + else { + SetTextColor(hDC, GetSysColor(COLOR_INFOTEXT)); + } + + DrawText(hDC, Box.text.c_str(), Box.text.length(), &tr, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); +} + +bool gdioutput::RemoveFirstInfoBox(const string &id) +{ + list::iterator it=IBox.begin(); + + while(it!=IBox.end()) { + if (it->id==id) { + IBox.erase(it); + return true; + } + ++it; + } + return false; +} + + +string gdioutput::getTimerText(int zeroTime, int format) +{ + TextInfo temp; + temp.zeroTime=0; + //memset(&temp, 0, sizeof(TextInfo)); + temp.format=format; + return getTimerText(&temp, 1000*zeroTime); +} + +string gdioutput::getTimerText(TextInfo *tit, DWORD T) +{ + int rt=(int(T)-int(tit->zeroTime))/1000; + int tenth = (abs(int(T)-int(tit->zeroTime))/100)%10; + string text; + + int t=abs(rt); + char bf[16]; + + if (tit->format & timeSeconds) { + if (tit->format & timeWithTenth) + sprintf_s(bf, 16, "%d.%d", t, tenth); + else + sprintf_s(bf, 16, "%d", t); + } + else if ((tit->format & timeWithTenth) && rt < 3600) { + sprintf_s(bf, 16, "%02d:%02d.%d", t/60, t%60, tenth); + } + else if (rt>=3600 || (tit->format&fullTimeHMS)) + sprintf_s(bf, 16, "%02d:%02d:%02d", t/3600, (t/60)%60, t%60); + else + sprintf_s(bf, 16, "%d:%02d", (t/60), t%60); + + if (rt>0 || ((tit->format&fullTimeHMS) && rt>=0) ) + if (tit->format&timerCanBeNegative) + text = string("+") + bf; + else + text = bf; + else if (rt<0) + if (tit->format&timerCanBeNegative) + text = string("-")+bf; + else if (tit->format&timerIgnoreSign) + text = bf; + else + text="-"; + + return text; +} + +void gdioutput::CheckInterfaceTimeouts(DWORD T) +{ + list::iterator it=IBox.begin(); + + while (it!=IBox.end()) { + if (it->TimeOut && it->TimeOutHasCapture || it->HasTCapture) + ReleaseCapture(); + + InvalidateRect(hWndTarget, &(it->BoundingBox), true); + IBox.erase(it); + it=IBox.begin(); + } + else ++it; + } + + list::iterator tit = TL.begin(); + vector timeout; + if (hasAnyTimer) { + bool anyChange = false; + while(tit!=TL.end()){ + if (tit->hasTimer){ + string text = tit->xp > 0 ? getTimerText(&*tit, T) : ""; + if (tit->timeOut && T>DWORD(tit->timeOut)){ + tit->timeOut=0; + if (tit->callBack || tit->hasEventHandler()) + timeout.push_back(*tit); + } + if (text != tit->text) { + RECT rc=tit->textRect; + tit->text=text; + calcStringSize(*tit); + + rc.right=max(tit->textRect.right, rc.right); + rc.bottom=max(tit->textRect.bottom, rc.bottom); + + anyChange = true; + //InvalidateRecthWndTarget, &rc, true); + } + } + ++tit; + } + + if (anyChange) { + int w, h; + getTargetDimension(w, h); + HDC hDC = GetDC(hWndTarget); + HBITMAP btm = CreateCompatibleBitmap(hDC, w, h); + HDC memDC = CreateCompatibleDC (hDC); + HGDIOBJ hOld = SelectObject(memDC, btm); + RECT rc; + rc.top = 0; + rc.left = 0; + rc.bottom = h; + rc.right = w; + RECT area = rc; + drawBackground(memDC, rc); + draw(memDC, rc, area); + BitBlt(hDC, 0, 0, w, h, memDC, 0,0, SRCCOPY); + SelectObject(memDC, hOld); + DeleteObject(btm); + DeleteDC(memDC); + ReleaseDC(hWndTarget, hDC); + } + } + + for (size_t k = 0; k < timeout.size(); k++) { + if (!timeout[k].handleEvent(*this, GUI_TIMEOUT)) + timeout[k].callBack(this, GUI_TIMEOUT, &timeout[k]); + } +} + +bool gdioutput::removeControl(const string &id) +{ + list::iterator it=BI.begin(); + + while (it!=BI.end()) { + if (it->id==id) { + DestroyWindow(it->hWnd); + biByHwnd.erase(it->hWnd); + BI.erase(it); + return true; + } + ++it; + } + + list::iterator lit=LBI.begin(); + + while (lit!=LBI.end()) { + if (lit->id==id) { + DestroyWindow(lit->hWnd); + lbiByHwnd.erase(lit->hWnd); + if (lit->writeLock) + hasCleared = true; + LBI.erase(lit); + return true; + } + ++lit; + } + + list::iterator iit=II.begin(); + + while (iit!=II.end()) { + if (iit->id==id) { + DestroyWindow(iit->hWnd); + iiByHwnd.erase(iit->hWnd); + II.erase(iit); + return true; + } + ++iit; + } + return false; +} + +bool gdioutput::hideControl(const string &id) +{ + list::iterator it=BI.begin(); + + while (it!=BI.end()) { + if (it->id==id) { + ShowWindow(it->hWnd, SW_HIDE); + return true; + } + ++it; + } + + list::iterator lit=LBI.begin(); + + while (lit!=LBI.end()) { + if (lit->id==id) { + ShowWindow(lit->hWnd, SW_HIDE); + return true; + } + ++lit; + } + + list::iterator iit=II.begin(); + + while (iit!=II.end()) { + if (iit->id==id) { + ShowWindow(iit->hWnd, SW_HIDE); + return true; + } + ++iit; + } + return false; +} + + +void gdioutput::setRestorePoint() +{ + setRestorePoint(""); +} + + +void gdioutput::setRestorePoint(const string &id) +{ + RestoreInfo ri; + + ri.id = id; + + ri.nLBI = LBI.size(); + ri.nBI = BI.size(); + ri.nII = II.size(); + ri.nTL = TL.size(); + ri.nRect = Rectangles.size(); + ri.nTooltip = toolTips.size(); + ri.nTables = Tables.size(); + ri.nHWND = FocusList.size(); + ri.nData = DataInfo.size(); + + ri.sCX=CurrentX; + ri.sCY=CurrentY; + ri.sMX=MaxX; + ri.sMY=MaxY; + ri.sOX=OffsetX; + ri.sOY=OffsetY; + + ri.onClear = onClear; + ri.postClear = postClear; + restorePoints[id]=ri; +} + +void gdioutput::restoreInternal(const RestoreInfo &ri) +{ + int toolRemove=toolTips.size()-ri.nTooltip; + while (toolRemove>0 && toolTips.size()>0) { + ToolInfo &info=toolTips.back(); + if (hWndToolTip) { + SendMessage(hWndToolTip, TTM_DELTOOL, 0, (LPARAM) &info.ti); + } + toolTips.pop_back(); + toolRemove--; + } + + int lbiRemove=LBI.size()-ri.nLBI; + while (lbiRemove>0 && LBI.size()>0) { + ListBoxInfo &lbi=LBI.back(); + lbi.callBack = 0; // Avoid kill focus event here + lbi.setHandler(0); + + DestroyWindow(lbi.hWnd); + if (lbi.writeLock) + hasCleared = true; + lbiByHwnd.erase(lbi.hWnd); + LBI.pop_back(); + lbiRemove--; + } + int tlRemove=TL.size()-ri.nTL; + + while (tlRemove>0 && TL.size()>0) { + TL.pop_back(); + tlRemove--; + } + itTL=TL.begin(); + // Clear cache of shown strings + shownStrings.clear(); + + int biRemove=BI.size()-ri.nBI; + while (biRemove>0 && BI.size()>0) { + ButtonInfo &bi=BI.back(); + + DestroyWindow(bi.hWnd); + biByHwnd.erase(bi.hWnd); + BI.pop_back(); + biRemove--; + } + + int iiRemove=II.size()-ri.nII; + + while (iiRemove>0 && II.size()>0) { + InputInfo &ii=II.back(); + ii.callBack = 0; // Avoid kill focus event here + ii.setHandler(0); + DestroyWindow(ii.hWnd); + iiByHwnd.erase(ii.hWnd); + II.pop_back(); + iiRemove--; + } + + int rectRemove=Rectangles.size()-ri.nRect; + + while (rectRemove>0 && Rectangles.size()>0) { + Rectangles.pop_back(); + rectRemove--; + } + + int hwndRemove=FocusList.size()-ri.nHWND; + while(hwndRemove>0 && FocusList.size()>0) { + FocusList.pop_back(); + hwndRemove--; + } + + while(Tables.size() > unsigned(ri.nTables)){ + Table *t=Tables.back().table; + Tables.back().table=0; + Tables.pop_back(); + t->hide(*this); + t->releaseOwnership(); + } + + int dataRemove=DataInfo.size()-ri.nData; + while(dataRemove>0 && DataInfo.size()>0) { + DataInfo.pop_front(); + dataRemove--; + } + + CurrentX=ri.sCX; + CurrentY=ri.sCY; + onClear = ri.onClear; + postClear = ri.postClear; +} + +void gdioutput::restore(const string &id, bool DoRefresh) +{ + if (restorePoints.count(id)==0) + return; + + const RestoreInfo &ri=restorePoints[id]; + + restoreInternal(ri); + + MaxX=ri.sMX; + MaxY=ri.sMY; + + if (DoRefresh) + refresh(); + + setOffset(ri.sOY, ri.sOY, false); +} + +void gdioutput::restoreNoUpdate(const string &id) +{ + if (restorePoints.count(id)==0) + return; + + const RestoreInfo &ri=restorePoints[id]; + + MaxX=ri.sMX; + MaxY=ri.sMY; + + restoreInternal(ri); +} + +void gdioutput::setPostClearCb(GUICALLBACK cb) +{ + postClear=cb; +} + + +void gdioutput::setOnClearCb(GUICALLBACK cb) +{ + onClear=cb; +} + +bool gdioutput::canClear() +{ + if (!onClear) + return true; + + try { + return onClear(this, GUI_CLEAR, 0)!=0; + } + catch(const std::exception &ex) { + if (isTestMode) + throw ex; + string msg(ex.what()); + alert(msg); + return true; + } +} + +int gdioutput::sendCtrlMessage(const string &id) +{ + for (list::iterator it=BI.begin(); it != BI.end(); ++it) { + if (id==it->id) { + if (it->handler) + return it->handleEvent(*this, GUI_BUTTON); + else if (it->callBack) + return it->callBack(this, GUI_BUTTON, &*it); //it may be destroyed here... + } + } + for(list::iterator it=Events.begin(); it != Events.end(); ++it){ + if (id==it->id) { + if (it->hasEventHandler()) + return it->handleEvent(*this, GUI_EVENT); + else if (it->callBack) + return it->callBack(this, GUI_EVENT, &*it); //it may be destroyed here... + } + } +#ifdef _DEBUG + throw meosException("Unknown command " +id); +#endif + return 0; +} + +void gdioutput::unregisterEvent(const string &id) +{ + list::iterator it; + for (it = Events.begin(); it != Events.end(); ++it) { + if ( id == it->id) { + Events.erase(it); + return; + } + } +} + +EventInfo &gdioutput::registerEvent(const string &id, GUICALLBACK cb) +{ + list::iterator it; + for (it = Events.begin(); it != Events.end(); ++it) { + if ( id == it->id) { + Events.erase(it); + break; + } + } + + EventInfo ei; + ei.id=id; + ei.callBack=cb; + + Events.push_front(ei); + return Events.front(); +} + +void flushEvent(const string &id, const string &origin, DWORD data, int extraData); + +DWORD gdioutput::makeEvent(const string &id, const string &origin, + DWORD data, int extraData, bool doflush) +{ + if (doflush) { +#ifndef MEOSDB + ::flushEvent(id, origin, data, extraData); +#else + throw std::exception("internal gdi/database error"); +#endif + } + else { + list::iterator it; + + for(it=Events.begin(); it != Events.end(); ++it){ + if (id==it->id && (it->callBack || it->hasEventHandler()) ) { + it->setData(origin, data); + if (extraData) { + it->setExtra(extraData); + } + if (it->handleEvent(*this, GUI_EVENT)) { + return 1; + } + else + return it->callBack(this, GUI_EVENT, &*it); //it may be destroyed here... + } + } + } + return -1; +} + + +RectangleInfo &RectangleInfo::changeDimension(gdioutput &gdi, int dx, int dy) { + rc.right += dx; + rc.bottom += dy; + int ex = gdi.scaleLength(5); + gdi.updatePos(rc.left, rc.top, rc.right-rc.left+ex, rc.bottom-rc.top+ex); + return *this; +} + +RectangleInfo &gdioutput::addRectangle(RECT &rc, GDICOLOR color, bool drawBorder, bool addFirst) { + RectangleInfo ri; + + ri.rc = rc; + if (color==colorDefault) + ri.color = GetSysColor(COLOR_INFOBK); + else if (color == colorWindowBar) { + ri.color = GetSysColor(COLOR_3DFACE); + } + else ri.color = color; + + ri.color2 = ri.color; + ri.drawBorder = drawBorder; + + if (hWndTarget && !manualUpdate) { + HDC hDC=GetDC(hWndTarget); + renderRectangle(hDC, 0, ri); + ReleaseDC(hWndTarget, hDC); + } + + int ex = scaleLength(5); + updatePos(rc.left, rc.top, rc.right-rc.left+ex, rc.bottom-rc.top+ex); + if (addFirst) { + Rectangles.push_front(ri); + return Rectangles.front(); + } + else { + Rectangles.push_back(ri); + return Rectangles.back(); + } +} + +RectangleInfo &gdioutput::getRectangle(const char *id) { + for (list::iterator it = Rectangles.begin(); it != Rectangles.end(); ++it) { + return *it; + } + string err = string("Internal Error, identifier not found: X#") + id; + throw std::exception(err.c_str()); +} + +void gdioutput::setOffset(int x, int y, bool update) +{ + int h,w; + getTargetDimension(w, h); + + int cdy = 0; + int cdx = 0; + + if (y!=OffsetY) { + int oldY = OffsetY; + OffsetY = y; + if (OffsetY < 0) + OffsetY = 0; + else if (OffsetY > MaxY) + OffsetY = MaxY; + //cdy=(oldY!=OffsetY); + cdy = oldY - OffsetY; + } + + if (x!=OffsetX) { + int oldX = OffsetX; + OffsetX = x; + if (OffsetX < 0) + OffsetX = 0; + else if (OffsetX > MaxX) + OffsetX = MaxX; + + //cdx=(oldX!=OffsetX); + cdx = oldX - OffsetX; + } + + if (cdx || cdy) { + updateScrollbars(); + updateObjectPositions(); + if (cdy) { + SCROLLINFO si; + memset(&si, 0, sizeof(si)); + + si.nPos=OffsetY; + si.fMask=SIF_POS; + SetScrollInfo(hWndTarget, SB_VERT, &si, true); + } + + if (cdx) { + SCROLLINFO si; + memset(&si, 0, sizeof(si)); + + si.nPos=OffsetX; + si.fMask=SIF_POS; + SetScrollInfo(hWndTarget, SB_HORZ, &si, true); + } + + if (update) { + //RECT ScrollArea, ClipArea; + //GetClientRect(hWndTarget, &ScrollArea); + //ClipArea = ScrollArea; + + /* ScrollArea.top=-gdi->getHeight()-100; + ScrollArea.bottom+=gdi->getHeight(); + ScrollArea.right=gdi->getWidth()-gdi->GetOffsetX()+15; + ScrollArea.left = -2000; + */ + ScrollWindowEx(hWndTarget, -cdx, cdy, + NULL, NULL, + (HRGN) NULL, (LPRECT) NULL, 0/*SW_INVALIDATE|SW_SMOOTHSCROLL|(1000*65536 )*/); + UpdateWindow(hWndTarget); + + } + } +} + +void gdioutput::scrollTo(int x, int y) +{ + int cx=x-OffsetX; + int cy=y-OffsetY; + + int h,w; + getTargetDimension(w, h); + + bool cdy=false; + bool cdx=false; + + if (cy<=(h/15) || cy>=(h-h/10)) { + int oldY=OffsetY; + OffsetY=y-h/2; + if (OffsetY<0) + OffsetY=0; + else if (OffsetY>MaxY) + OffsetY=MaxY; + + cdy=(oldY!=OffsetY); + } + + if (cx<=(w/15) || cx>=(w-w/8)) { + int oldX=OffsetX; + OffsetX=x-w/2; + if (OffsetX<0) + OffsetX=0; + else if (OffsetX>MaxX) + OffsetX=MaxX; + + cdx=(oldX!=OffsetX); + } + + if (cdx || cdy) { + updateScrollbars(); + updateObjectPositions(); + if (cdy) { + SCROLLINFO si; + memset(&si, 0, sizeof(si)); + + si.nPos=OffsetY; + si.fMask=SIF_POS; + SetScrollInfo(hWndTarget, SB_VERT, &si, true); + } + + if (cdx) { + SCROLLINFO si; + memset(&si, 0, sizeof(si)); + + si.nPos=OffsetX; + si.fMask=SIF_POS; + SetScrollInfo(hWndTarget, SB_HORZ, &si, true); + } + } +} + +void gdioutput::scrollToBottom() +{ + OffsetY=MaxY; + SCROLLINFO si; + memset(&si, 0, sizeof(si)); + + updateScrollbars(); + updateObjectPositions(); + si.nPos=OffsetY; + si.fMask=SIF_POS; + SetScrollInfo(hWndTarget, SB_VERT, &si, true); +} + +bool gdioutput::clipOffset(int PageX, int PageY, int &MaxOffsetX, int &MaxOffsetY) +{ + if (highContrast) + setHighContrastMaxWidth(); + + int oy=OffsetY; + int ox=OffsetX; + + MaxOffsetY=max(GetPageY()-PageY, 0); + MaxOffsetX=max(GetPageX()-PageX, 0); + + if (OffsetY<0) OffsetY=0; + else if (OffsetY>MaxOffsetY) + OffsetY=MaxOffsetY; + + if (OffsetX<0) OffsetX=0; + else if (OffsetX>MaxOffsetX) + OffsetX=MaxOffsetX; + + if (ox!=OffsetX || oy!=OffsetY){ + updateObjectPositions(); + return true; + + } + return false; +} + +//bool ::GetSaveFile(string &file, char *filter) +string gdioutput::browseForSave(const vector< pair > &filter, + const string &defext, int &filterIndex) +{ + if (isTestMode) { + if (!cmdAnswers.empty()) { + string ans = cmdAnswers.front(); + cmdAnswers.pop_front(); + if (ans.substr(0, 1) == "*") + return ans.substr(1); + } + throw meosException("Browse for file"); + } + + InitCommonControls(); + + char FileName[260]; + FileName[0]=0; + char sbuff[256]; + memset(sbuff,0, 256); + OPENFILENAME of; + string sFilter; + for (size_t k = 0; k< filter.size(); k++) + sFilter += (lang.tl(filter[k].first) + "¤" + filter[k].second + "¤"); + + sprintf_s(sbuff, 256, "%s", sFilter.c_str()); + + int sl=strlen(sbuff); + for(int m=0;m > &filter, + const string &defext) +{ + if (isTestMode) { + if (!cmdAnswers.empty()) { + string ans = cmdAnswers.front(); + cmdAnswers.pop_front(); + if (ans.substr(0, 1) == "*") + return ans.substr(1); + } + throw meosException("Browse for file"); + } + + InitCommonControls(); + + char FileName[260]; + FileName[0]=0; + char sbuff[256]; + memset(sbuff,0, 256); + OPENFILENAME of; + + string sFilter; + for (size_t k = 0; k< filter.size(); k++) + sFilter += (lang.tl(filter[k].first) + "¤" + filter[k].second + "¤"); + + sprintf_s(sbuff, 256, "%s", sFilter.c_str()); + + int sl=strlen(sbuff); + for(int m=0;mFree(pidl_new); + + // Free our task allocator + pMalloc->Release(); + + return InstPath; +} + + +bool gdioutput::openDoc(const char *doc) +{ + return (int)ShellExecute(hWndTarget, "open", doc, NULL, "", SW_SHOWNORMAL ) >32; +} + +void gdioutput::init(HWND hWnd, HWND hMain, HWND hTab) +{ + setWindow(hWnd); + hWndAppMain=hMain; + hWndTab=hTab; + + InitCommonControls(); + + hWndToolTip = CreateWindow(TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, (HMENU) NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); +} + +ToolInfo &gdioutput::addToolTip(const string &tipId, const string &tip, HWND hWnd, RECT *rc) { + static ToolInfo dummy; + if (!hWndToolTip) + return dummy; + + toolTips.push_back(ToolInfo()); + ToolInfo &info = toolTips.back(); + TOOLINFOW &ti = info.ti; + info.tip = toWide(lang.tl(tip)); + + memset(&ti, 0, sizeof(ti)); + ti.cbSize = sizeof(TOOLINFO); + + if (hWnd != 0) { + ti.uFlags = TTF_IDISHWND; + info.id = int(hWnd); + ti.uId = (UINT) hWnd; + } + else { + ti.uFlags = TTF_SUBCLASS; + info.id = toolTips.size(); + ti.uId = info.id; + } + + ti.hwnd = hWndTarget; + ti.hinst = (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE); + info.name = tipId; + ti.lpszText = (LPWSTR)toolTips.back().tip.c_str(); + + if (rc != 0) + ti.rect = *rc; + + SendMessage(hWndToolTip, TTM_ADDTOOLW, 0, (LPARAM) &ti); + + if (tip.find('\n') != string::npos || tip.length()>40) + SendMessage(hWndToolTip, TTM_SETMAXTIPWIDTH, 0, 250); + + return info; +} + +ToolInfo *gdioutput::getToolTip(const string &id) { + for (ToolList::reverse_iterator it = toolTips.rbegin(); it != toolTips.rend(); ++it) { + if (it->name == id) + return &*it; + } + return 0; +} + +ToolInfo &gdioutput::updateToolTip(const string &id, const string &tip) { + for (ToolList::reverse_iterator it = toolTips.rbegin(); it != toolTips.rend(); ++it) { + if (it->name == id && hWndToolTip) { + it->tip = toWide(lang.tl(tip)); + SendMessage(hWndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM) &it->ti); + return *it; + } + } + BaseInfo &bi = getBaseInfo(id.c_str()); + return addToolTip(id, tip, bi.getControlWindow()); +} + +void gdioutput::selectTab(int Id) +{ + if (hWndTab) + TabCtrl_SetCurSel(hWndTab, Id); +} + +void gdioutput::getTargetDimension(int &x, int &y) const +{ + if (hWndTarget){ + RECT rc; + GetClientRect(hWndTarget, &rc); + x=rc.right; + y=rc.bottom; + } + else { + x=0; + y=0; + } +} + +Table &gdioutput::getTable() const { + if (Tables.empty()) + throw std::exception("No table defined"); + + return *const_cast(Tables.back().table); +} + +static int gdiTableCB(gdioutput *gdi, int type, void *data) +{ + if (type == GUI_BUTTON) { + ButtonInfo bi = *static_cast(data); + //gdi->tableCB(bi, static_cast
(bi.getExtra())); + gdi->tableCB(bi, &gdi->getTable()); + } + return 0; +} + +void gdioutput::tableCB(ButtonInfo &bu, Table *t) +{ + #ifndef MEOSDB + + if (bu.id=="tblPrint") { + t->keyCommand(*this, KC_PRINT); + } + else if (bu.id=="tblColumns") { + disableTables(); + if (Tables.empty()) + return; + + restore("tblRestore"); + int ybase = Tables.back().yp; + addString("", ybase, 20, boldLarge, "Välj kolumner"); + ybase += scaleLength(30); + addString("", ybase, 20, 0, "Välj kolumner för tabellen X.#"+ t->getTableName()); + ybase += getLineHeight()*2; + + addListBox(20, ybase, "tblColSel", 180, 450, 0, "", "", true); + const int btnHeight = getButtonHeight()+scaleLength(5); + vector cols = t->getColumns(); + set sel; + + for (size_t k=0; kgetTableId()); + + addButton(xp, ybase+btnHeight*4, "tblOK", "OK", gdiTableCB).setExtra(t->getTableId()); + addButton(xp, ybase+btnHeight*5, "tblCancel", "Avbryt", gdiTableCB); + + if (toolbar) + toolbar->hide(); + + refresh(); + } + else if (bu.id=="tblAll") { + set sel; + sel.insert(-1); + setSelection("tblColSel", sel); + } + else if (bu.id=="tblNone") { + set sel; + setSelection("tblColSel", sel); + } + else if (bu.id=="tblAuto") { + restore("tblRestore", false); + t->autoSelectColumns(); + t->autoAdjust(*this); + enableTables(); + refresh(); + } + else if (bu.id=="tblOK") { + set sel; + getSelection("tblColSel", sel); + restore("tblRestore", false); + t->clearCellSelection(this); + t->selectColumns(sel); + t->autoAdjust(*this); + enableTables(); + refresh(); + } + else if (bu.id=="tblReset") { + t->clearCellSelection(this); + t->resetColumns(); + t->autoAdjust(*this); + t->updateDimension(*this); + refresh(); + } + else if (bu.id=="tblUpdate") { + t->keyCommand(*this, KC_REFRESH); + } + else if (bu.id=="tblCancel") { + restore("tblRestore", true); + enableTables(); + refresh(); + } + else if (bu.id == "tblCopy") { + t->keyCommand(*this, KC_COPY); + } + else if (bu.id == "tblPaste") { + t->keyCommand(*this, KC_PASTE); + } + else if (bu.id == "tblRemove") { + t->keyCommand(*this, KC_DELETE); + } + else if (bu.id == "tblInsert") { + t->keyCommand(*this, KC_INSERT); + } + + #endif +} + +void gdioutput::enableTables() +{ + useTables=true; +#ifndef MEOSDB + if (!Tables.empty()) { + Table *t = Tables.front().table; + if (toolbar == 0) + toolbar = new Toolbar(*this); +/* RECT rc; + rc.top = 10; + rc.bottom = 100; + rc.left = 100; + rc.right = 200; + addToolTip("Hej hopp!", 0, &rc); +*/ + toolbar->setData(t); + + string tname = string("table") + itos(t->canDelete()) + itos(t->canInsert()) + itos(t->canPaste()); + if (!toolbar->isLoaded(tname)) { + toolbar->reset(); + toolbar->addButton("tblColumns", 1, 2, "Välj vilka kolumner du vill visa"); + toolbar->addButton("tblPrint", 0, STD_PRINT, "Skriv ut tabellen (X)#Ctrl+P"); + toolbar->addButton("tblUpdate", 1, 0, "Uppdatera alla värden i tabellen (X)#F5"); + toolbar->addButton("tblReset", 1, 4, "Återställ tabeldesignen och visa allt"); + toolbar->addButton("tblCopy", 0, STD_COPY, "Kopiera selektionen till urklipp (X)#Ctrl+C"); + if (t->canPaste()) + toolbar->addButton("tblPaste", 0, STD_PASTE, "Klistra in data från urklipp (X)#Ctrl+V"); + if (t->canDelete()) + toolbar->addButton("tblRemove", 1, 1, "Ta bort valda rader från tabellen (X)#Del"); + if (t->canInsert()) + toolbar->addButton("tblInsert", 1, 3, "Lägg till en ny rad i tabellen (X)#Ctrl+I"); + toolbar->createToolbar(tname, "Tabellverktyg"); + } + else { + toolbar->show(); + } + } +#endif +} + +void gdioutput::processToolbarMessage(const string &id, void *data) { + if (hasCommandLock()) + return; + string msg; + string cmd; + if (getRecorder().recording()) { + Table *tbl = (Table *)data; + cmd = "tableCmd(\"" + id + "\"); //" + tbl->getTableName(); + } + try { + ButtonInfo bi; + bi.id = id; + tableCB(bi, (Table *)data); + getRecorder().record(cmd); + } + catch(std::exception &ex) { + msg = ex.what(); + if (msg.empty()) + msg="Ett okänt fel inträffade."; + } + catch(...) { + msg = "Ett okänt fel inträffade."; + } + + if (!msg.empty()) + alert(msg); +} + +#ifndef MEOSDB + +HWND gdioutput::getToolbarWindow() const { + if (!toolbar) + return 0; + return toolbar->getFloater(); +} + +bool gdioutput::hasToolbar() const { + if (!toolbar) + return false; + return toolbar->isVisible(); +} + +void gdioutput::activateToolbar(bool active) { + if (!toolbar) + return; + toolbar->activate(active); +} +#else + HWND gdioutput::getToolbarWindow() const { + return 0; + } + + bool gdioutput::hasToolbar() const { + return false; + } +#endif + + + +void gdioutput::disableTables() +{ + useTables=false; + + for(list::iterator bit=BI.begin(); bit != BI.end();) { + if (bit->id.substr(0, 3)=="tbl" && bit->getExtra()!=0) { + string id = bit->id; + ++bit; + removeControl(id); + } + else + ++bit; + } + +} + +void gdioutput::addTable(Table *t, int x, int y) +{ + TableInfo ti; + ti.table = t; + ti.xp = x; + ti.yp = y; + t->setPosition(x,y, MaxX, MaxY); + + if (t->hasAutoSelect()) + t->autoSelectColumns(); + t->autoAdjust(*this); + + ti.table->addOwnership(); + Tables.push_back(ti); + + //updatePos(x, y, dx + TableXMargin, dy + TableYMargin); + setRestorePoint("tblRestore"); + + enableTables(); + updateScrollbars(); +} + +void gdioutput::pasteText(const char *id) +{ + list::iterator it; + for (it=II.begin(); it != II.end(); ++it) { + if (it->id==id) { + SendMessage(it->hWnd, WM_PASTE, 0,0); + return; + } + } +} + +char *gdioutput::getExtra(const char *id) const { + return getBaseInfo(id).getExtra(); +} + +int gdioutput::getExtraInt(const char *id) const { + return getBaseInfo(id).getExtraInt(); +} + +bool gdioutput::hasEditControl() const +{ + return !II.empty() || (Tables.size()>0 && Tables.front().table->hasEditControl()); +} + +void gdioutput::enableEditControls(bool enable) +{ + set TCheckControls; + for (list::iterator it=BI.begin(); it != BI.end(); ++it) { + if (it->isEditControl) { + EnableWindow(it->hWnd, enable); + if (it->isCheckbox) { + TCheckControls.insert("T" + it->id); + } + } + } + + for (list::iterator it=TL.begin(); it != TL.end(); ++it) { + if (TCheckControls.count(it->id)) { + enableCheckBoxLink(*it, enable); + } + } + + + for (list::iterator it=II.begin(); it != II.end(); ++it) { + if (it->isEditControl) + EnableWindow(it->hWnd, enable); + } + + for( list::iterator it=LBI.begin(); it != LBI.end(); ++it) { + if (it->isEditControl) + EnableWindow(it->hWnd, enable); + } +} + +void gdioutput::closeWindow() +{ + PostMessage(hWndTarget, WM_CLOSE, 0, 0); +} + +InputInfo &InputInfo::setPassword(bool pwd) { + LONG style = GetWindowLong(hWnd, GWL_STYLE); + if (pwd) + style |= ES_PASSWORD; + else + style &= ~ES_PASSWORD; + SetWindowLong(hWnd, GWL_STYLE, style); + SendMessage(hWnd, EM_SETPASSWORDCHAR, 183, 0); + return *this; +} + +int gdioutput::setHighContrastMaxWidth() { + + RECT rc; + GetClientRect(hWndTarget, &rc); + + if (lockRefresh) + return rc.bottom; + +#ifdef DEBUGRENDER + OutputDebugString("Set high contrast\n"); +#endif + + double w = GetPageX(); + double s = rc.right / w; + if (!highContrast || (fabs(s-1.0) > 1e-3 && (s * scale) >= 1.0) ) { + lockRefresh = true; + try { + highContrast = true; + scaleSize(s); + refresh(); + lockRefresh = false; + } + catch (...) { + lockRefresh = false; + throw; + } + } + return rc.bottom; +} + +double static acc = 0; + +void gdioutput::setAutoScroll(double speed) { + if (autoSpeed == 0 && speed != 0) { + SetTimer(hWndTarget, 1001, 20, 0); + autoPos = OffsetY; + } + else if (speed == 0 && autoSpeed != 0) { + KillTimer(hWndTarget, 1001); + } + + if (speed == -1) + autoSpeed = -autoSpeed; + else + autoSpeed = speed; + + autoCounter = - M_PI_2; + acc = 0; +} + +void gdioutput::getAutoScroll(double &speed, double &pos) const { + RECT rc; + GetClientRect(hWndTarget, &rc); + double height = rc.bottom; + + double s = autoSpeed * (1 + height/1000 + sin(autoCounter)/max(1.0, 500/height)); + + autoCounter += M_PI/75.0; + if (autoCounter > M_PI) + autoCounter -= 2*M_PI; + + acc += 0.3/30; + if (acc>0.8) + acc = 0.8; + + speed = (lastSpeed * (1.0-acc) + s * acc); + lastSpeed = speed; + pos = autoPos; +} + +void gdioutput::storeAutoPos(double pos) { + autoPos = pos; +} + +void gdioutput::setFullScreen(bool useFullScreen) { + SetWindowLong(hWndTarget, GWL_STYLE, WS_POPUP|WS_BORDER); + ShowWindow(hWndTarget, SW_MAXIMIZE); + UpdateWindow(hWndTarget); + fullScreen = true; +} + +bool gdioutput::hasCommandLock() const { + if (commandLock) + return true; + + if (commandUnlockTime > 0) { + DWORD t = GetTickCount(); + if (commandUnlockTime < (commandUnlockTime + 500) && + t < (commandUnlockTime+500)) { + commandUnlockTime = 0; + return true; + } + } + + return false; +} + +void gdioutput::setCommandLock() const { + commandLock = true; +} + +void gdioutput::liftCommandLock() const { + commandUnlockTime = GetTickCount(); + commandLock = false; +} + +int gdioutput::getLineHeight(gdiFonts font, const char *face) const { + TextInfo ti; + ti.xp = 0; + ti.yp = 0; + ti.format = font; + ti.text = "&abc_M|!I"; + if (face) + ti.font = face; + calcStringSize(ti); + return (11*(ti.textRect.bottom - ti.textRect.top))/10; +} + +GDIImplFontSet::GDIImplFontSet() : charSet(-1) { + Huge = 0; + Large = 0; + Medium = 0; + Small = 0; + pfLarge = 0; + pfMedium = 0; + pfMediumPlus = 0; + pfSmall = 0; + pfSmallItalic = 0; + pfItalic = 0; + pfItalicMediumPlus = 0; + pfMono = 0; +} + +GDIImplFontSet::~GDIImplFontSet() { + deleteFonts(); +} + +void GDIImplFontSet::deleteFonts() +{ + if (Huge) + DeleteObject(Huge); + Huge = 0; + + if (Large) + DeleteObject(Large); + Large = 0; + + if (Medium) + DeleteObject(Medium); + Medium = 0; + + if (Small) + DeleteObject(Small); + Small = 0; + + if (pfLarge) + DeleteObject(pfLarge); + pfLarge = 0; + + if (pfMedium) + DeleteObject(pfMedium); + pfMedium = 0; + + if (pfMediumPlus) + DeleteObject(pfMediumPlus); + pfMediumPlus = 0; + + if (pfSmall) + DeleteObject(pfSmall); + pfSmall = 0; + + if (pfMono) + DeleteObject(pfMono); + pfMono = 0; + + + if (pfSmallItalic) + DeleteObject(pfSmallItalic); + pfSmallItalic = 0; + + if (pfItalicMediumPlus) + DeleteObject(pfItalicMediumPlus); + pfItalicMediumPlus = 0; + + if (pfItalic) + DeleteObject(pfItalic); + pfItalic = 0; +} + +float GDIImplFontSet::baseSize(int format, float scale) { + format &= 0xFF; + if (format==0 || format==10) { + return 14 * scale; + } + else if (format==fontMedium){ + return 14 * scale; + } + else if (format==1) { + return 14.0001f * scale; //Bold + } + else if (format==boldLarge){ + return 24.0001f * scale; + } + else if (format==boldHuge){ + return 34.0001f * scale; + } + else if (format==boldSmall){ + return 11.0001f * scale; + } + else if (format==fontLarge){ + return 24 * scale; + } + else if (format==fontMediumPlus){ + return 18 * scale; + } + else if (format==fontSmall){ + return 11 * scale; + } + else if (format==italicSmall){ + return 11 * scale; + } + else if (format==italicText){ + return 14 * scale; + } + else if (format == monoText){ + return 14 * scale; + } + else if (format==italicMediumPlus){ + return 18 * scale; + } + else { + return 10 * scale; + } +} + +int gdioutput::getCharSet() const { + if (fontEncoding == Russian) + return RUSSIAN_CHARSET; + else if (fontEncoding == EastEurope) + return EASTEUROPE_CHARSET; + else + return ANSI_CHARSET; +} + +void GDIImplFontSet::init(double scale, int charSet_, const string &font, const string &gdiName_) +{ + charSet = charSet_; + deleteFonts(); + gdiName = gdiName_; + + Huge=CreateFont(int(scale*34), 0, 0, 0, FW_BOLD, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + Large=CreateFont(int(scale*24), 0, 0, 0, FW_BOLD, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + Medium=CreateFont(int(scale*14), 0, 0, 0, FW_BOLD, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + Small=CreateFont(int(scale*11), 0, 0, 0, FW_BOLD, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfLarge=CreateFont(int(scale*24), 0, 0, 0, FW_NORMAL, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfMedium=CreateFont(int(scale*14), 0, 0, 0, FW_NORMAL, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfMediumPlus=CreateFont(int(scale*18), 0, 0, 0, FW_NORMAL, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfSmall=CreateFont(int(scale*11), 0, 0, 0, FW_NORMAL, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfSmallItalic = CreateFont(int(scale*11), 0, 0, 0, FW_NORMAL, true, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfItalic = CreateFont(int(scale*14), 0, 0, 0, FW_NORMAL, true, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); + + pfMono = CreateFont(int(scale*12), 0, 0, 0, FW_NORMAL, false, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_MODERN, "Lucida Console"); + + pfItalicMediumPlus = CreateFont(int(scale*18), 0, 0, 0, FW_NORMAL, true, false, false, charSet, + OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH|FF_ROMAN, font.c_str()); +} + +void GDIImplFontSet::getInfo(FontInfo &fi) const { + fi.normal = pfMedium; + fi.bold = Medium; + fi.italic = pfItalic; +} + +void GDIImplFontSet::selectFont(HDC hDC, int format) const { + if (format==0 || format==10) { + SelectObject(hDC, pfMedium); + } + else if (format==fontMedium){ + SelectObject(hDC, pfMedium); + } + else if (format==1){ + SelectObject(hDC, Medium); + } + else if (format==boldLarge){ + SelectObject(hDC, Large); + } + else if (format==boldHuge){ + SelectObject(hDC, Huge); + } + else if (format==boldSmall){ + SelectObject(hDC, Small); + } + else if (format==fontLarge){ + SelectObject(hDC, pfLarge); + } + else if (format==fontMediumPlus){ + SelectObject(hDC, pfMediumPlus); + } + else if (format==fontSmall){ + SelectObject(hDC, pfSmall); + } + else if (format==italicSmall){ + SelectObject(hDC, pfSmallItalic); + } + else if (format==italicText){ + SelectObject(hDC, pfItalic); + } + else if (format==italicMediumPlus){ + SelectObject(hDC, pfItalicMediumPlus); + } + else if (format == monoText) { + SelectObject(hDC, pfMono); + } + else { + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + } +} + + +HFONT GDIImplFontSet::getFont(int format) const { + format = format & 31; + if (format==0 || format==10) { + return pfMedium; + } + else if (format==fontMedium){ + return pfMedium; + } + else if (format==1){ + return Medium; + } + else if (format==boldLarge){ + return Large; + } + else if (format==boldHuge){ + return Huge; + } + else if (format==boldSmall){ + return Small; + } + else if (format==fontLarge){ + return pfLarge; + } + else if (format==fontMediumPlus){ + return pfMediumPlus; + } + else if (format==fontSmall){ + return pfSmall; + } + else if (format==italicSmall){ + return pfSmallItalic; + } + else if (format==italicText){ + return pfItalic; + } + else if (format==italicMediumPlus){ + return pfItalicMediumPlus; + } + else if (format == monoText) { + return pfMono; + } + else { + return (HFONT)GetStockObject(DEFAULT_GUI_FONT); + } +} + + + +const GDIImplFontSet &gdioutput::getCurrentFont() const { + if (currentFontSet == 0) { + map::const_iterator res = fonts.find(currentFont); + if (res == fonts.end()) + throw meosException("Font not defined: " + currentFont); + currentFontSet = &res->second; + } + + return *currentFontSet; +} + +const GDIImplFontSet &gdioutput::getFont(const string &font) const { + map::const_iterator res = fonts.find(font); + if (res == fonts.end()) { + return const_cast(this)->loadFont(font); + throw meosException("Font not defined: " + currentFont); + } + return res->second; +} + +int CALLBACK enumFontProc(const LOGFONT* logFont, const TEXTMETRIC *metric, DWORD id, LPARAM lParam) { + if (logFont->lfFaceName[0] == '@') + return 1; + + if (metric->tmAveCharWidth <= 0) + return 1; + + vector &enumFonts = *(vector *)(lParam); + /*string we = "we: " + itos(logFont->lfWeight); + string wi = "wi: " + itos(metric->tmAveCharWidth); + string he = "he: " + itos(metric->tmHeight); + string info = string(logFont->lfFaceName) + ", " + we + ", " + wi + ", " + he;*/ + enumFonts.push_back(GDIImplFontEnum()); + GDIImplFontEnum &f = enumFonts.back(); + f.face = logFont->lfFaceName; + f.height = metric->tmHeight; + f.width = metric->tmAveCharWidth; + f.relScale = ((double(metric->tmHeight) / double(metric->tmAveCharWidth)) * 14.0/36.0); + return 1; +} + +void gdioutput::getEnumeratedFonts(vector< pair > &output) const { + if (enumeratedFonts.empty()) { + HDC hDC = GetDC(hWndTarget); +// EnumFontFamilies(hDC, NULL, enumFontProc, LPARAM(&enumeratedFonts)); + LOGFONT logFont; + memset(&logFont, 0, sizeof(LOGFONT)); + logFont.lfCharSet = getCharSet(); + EnumFontFamiliesEx(hDC, &logFont, enumFontProc, LPARAM(&enumeratedFonts), 0); + ReleaseDC(hWndTarget, hDC); + } + output.resize(enumeratedFonts.size()); + for (size_t k = 0; k avgWidthCache.size()) + throw meosException("Internal font error"); + + if (avgWidthCache[font] == 0) { + TextInfo ti; + ti.xp = 0; + ti.yp = 0; + ti.format = font; + ti.text = "Goliat Meze 1234:5678"; + ti.font = gdiName; + gdi.calcStringSize(ti); + avgWidthCache[font] = double(ti.textRect.right) / double(ti.text.length()); + + } + return avgWidthCache[font]; +} + +const string &gdioutput::getFontName(int id) { + + return _EmptyString; +} + +GDIImplFontEnum::GDIImplFontEnum() { + relScale = 1.0; +} + +GDIImplFontEnum::~GDIImplFontEnum() { +} + +void gdioutput::setEncoding(FontEncoding encoding) { + if (encoding != fontEncoding) { + enumeratedFonts.clear(); + fonts.clear(); + fontEncoding = encoding; + } +} + +FontEncoding gdioutput::getEncoding() const { + return fontEncoding; +} + +FontEncoding interpetEncoding(const string &enc) { + if (enc == "RUSSIAN") + return Russian; + else if (enc == "EASTEUROPE") + return EastEurope; + else if (enc == "HEBREW") + return Hebrew; + else + return ANSI; +} + +const wstring &gdioutput::toWide(const string &input) const { + wstring &output = StringCache::getInstance().wget(); + int cp = 1252; + switch(getEncoding()) { + case Russian: + cp = 1251; + break; + case EastEurope: + cp = 1250; + break; + case Hebrew: + cp = 1255; + break; + } + + output.resize(input.size()+1, 0); + MultiByteToWideChar(cp, MB_PRECOMPOSED, input.c_str(), -1, &output[0], output.size() * sizeof(wchar_t)); + return output; +} + +const string &gdioutput::toUTF8(const string &input) const { + return toUTF8(toWide(input)); +} + +const string &gdioutput::toUTF8(const wstring &winput) const { + string &output = StringCache::getInstance().get(); + size_t alloc = winput.length()*2; + output.resize(alloc); + WideCharToMultiByte(CP_UTF8, 0, winput.c_str(), winput.length()+1, (char *)output.c_str(), alloc, 0, 0); + output.resize(strlen(output.c_str())); + return output; +} + +void gdioutput::setListDescription(const string &desc) { + listDescription = desc; +} + +InputInfo &InputInfo::setFont(gdioutput &gdi, gdiFonts font) { + SendMessage(hWnd, WM_SETFONT, (WPARAM) gdi.getCurrentFont().getFont(font), 0); + return *this; +} + +void gdioutput::copyToClipboard(const string &html, bool convertToUTF8, const string &txt) const { + + if (OpenClipboard(getHWND()) != false) { + EmptyClipboard(); + + string htmlUTF; + size_t len = html.length() + 1; + const char *output = html.c_str(); + if (convertToUTF8) { + htmlUTF = toUTF8(html); + len = htmlUTF.length() + 1; + output = htmlUTF.c_str(); + } + + const char cbd[]= + "Version:0.9\n" + "StartHTML:%08u\n" + "EndHTML:%08u\n" + "StartFragment:%08u\n" + "EndFragment:%08u\n"; + + char head[256]; + sprintf_s(head, cbd, 1,0,0,0); + + int offset=strlen(head); + + //Fill header with relevant information + int ho_start = offset; + int ho_end = offset + len; + sprintf_s(head, cbd, offset,offset+len,ho_start,ho_end); + + HANDLE hMem=GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, offset+len); + LPVOID data=GlobalLock(hMem); + + memcpy(LPSTR(data), head, offset); + memcpy(LPSTR(data)+offset, output, len); + + GlobalUnlock(hMem); + + // Text format + HANDLE hMemText = 0; + HANDLE hMemTextWide = 0; + + if (txt.length() > 0) { + hMemText = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, txt.length()+1); + LPVOID dataText=GlobalLock(hMemText); + memcpy(LPSTR(dataText), txt.c_str() , txt.length()+1); + GlobalUnlock(hMemText); + } + else { + // HTML table to text + ostringstream result; + bool started = false; + bool newline = false; + bool dowrite = false; + for (size_t k = 0; k + 3 < html.size(); k++) { + if (html[k] == '<') { + if (html[k+1] == 't') { + if (html[k+2] == 'r') { + newline = true; + if (started) + result << "\r\n"; + } + else if (html[k+2] == 'd') { + if (!newline) + result << "\t"; + started = true; + newline = false; + dowrite = true; + } + } + else if (html[k+1] == '/') { + if (html[k+2] == 't' && html[k+3] == 'd') { + dowrite = false; + } + } + while (k < html.size() && html[k] != '>') + k++; + } + else { + if (dowrite) + result << html[k]; + } + } + + string atext = decodeXML(result.str()); +/* result.flush(); + + for (size_t k = 0; k < atext.size(); k++) { + if (atext[k] == '&') { + size_t m = 0; + while ((k+m) < atext.size() && atext[k+m] != ';') + m++; + + if ((k+m) < atext.size() && atext[k+m] == ';') { + string cmd = atext.substr(k, m-k); + if (cmd == "nbsp") + result << " "; + else if (cmd == "amp") + result << " "; + else if (cmd == "lt") + result << "<"; + else if (cmd == "gt") + result << ">"; + else if (cmd == "quot") + result << "\""; + + k += m; + } + } + else + result << atext[k]; + + } + + atext = result.str(); +*/ + if (atext.size() > 0) { + wstring atextw; + int osize = atext.size(); + atextw.resize(osize + 1, 0); + size_t siz = atextw.size(); + MultiByteToWideChar(CP_UTF8, 0, atext.c_str(), -1, &atextw[0], siz * sizeof(wchar_t)); + hMemTextWide = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, siz * sizeof(wchar_t)); + LPVOID dataText = GlobalLock(hMemTextWide); + memcpy(LPSTR(dataText), atextw.c_str(), siz * sizeof(wchar_t)); + GlobalUnlock(hMemTextWide); + } + } + UINT CF_HTML = RegisterClipboardFormat("HTML format"); + SetClipboardData(CF_HTML, hMem); + + if (hMemText != 0) + SetClipboardData(CF_TEXT, hMemText); + if (hMemTextWide != 0) { + SetClipboardData(CF_UNICODETEXT, hMemTextWide); + } + CloseClipboard(); + } +} + +Recorder &gdioutput::getRecorder() { + if (recorder.first == 0) { + recorder.first = new Recorder(); + recorder.second = true; + } + return *recorder.first; +} + +void gdioutput::initRecorder(Recorder *rec) { + if (recorder.second) + delete recorder.first; + + recorder.first = rec; + recorder.second = false; +} + +string gdioutput::dbPress(const string &id, int extra) { + bool notEnabled = false; + for (list::iterator it=BI.begin(); it != BI.end(); ++it) { + if (id==it->id && (extra == -65536 || extra == it->getExtraInt())) { + + if (!IsWindowEnabled(it->hWnd)) { + notEnabled = true; + continue; + } + + if (it->isCheckbox) { + check(id, !isChecked(id)); + } + else if(!it->callBack && !it->handler) + throw meosException("Button " + id + " is not active."); + + string val = it->text; + if (it->handler) + it->handleEvent(*this, GUI_BUTTON); + else if (it->callBack) + it->callBack(this, GUI_BUTTON, &*it); //it may be destroyed here... + return val; + } + } + if (notEnabled) + throw meosException("Button " + id + " is not active."); + + throw meosException("Unknown command " + id + "."); +} + +string gdioutput::dbPress(const string &id, const char *extra) { + string eid = extra ? extra : ""; + for (list::iterator it=BI.begin(); it != BI.end(); ++it) { + if (id==it->id && (!extra || (it->isExtraString() && eid == it->getExtra()))) { + + if (!IsWindowEnabled(it->hWnd)) + throw meosException("Button " + id + " is not active."); + + if (it->isCheckbox) { + check(id, !isChecked(id)); + } + else if(!it->callBack && !it->handler) + throw meosException("Button " + id + " is not active."); + + string val = it->text; + if (it->handler) + it->handleEvent(*this, GUI_BUTTON); + else if (it->callBack) + it->callBack(this, GUI_BUTTON, &*it); //it may be destroyed here... + return val; + } + } + throw meosException("Unknown command " + id + "/" + eid +"."); +} + + +string gdioutput::dbSelect(const string &id, int data) { + + for (list::iterator it = LBI.begin(); it != LBI.end(); ++it) { + if (id==it->id) { + if (!IsWindowEnabled(it->hWnd)) + throw meosException("Selection " + id + " is not active."); + if (it->multipleSelection) { + map::const_iterator res = it->data2Index.find(data); + if (res != it->data2Index.end()) + SendMessage(it->hWnd, LB_SETSEL, true, res->second); + else + throw meosException("List " + id + " does not contain value " + itos(data) + "."); + } + else { + if (!selectItemByData(id, data)) + throw meosException("List " + id + " does not contain value " + itos(data) + "."); + } + UpdateWindow(it->hWnd); + string res = it->text; + internalSelect(*it); + return res; + } + } + throw meosException("Unknown selection " + id + "."); +} + +void gdioutput::internalSelect(ListBoxInfo &bi) { + bi.syncData(); + if (bi.callBack || bi.handler) { + setWaitCursor(true); + hasCleared = false; + try { + bi.writeLock = true; + if (bi.handler) + bi.handleEvent(*this, GUI_LISTBOX); + else + bi.callBack(this, GUI_LISTBOX, &bi); //it may be destroyed here... Then hasCleared is set. + } + catch(...) { + if (!hasCleared) + bi.writeLock = false; + setWaitCursor(false); + throw; + } + if (!hasCleared) + bi.writeLock = false; + setWaitCursor(false); + } +} + +void gdioutput::dbInput(const string &id, const string &text) { + for (list::iterator it = LBI.begin(); it != LBI.end(); ++it) { + if (id==it->id) { + if (!IsWindowEnabled(it->hWnd) || !it->IsCombo) + throw meosException("Selection " + id + " is not active."); + + SendMessage(it->hWnd, CB_SETCURSEL, -1, 0); + SetWindowText(it->hWnd, text.c_str()); + it->text = text; + it->data = -1; + if (it->handler) + it->handleEvent(*this, GUI_COMBO); + else if (it->callBack) + it->callBack(this, GUI_COMBO, &*it); //it may be destroyed here... + return; + } + } + + for (list::iterator it = II.begin(); it != II.end(); ++it) { + if (id == it->id) { + if (!IsWindowEnabled(it->hWnd)) + throw meosException("Input " + id + " is not active."); + + it->text = text; + SetWindowText(it->hWnd, text.c_str()); + if (it->handler) + it->handleEvent(*this, GUI_INPUT); + else if (it->callBack) + it->callBack(this, GUI_INPUT, &*it); + return; + } + } + + throw meosException("Unknown input " + id + "."); +} + +void gdioutput::dbCheck(const string &id, bool state) { + +} + +string gdioutput::dbClick(const string &id, int extra) { + for (list::iterator it = TL.begin(); it != TL.end(); ++it) { + if (it->id == id && (extra == -65536 || it->getExtraInt() == extra)) { + if (it->callBack || it->hasEventHandler()) { + string res = it->text; + if (!it->handleEvent(*this, GUI_LINK)) + it->callBack(this, GUI_LINK, &*it); + return res; + } + else + throw meosException("Link " + id + " is not active."); + } + } + + throw meosException("Unknown link " + id + "."); +} + +void gdioutput::dbDblClick(const string &id, int data) { + for (list::iterator it = LBI.begin(); it != LBI.end(); ++it) { + if (id==it->id) { + if (!IsWindowEnabled(it->hWnd)) + throw meosException("Selection " + id + " is not active."); + selectItemByData(id, data); + if (it->handler) + it->handleEvent(*this, GUI_LISTBOXSELECT); + else if (it->callBack) + it->callBack(this, GUI_LISTBOXSELECT, &*it); //it may be destroyed here... + return; + } + } + throw meosException("Unknown selection " + id + "."); +} + +// Add the next answer for a dialog popup +void gdioutput::dbPushDialogAnswer(const string &answer) { + cmdAnswers.push_back(answer); +} + +void gdioutput::clearDialogAnswers(bool checkEmpty) { + if (!cmdAnswers.empty()) { + string front = cmdAnswers.front(); + cmdAnswers.clear(); + if (checkEmpty) + throw meosException("Pending answer: X#" + front); + } +} + +int gdioutput::dbGetStringCount(const string &str, bool subString) const { + int count = 0; + for (list::const_iterator it = TL.begin(); it != TL.end(); ++it) { + if (subString == false) { + if (it->text == str) + count++; + } + else { + if (it->text.find(str) != string::npos) + count++; + } + } + return count; +} + diff --git a/code/gdioutput.h b/code/gdioutput.h new file mode 100644 index 0000000..eb0bdd7 --- /dev/null +++ b/code/gdioutput.h @@ -0,0 +1,654 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// gdioutput.h: interface for the gdioutput class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_GDIOUTPUT_H__396F60F8_679F_498A_B759_DF8F6F346A4A__INCLUDED_) +#define AFX_GDIOUTPUT_H__396F60F8_679F_498A_B759_DF8F6F346A4A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include +#include +#include +#include +#include +#include + +class Toolbar; + +class gdioutput; +class oEvent; +typedef oEvent *pEvent; + +struct PrinterObject; + +class GDIImplFontEnum; +class GDIImplFontSet; + +class Table; +class FixedTabs; + +struct PageInfo; +struct RenderedPage; + +typedef int (*GUICALLBACK)(gdioutput *gdi, int type, void *data); + +enum GDICOLOR; +enum KeyCommandCode; +enum gdiFonts; +#include "gdistructures.h" + + +#define START_YP 30 +#define NOTIMEOUT 0x0AAAAAAA + +typedef list ToolList; + +enum FontEncoding { + ANSI, Russian, EastEurope, Hebrew +}; + +FontEncoding interpetEncoding(const string &enc); + +struct FontInfo { + const string *name; + HFONT normal; + HFONT bold; + HFONT italic; +}; + +class Recorder; + +class gdioutput { +protected: + string tag; + // Database error state warning + bool dbErrorState; + // Flag set to true when clearPage is called. + bool hasCleared; + bool useTables; + FontEncoding fontEncoding; + // Set to true when in test mode + bool isTestMode; + + int getCharSet() const; + + bool highContrast; + + void deleteFonts(); + void constructor(double _scale); + + void updateStringPosCache(); + vector shownStrings; + + void enableCheckBoxLink(TextInfo &ti, bool enable); + + //void CalculateCS(TextInfo &text); + //void printPage(PrinterObject &po, int StartY, int &EndY, bool calculate); + void printPage(PrinterObject &po, const PageInfo &pageInfo, RenderedPage &page); + bool startDoc(PrinterObject &po); + + bool getSelectedItem(ListBoxInfo &lbi); + bool doPrint(PrinterObject &po, PageInfo &pageInfo, pEvent oe); + + PrinterObject *po_default; + + void restoreInternal(const RestoreInfo &ri); + + void drawCloseBox(HDC hDC, RECT &Close, bool pressed); + + void setFontCtrl(HWND hWnd); + + list TL; + + //True if textlist has increasing y-values so + //that we can optimize rendering. + bool renderOptimize; + //Stored iterator used to optimize rendering + //by avoiding to loop through complete TL. + list::iterator itTL; + + list BI; + stdext::hash_map biByHwnd; + + list II; + stdext::hash_map iiByHwnd; + + list LBI; + stdext::hash_map lbiByHwnd; + + list DataInfo; + list Events; + list Rectangles; + list Tables; + list timers; + + Toolbar *toolbar; + ToolList toolTips; + + map restorePoints; + + GUICALLBACK onClear; + GUICALLBACK postClear; + + list IBox; + + list FocusList; + struct FucusInfo { + bool wasTabbed; + HWND hWnd; + FucusInfo() : wasTabbed(false), hWnd(false) {} + FucusInfo(HWND wnd) : wasTabbed(false), hWnd(wnd) {} + }; + + FucusInfo currentFocus; + + int lineHeight; + HWND hWndTarget; + HWND hWndAppMain; + HWND hWndToolTip; + HWND hWndTab; + + HBRUSH Background; + + map fonts; + const GDIImplFontSet &getCurrentFont() const; + const GDIImplFontSet &getFont(const string &font) const; + const GDIImplFontSet &loadFont(const string &font); + mutable const GDIImplFontSet *currentFontSet; + + int MaxX; + int MaxY; + int CurrentX; + int CurrentY; + int SX; + int SY; + + int Direction; + + int OffsetY; //Range 0 -- MaxY + int OffsetX; //Range 0 -- MaxX + + //Set to true if we should not update window during "addText" operations + bool manualUpdate; + + LRESULT ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam); + void getWindowText(HWND hWnd, string &text); + double scale; + HFONT getGUIFont() const; + + void resetLast() const; + mutable int lastFormet; + mutable bool lastActive; + mutable bool lastHighlight; + mutable DWORD lastColor; + mutable string lastFont; + + void initCommon(double scale, const string &font); + + void processButtonMessage(ButtonInfo &bi, DWORD wParam); + void processEditMessage(InputInfo &bi, DWORD wParam); + void processComboMessage(ListBoxInfo &bi, DWORD wParam); + void processListMessage(ListBoxInfo &bi, DWORD wParam); + + void doEnter(); + void doEscape(); + bool doUpDown(int direction); + + FixedTabs *tabs; + + string currentFont; + vector< GDIImplFontEnum > enumeratedFonts; + + double autoSpeed; + double autoPos; + mutable double lastSpeed; + mutable double autoCounter; + + bool lockRefresh; + bool fullScreen; + bool hideBG; + mutable bool commandLock; + mutable DWORD commandUnlockTime; + + bool hasCommandLock() const; + void setCommandLock() const; + void liftCommandLock() const; + + struct ScreenStringInfo { + RECT rc; + string str; + bool reached; + + ScreenStringInfo(const RECT &r, const string &s) { + rc = r; + str = s; + reached = false; + } + }; + + string listDescription; + + mutable map, ScreenStringInfo> screenXYToString; + mutable map > stringToScreenXY; + mutable pair snapshotMaxXY; + bool hasAnyTimer; + + friend class InputInfo; + friend class TestMeOS; + + // Recorder, the second member is true if the recorder is owned and should be deleted + pair recorder; +public: + + void initRecorder(Recorder *rec); + Recorder &getRecorder(); + string dbPress(const string &id, int extra); + string dbPress(const string &id, const char *extra); + + string dbSelect(const string &id, int data); + void dbInput(const string &id, const string &test); + void dbCheck(const string &id, bool state); + string dbClick(const string &id, int extra); + void dbDblClick(const string &id, int data); + + // Add the next answer for a dialog popup + void dbPushDialogAnswer(const string &answer); + mutable list cmdAnswers; + + int dbGetStringCount(const string &str, bool subString) const; + + // Ensure list of stored answers is empty + void clearDialogAnswers(bool checkEmpty); + + void internalSelect(ListBoxInfo &bi); + + bool isTest() const {return isTestMode;} + const string &getTag() const {return tag;} + bool hasTag(const string &t) const {return tag == t;} + const wstring &toWide(const string &input) const; + + const string &toUTF8(const string &input) const; + const string &toUTF8(const wstring &input) const; + + void setEncoding(FontEncoding encoding); + FontEncoding getEncoding() const; + + void getFontInfo(const TextInfo &ti, FontInfo &fi) const; + + /** Return true if rendering text should be skipped for + this format. */ + static bool skipTextRender(int format); + + const list &getTL() const {return TL;} + + void getEnumeratedFonts(vector< pair > &output) const; + const string &getFontName(int id); + double getRelativeFontScale(gdiFonts font, const char *fontFace) const; + + bool isFullScreen() const {return fullScreen;} + void setFullScreen(bool useFullScreen); + void setAutoScroll(double speed); + void getAutoScroll(double &speed, double &pos) const; + void storeAutoPos(double pos); + int getAutoScrollDir() const {return (autoSpeed > 0 ? 1:-1);} + int setHighContrastMaxWidth(); + void hideBackground(bool hide) {hideBG = hide;} + HWND getToolbarWindow() const; + bool hasToolbar() const; + void activateToolbar(bool active); + + void processToolbarMessage(const string &id, void *data); + + void synchronizeListScroll(const string &id1, const string &id2); + + FixedTabs &getTabs(); + + // True if up/down is locked, i.e, don't move page + bool lockUpDown; + + + double getScale() const {return scale;} + void enableEditControls(bool enable); + + bool hasEditControl() const; + + void setFont(int size, const string &font, FontEncoding encoding); + + int getButtonHeight() const; + int scaleLength(int input) const {return int(scale*input + 0.5);} + + // Fill in current printer settings + void fetchPrinterSettings(PrinterObject &po) const; + + void tableCB(ButtonInfo &bu, Table *t); + + char *getExtra(const char *id) const; + int getExtraInt(const char *id) const; + + void enableTables(); + void disableTables(); + + void pasteText(const char *id); + + bool writeHTML(const wstring &file, const string &title, int refreshTimeOut) const; + bool writeTableHTML(const wstring &file, const string &title, int refreshTimeOut) const; + bool writeTableHTML(ostream &fout, + const string &title, + bool simpleFormat, + int refreshTimeOut) const; + + void print(pEvent oe, Table *t=0, bool printMeOSHeader=true, bool noMargin=false); + void print(PrinterObject &po, pEvent oe, bool printMeOSHeader=true, bool noMargin=false); + void printSetup(PrinterObject &po); + void destroyPrinterDC(PrinterObject &po); + + void setSelection(const string &id, const set &selection); + void getSelection(const string &id, set &selection); + + HWND getTarget() const {return hWndTarget;} + HWND getMain() const {return hWndAppMain;} + + string browseForFolder(const string &folderStart, const char *descr); + void scrollToBottom(); + void scrollTo(int x, int y); + void setOffset(int x, int y, bool update); + + void selectTab(int Id); + + void addTable(Table *table, int x, int y); + Table &getTable() const; //Get the (last) table. If needed, add support for named tables... + + ToolInfo &addToolTip(const string &id, const string &tip, HWND hWnd, RECT *rc=0); + ToolInfo *getToolTip(const string &id); + ToolInfo &updateToolTip(const string &id, const string &tip); + + HWND getToolTip(){return hWndToolTip;} + + void init(HWND hWnd, HWND hMainApp, HWND hTab); + bool openDoc(const char *doc); + string browseForSave(const vector< pair > &filter, + const string &defext, int &FilterIndex); + string browseForOpen(const vector< pair > &filter, + const string &defext); + + bool clipOffset(int PageX, int PageY, int &MaxOffsetX, int &MaxOffsetY); + RectangleInfo &addRectangle(RECT &rc, GDICOLOR Color = GDICOLOR(-1), + bool DrawBorder = true, bool addFirst = false); + + RectangleInfo &getRectangle(const char *id); + + DWORD makeEvent(const string &id, const string &origin, + DWORD data, int extraData, bool flushEvent); + + void unregisterEvent(const string &id); + EventInfo ®isterEvent(const string &id, GUICALLBACK cb); + + int sendCtrlMessage(const string &id); + bool canClear(); + void setOnClearCb(GUICALLBACK cb); + void setPostClearCb(GUICALLBACK cb); + + void restore(const string &id="", bool DoRefresh=true); + + /// Restore, but do not update client area size, + /// position, zoom, scrollbars, and do not refresh + void restoreNoUpdate(const string &id); + + void setRestorePoint(); + void setRestorePoint(const string &id); + + bool removeControl(const string &id); + bool hideControl(const string &id); + + void CheckInterfaceTimeouts(DWORD T); + bool RemoveFirstInfoBox(const string &id); + void drawBoxText(HDC hDC, RECT &tr, InfoBox &Box, bool highligh); + void drawBoxes(HDC hDC, RECT &rc); + void drawBox(HDC hDC, InfoBox &Box, RECT &pos); + void addInfoBox(string id, string text, int TimeOut=0, GUICALLBACK cb=0); + HWND getHWND() const {return hWndTarget;} + void updateObjectPositions(); + void drawBackground(HDC hDC, RECT &rc); + void renderRectangle(HDC hDC, RECT *clipRegion, const RectangleInfo &ri); + + void updateScrollbars() const; + + void SetOffsetY(int oy){OffsetY=oy;} + void SetOffsetX(int ox){OffsetX=ox;} + int GetPageY(){return max(MaxY, 100)+60;} + int GetPageX(){return max(MaxX, 100)+100;} + int GetOffsetY(){return OffsetY;} + int GetOffsetX(){return OffsetX;} + + void RenderString(TextInfo &ti, const string &text, HDC hDC); + void RenderString(TextInfo &ti, HDC hDC=0); + void calcStringSize(TextInfo &ti, HDC hDC=0) const; + void formatString(const TextInfo &ti, HDC hDC) const; + + static string getTimerText(TextInfo *tit, DWORD T); + static string getTimerText(int ZeroTime, int format); + + + void fadeOut(string Id, int ms); + void setWaitCursor(bool wait); + void setWindowTitle(const string &title); + bool selectFirstItem(const string &name); + void removeString(string Id); + void refresh() const; + void refreshFast() const; + + void takeShownStringsSnapshot(); + void refreshSmartFromSnapshot(bool allowMoveOffset); + + void dropLine(double lines=1){CurrentY+=int(lineHeight*lines); MaxY=max(MaxY, CurrentY);} + int getCX() const {return CurrentX;} + int getCY() const {return CurrentY;} + int getWidth() const {return MaxX;} + int getHeight() const {return MaxY;} + void getTargetDimension(int &x, int &y) const; + + void setCX(int cx){CurrentX=cx;} + void setCY(int cy){CurrentY=cy;} + int getLineHeight() const {return lineHeight;} + int getLineHeight(gdiFonts font, const char *face) const; + + BaseInfo *setInputFocus(const string &id, bool select=false); + InputInfo *getInputFocus(); + + void enableInput(const char *id, bool acceptMissing = false) {setInputStatus(id, true, acceptMissing);} + void disableInput(const char *id, bool acceptMissing = false) {setInputStatus(id, false, acceptMissing);} + void setInputStatus(const char *id, bool status, bool acceptMissing = false); + void setInputStatus(const string &id, bool status, bool acceptMissing = false) + {setInputStatus(id.c_str(), status, acceptMissing);} + + void setTabStops(const string &Name, int t1, int t2=-1); + void setData(const string &id, DWORD data); + void setData(const string &id, void *data); + void *getData(const string &id) const; + + void autoRefresh(bool flag) {manualUpdate = !flag;} + + bool getData(const string &id, DWORD &data) const; + bool hasData(const char *id) const; + + int getItemDataByName(const char *id, const char *name) const; + bool selectItemByData(const char *id, int data); + void removeSelected(const char *id); + + bool selectItemByData(const string &id, int data) { + return selectItemByData(id.c_str(), data); + } + + enum AskAnswer {AnswerNo = 0, AnswerYes = 1, AnswerCancel = 2}; + bool ask(const string &s); + AskAnswer askCancel(const string &s); + + void alert(const string &msg) const; + void fillDown(){Direction=1;} + void fillRight(){Direction=0;} + void fillNone(){Direction=-1;} + void newColumn(){CurrentY=START_YP; CurrentX=MaxX+10;} + void newRow(){CurrentY=MaxY; CurrentX=10;} + + void pushX(){SX=CurrentX;} + void pushY(){SY=CurrentY;} + void popX(){CurrentX=SX;} + void popY(){CurrentY=SY;} + + bool updatePos(int x, int y, int width, int height); + void adjustDimension(int width, int height); + + /** Return a selected item*/ + bool getSelectedItem(const string &id, ListBoxInfo &lbi); + + /** Return the selected data in first, second indicates if data was available*/ + pair getSelectedItem(const string &id); + pair getSelectedItem(const char *id); + + bool addItem(const string &id, const string &text, size_t data = 0); + bool addItem(const string &id, const vector< pair > &items); + void filterOnData(const string &id, const stdext::hash_set &filter); + + bool clearList(const string &id); + + bool hasField(const string &id) const; + const string &getText(const char *id, bool acceptMissing = false) const; + BaseInfo &getBaseInfo(const char *id) const; + + int getTextNo(const char *id, bool acceptMissing = false) const; + int getTextNo(const string &id, bool acceptMissing = false) const + {return getTextNo(id.c_str(), acceptMissing);} + + const string &getText(const string &id, bool acceptMissing = false) const + {return getText(id.c_str(), acceptMissing);} + + // Insert text and notify "focusList" + bool insertText(const string &id, const string &text); + + void copyToClipboard(const string &html, bool convertToUTF8, + const string &txt) const; + + BaseInfo *setTextTranslate(const char *id, const string &text, bool update=false); + BaseInfo *setTextTranslate(const char *id, const char *text, bool update=false); + BaseInfo *setTextTranslate(const string &id, const string &text, bool update=false); + + BaseInfo *setText(const char *id, const string &text, bool update=false); + BaseInfo *setText(const char *id, int number, bool update=false); + BaseInfo *setTextZeroBlank(const char *id, int number, bool update=false); + BaseInfo *setText(const string &id, const string &text, bool update=false) + {return setText(id.c_str(), text, update);} + BaseInfo *setText(const string &id, int number, bool update=false) + {return setText(id.c_str(), number, update);} + + void clearPage(bool autoRefresh, bool keepToolbar = false); + + void TabFocus(int direction=1); + void Enter(); + void Escape(); + bool UpDown(int direction); + void keyCommand(KeyCommandCode code); + + LRESULT ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam); + void setWindow(HWND hWnd){hWndTarget=hWnd;} + + void scaleSize(double scale); + + ButtonInfo &addButton(const string &id, const string &text, GUICALLBACK cb = 0, const string &tooltip=""); + + ButtonInfo &addButton(int x, int y, const string &id, const string &text, + GUICALLBACK cb = 0, const string &tooltop=""); + ButtonInfo &addButton(int x, int y, int w, const string &id, const string &text, + GUICALLBACK cb, const string &tooltop, bool AbsPos, bool hasState); + + ButtonInfo &addCheckbox(const string &id, const string &text, GUICALLBACK cb=0, bool Checked=true, const string &Help=""); + ButtonInfo &addCheckbox(int x, int y, const string &id, const string &text, GUICALLBACK cb=0, bool Checked=true, const string &Help="", bool AbsPos=false); + bool isChecked(const string &id); + void check(const string &id, bool state, bool keepOriginalState = false); + + bool isInputChanged(const string &exclude); + + InputInfo &addInput(const string &id, const string &text="", int length=16, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip=""); + InputInfo &addInput(int x, int y, const string &id, const string &text, int length, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip=""); + + InputInfo *replaceSelection(const char *id, const string &text); + + InputInfo &addInputBox(const string &id, int width, int height, const string &text, + GUICALLBACK cb, const string &Explanation); + + InputInfo &addInputBox(const string &id, int x, int y, int width, int height, + const string &text, GUICALLBACK cb, const string &Explanation); + + ListBoxInfo &addListBox(const string &id, int width, int height, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip="", bool multiple=false); + ListBoxInfo &addListBox(int x, int y, const string &id, int width, int height, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip="", bool multiple=false); + + ListBoxInfo &addSelection(const string &id, int width, int height, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip=""); + ListBoxInfo &addSelection(int x, int y, const string &id, int width, int height, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip=""); + + ListBoxInfo &addCombo(const string &id, int width, int height, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip=""); + ListBoxInfo &addCombo(int x, int y, const string &id, int width, int height, GUICALLBACK cb=0, const string &Explanation="", const string &tooltip=""); + // Grows a listbox, selection, combo in X-direction to fit current contents. Returns true if changed. + bool autoGrow(const char *id); + + void setListDescription(const string &desc); + + TextInfo &addString(const string &id, int format, const string &text, GUICALLBACK cb=0); + TextInfo &addString(const string &id, int yp, int xp, int format, const string &text, + int xlimit=0, GUICALLBACK cb=0, const char *fontFace = 0); + TextInfo &addString(const char *id, int format, const string &text, GUICALLBACK cb=0); + TextInfo &addString(const char *id, int yp, int xp, int format, const string &text, + int xlimit=0, GUICALLBACK cb=0, const char *fontFace = 0); + // Untranslated versions + TextInfo &addStringUT(int yp, int xp, int format, const string &text, + int xlimit=0, GUICALLBACK cb=0, const char *fontFace = 0); + TextInfo &addStringUT(int format, const string &text, GUICALLBACK cb=0); + + TextInfo &addTimer(int yp, int xp, int format, DWORD ZeroTime, + int xlimit=0, GUICALLBACK cb=0, int TimeOut=NOTIMEOUT, const char *fontFace = 0); + TextInfo &addTimeout(int TimeOut, GUICALLBACK cb); + + void removeTimeoutMilli(const string &id); + TimerInfo &addTimeoutMilli(int timeOut, const string &id, GUICALLBACK cb); + void timerProc(TimerInfo &timer, DWORD timeout); + + void draw(HDC hDC, RECT &windowArea, RECT &drawArea); + + void closeWindow(); + + void setDBErrorState(bool state); + + friend int TablesCB(gdioutput *gdi, int type, void *data); + friend class Table; + friend gdioutput *createExtraWindow(const string &tag, const string &title, int max_x, int max_y); + + gdioutput(const string &tag, double _scale, FontEncoding encoding); + gdioutput(double _scale, FontEncoding encoding, HWND hWndTarget, const PrinterObject &defprn); + virtual ~gdioutput(); +}; + +#endif // !defined(AFX_GDIOUTPUT_H__396F60F8_679F_498A_B759_DF8F6F346A4A__INCLUDED_) diff --git a/code/gdistructures.h b/code/gdistructures.h new file mode 100644 index 0000000..c77b194 --- /dev/null +++ b/code/gdistructures.h @@ -0,0 +1,402 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#ifndef GDI_STRUCTURES +#define GDI_STRUCTURES + +#include +#include "guihandler.h" + +class BaseInfo +{ +protected: + void *extra; + GuiHandler *handler; + bool dataString; +public: + + bool hasEventHandler() const { + return handler != 0; + } + + bool handleEvent(gdioutput &gdi, GuiEventType type) { + if (handler) { + handler->handle(gdi, *this, type); + return true; + } + return false; + } + + BaseInfo():extra(0), dataString(false), handler(0) {} + virtual ~BaseInfo() {} + string id; + + virtual HWND getControlWindow() const = 0; + + virtual void refresh() { + InvalidateRect(getControlWindow(), 0, true); + } + + BaseInfo &setExtra(const char *e) {extra=(void *)e; dataString = true; return *this;} + + BaseInfo &setExtra(int e) {extra = (void *)(e); return *this;} + BaseInfo &setExtra(size_t e) {extra = (void *)(e); return *this;} + + bool isExtraString() const {return dataString;} + char *getExtra() const {assert(extra == 0 || dataString); return (char *)extra;} + int getExtraInt() const {return int(extra);} + size_t getExtraSize() const {return size_t(extra);} + + GuiHandler &getHandler() const; + BaseInfo &setHandler(const GuiHandler *h) {handler = const_cast(h); return *this;} + +}; + +class RestoreInfo : public BaseInfo +{ +public: + int nLBI; + int nBI; + int nII; + int nTL; + int nRect; + int nHWND; + int nData; + + int sCX; + int sCY; + int sMX; + int sMY; + int sOX; + int sOY; + + int nTooltip; + int nTables; + + GUICALLBACK onClear; + GUICALLBACK postClear; + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + +class RectangleInfo : public BaseInfo +{ +private: + DWORD color; + DWORD color2; + bool drawBorder; + DWORD borderColor; + RECT rc; + + bool border3D; +public: + const RECT &getRect() const {return rc;} + RectangleInfo(): color(0), color2(0), borderColor(0), border3D(false), drawBorder(false) {memset(&rc, 0, sizeof(RECT));} + RectangleInfo &setColor(GDICOLOR c) {color = c; return *this;} + RectangleInfo &setColor2(GDICOLOR c) {color2 = c; return *this;} + RectangleInfo &set3D(bool is3d) {border3D = is3d; return *this;} + RectangleInfo &setBorderColor(GDICOLOR c) {borderColor = c; return *this;} + friend class gdioutput; + friend struct PageInfo; + + RectangleInfo &changeDimension(gdioutput &gdi, int dx, int dy); + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + + +class TableInfo : public BaseInfo +{ +public: + TableInfo():xp(0), yp(0), table(0) {} + int xp; + int yp; + Table *table; + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + + +class TextInfo : public BaseInfo +{ +public: + + TextInfo():format(0), color(0), xlimit(0), hasTimer(false), + hasCapture(false), callBack(0), highlight(false), + active(false), lineBreakPrioity(0), + absPrintX(0), absPrintY(0), realWidth(0) { + textRect.left = 0; textRect.right = 0; + textRect.top = 0; textRect.bottom = 0; + } + + TextInfo &setColor(GDICOLOR c) {color = c; return *this;} + TextInfo &changeFont(const string &fnt) {font = fnt; return *this;} //Note: size not updated + + int getHeight() {return int(textRect.bottom-textRect.top);} + gdiFonts getGdiFont() const {return gdiFonts(format & 0xFF);} + // Sets absolute print coordinates in [mm] + TextInfo &setAbsPrintPos(int x, int y) { + absPrintX = x; absPrintY = y; return *this; + } + string text; + string font; + + int xp; + int yp; + + int format; + DWORD color; + int xlimit; + int lineBreakPrioity; + int absPrintX; + int absPrintY; + + bool hasTimer; + DWORD zeroTime; + DWORD timeOut; + + bool hasCapture; + GUICALLBACK callBack; + RECT textRect; + int realWidth; // The calculated actual width of the string in pixels + bool highlight; + bool active; + + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + +class ButtonInfo : public BaseInfo +{ +private: + bool originalState; + bool isEditControl; + bool checked; + bool *updateLastData; + void synchData() const {if (updateLastData) *updateLastData = checked;} + +public: + ButtonInfo(): callBack(0), hWnd(0), AbsPos(false), fixedRightTop(false), + flags(0), storedFlags(0), originalState(false), isEditControl(false), + isCheckbox(false), checked(false), updateLastData(0) {} + + ButtonInfo &isEdit(bool e) {isEditControl=e; return *this;} + + int xp; + int yp; + int width; + string text; + HWND hWnd; + bool AbsPos; + bool fixedRightTop; + int flags; + int storedFlags; + bool isCheckbox; + bool isDefaultButton() const {return (flags&1)==1;} + bool isCancelButton() const {return (flags&2)==2;} + + ButtonInfo &setSynchData(bool *variable) {updateLastData = variable; return *this;} + + + void moveButton(gdioutput &gdi, int xp, int yp); + void getDimension(gdioutput &gdi, int &w, int &h); + + ButtonInfo &setDefault(); + ButtonInfo &setCancel() {flags|=2, storedFlags|=2; return *this;} + ButtonInfo &fixedCorner() {fixedRightTop = true; return *this;} + GUICALLBACK callBack; + friend class gdioutput; + + HWND getControlWindow() const {return hWnd;} +}; + +enum gdiFonts; +class InputInfo : public BaseInfo +{ +public: + InputInfo(); + string text; + + bool changed() const {return text!=original;} + void ignore(bool ig) {ignoreCheck=ig;} + InputInfo &isEdit(bool e) {isEditControl=e; return *this;} + InputInfo &setBgColor(GDICOLOR c) {bgColor = c; return *this;} + InputInfo &setFgColor(GDICOLOR c) {fgColor = c; return *this;} + InputInfo &setFont(gdioutput &gdi, gdiFonts font); + GDICOLOR getBgColor() const {return bgColor;} + GDICOLOR getFgColor() const {return fgColor;} + + InputInfo &setPassword(bool pwd); + + HWND getControlWindow() const {return hWnd;} + + InputInfo &setSynchData(string *variable) {updateLastData = variable; return *this;} + + int getX() const {return xp;} + int getY() const {return yp;} + int getWidth() const {return int(width);} +private: + HWND hWnd; + GUICALLBACK callBack; + void synchData() const {if (updateLastData) *updateLastData = text;} + string *updateLastData; + int xp; + int yp; + double width; + double height; + + GDICOLOR bgColor; + GDICOLOR fgColor; + bool isEditControl; + bool writeLock; + string original; + string focusText; // Test when got focus + bool ignoreCheck; // True if changed-state should be ignored + friend class gdioutput; +}; + +class ListBoxInfo : public BaseInfo +{ +public: + ListBoxInfo() : hWnd(0), callBack(0), IsCombo(false), index(-1), + writeLock(false), ignoreCheck(false), isEditControl(true), + originalProc(0), lbiSync(0), multipleSelection(false), + xp(0), yp(0), width(0), height(0), data(0), lastTabStop(0), + updateLastData(0) {} + string text; + size_t data; + int index; + bool changed() const {return text!=original;} + void ignore(bool ig) {ignoreCheck=ig;} + ListBoxInfo &isEdit(bool e) {isEditControl=e; return *this;} + HWND getControlWindow() const {return hWnd;} + + void copyUserData(ListBoxInfo &userLBI) const; + ListBoxInfo &setSynchData(int *variable) {updateLastData = variable; return *this;} + int getWidth() const {return int(width);} + int getX() const {return xp;} + int getY() const {return yp;} + bool isCombo() const {return IsCombo;} +private: + void syncData() const {if (updateLastData) *updateLastData = data;} + bool IsCombo; + int *updateLastData; + + GUICALLBACK callBack; + + int xp; + int yp; + double width; + double height; + HWND hWnd; + int lastTabStop; + + bool multipleSelection; + bool isEditControl; + bool writeLock; + string original; + int originalIdx; + bool ignoreCheck; // True if changed-state should be ignored + + map data2Index; + + // Synchronize with other list box + WNDPROC originalProc; + ListBoxInfo *lbiSync; + + friend LRESULT CALLBACK GetMsgProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam); + friend class gdioutput; +}; + +class DataStore +{ +public: + string id; + void *data; +}; + +class EventInfo : public BaseInfo +{ +private: + string origin; + DWORD data; + KeyCommandCode keyEvent; +public: + KeyCommandCode getKeyCommand() const {return keyEvent;} + DWORD getData() const {return data;} + void setKeyCommand(KeyCommandCode kc) {keyEvent = kc;} + void setData(const string &origin_, DWORD d) {origin = origin_, data = d;} + const string &getOrigin() {return origin;} + EventInfo(); + GUICALLBACK callBack; + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + +class TimerInfo : public BaseInfo +{ +private: + DWORD data; + gdioutput *parent; + TimerInfo(gdioutput *gdi, GUICALLBACK cb) : parent(gdi), callBack(cb) {} + +public: + BaseInfo &setExtra(void *e) {return BaseInfo::setExtra((const char *)e);} + + GUICALLBACK callBack; + friend class gdioutput; + friend void CALLBACK gdiTimerProc(HWND hWnd, UINT a, UINT_PTR ptr, DWORD b); + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + + +class InfoBox : public BaseInfo +{ +public: + InfoBox() : callBack(0), HasCapture(0), HasTCapture(0), TimeOut(0) {} + string text; + GUICALLBACK callBack; + + RECT TextRect; + RECT Close; + RECT BoundingBox; + + bool HasCapture; + bool HasTCapture; + + DWORD TimeOut; + + HWND getControlWindow() const {throw std::exception("Unsupported");} +}; + +typedef list TIList; + +struct ToolInfo { + string name; + TOOLINFOW ti; + wstring tip; + int id; +}; + + +#endif diff --git a/code/generalresult.cpp b/code/generalresult.cpp new file mode 100644 index 0000000..aa0bcfa --- /dev/null +++ b/code/generalresult.cpp @@ -0,0 +1,1297 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include +#include "generalresult.h" +#include "oEvent.h" +#include "meos_util.h" +#include "oListInfo.h" +#include "meosexception.h" +#include "localizer.h" + +GeneralResultCtr::GeneralResultCtr(const char *tagIn, const string &nameIn, GeneralResult *ptrIn) { + name = nameIn; + tag = tagIn; + ptr = ptrIn; +} + +GeneralResultCtr::GeneralResultCtr(string &file, DynamicResult *ptrIn) { + ptr = ptrIn; + name = ptrIn->getName(false); + tag = ptrIn->getTag(); + fileSource = file; +} + +GeneralResultCtr::~GeneralResultCtr() { + delete ptr; + ptr = 0; +} + +GeneralResultCtr::GeneralResultCtr(const GeneralResultCtr &ctr) { + ptr = ctr.ptr; + name = ctr.name; + tag = ctr.tag; + fileSource = ctr.fileSource; + ctr.ptr = 0; +} + +void GeneralResultCtr::operator=(const GeneralResultCtr &ctr) { + if (this == &ctr) + return; + delete ptr; + name = ctr.name; + ptr = ctr.ptr; + ctr.ptr = 0; +} + +bool GeneralResultCtr::isDynamic() const { + return !fileSource.empty(); +} + +GeneralResult::GeneralResult(void) { + context = 0; +} + +GeneralResult::~GeneralResult(void) { +} + +void GRINSTANCE() { + vector a; + vector b; + GeneralResult gr; + gr.sort(a, SortByFinishTime); + gr.sort(b, SortByFinishTime); +} + +void GeneralResult::setContext(const oListParam *contextIn) { + context = contextIn; +} + +void GeneralResult::clearContext() { + context = 0; +} + +int GeneralResult::getListParamTimeToControl() const { + if (context) + return context->useControlIdResultTo; + else + return 0; // No context in method editor +} + +int GeneralResult::getListParamTimeFromControl() const { + if (context) + return context->useControlIdResultFrom; + else + return 0; // No context in method editor +} + +struct GRSortInfo { + int principalSort; + int score; + oAbstractRunner *tr; + + bool operator<(const GRSortInfo &other) const { + if (principalSort != other.principalSort) + return principalSort < other.principalSort; + else if (score != other.score) + return score < other.score; + + const string &as = tr->getBib(); + const string &bs = other.tr->getBib(); + if (as != bs) + return compareBib(as, bs); + else + return tr->getName() < other.tr->getName(); + } +}; + +void GeneralResult::calculateTeamResults(vector &teams, oListInfo::ResultType resType, bool sortTeams, int inputNumber) const { + if (teams.empty()) + return; + prepareCalculations(*teams[0]->oe, true, inputNumber); + + //bool classSort = resType == oListInfo::Global ? false : true; + vector teamScore(teams.size()); + for (size_t k = 0; k < teams.size(); k++) { + if (resType == oListInfo::Classwise) { + teamScore[k].principalSort = teams[k]->Class ? teams[k]->Class->getSortIndex() * 50000 + + teams[k]->Class->getId() : 0; + } + else + teamScore[k].principalSort = 0; + + prepareCalculations(*teams[k]); + teams[k]->tmpResult.runningTime = teams[k]->getStartTime(); //XXX + teams[k]->tmpResult.runningTime = deduceTime(*teams[k]); + teams[k]->tmpResult.status = deduceStatus(*teams[k]); + teams[k]->tmpResult.points = deducePoints(*teams[k]); + + teamScore[k].score = score(*teams[k], teams[k]->tmpResult.status, + teams[k]->tmpResult.runningTime, + teams[k]->tmpResult.points); + + storeOutput(teams[k]->tmpResult.outputTimes, + teams[k]->tmpResult.outputNumbers); + + teamScore[k].tr = teams[k]; + + } + + ::sort(teamScore.begin(), teamScore.end()); + int place = 1; + int iPlace = 1; + int leadtime = 0; + for (size_t k = 0; k < teamScore.size(); k++) { + if (k>0 && teamScore[k-1].principalSort != teamScore[k].principalSort) { + place = 1; + iPlace = 1; + } + else if (k>0 && teamScore[k-1].score != teamScore[k].score) { + place = iPlace; + } + + if (teamScore[k].tr->tmpResult.status == StatusOK) { + teamScore[k].tr->tmpResult.place = place; + iPlace++; + if (place == 1) { + leadtime = teamScore[k].tr->tmpResult.runningTime; + teamScore[k].tr->tmpResult.timeAfter = 0; + } + else { + teamScore[k].tr->tmpResult.timeAfter = teamScore[k].tr->tmpResult.runningTime - leadtime; + } + } + else { + teamScore[k].tr->tmpResult.place = 0; + teamScore[k].tr->tmpResult.timeAfter = 0; + } + } + + if (sortTeams) { + for (size_t k = 0; k < teamScore.size(); k++) { + teams[k] = (oTeam *)teamScore[k].tr; + } + } +} + +void GeneralResult::sortTeamMembers(vector &runners) const { + vector runnerScore(runners.size()); + for (size_t k = 0; k < runners.size(); k++) { + runnerScore[k].principalSort = 0; + runnerScore[k].score = runners[k]->tmpResult.internalScore; + //runnerScore[k].score = score(*runners[k], runners[k]->tmpResult.status, + // runners[k]->tmpResult.runningTime, + // runners[k]->tmpResult.points); + + runnerScore[k].tr = runners[k]; + } + + ::sort(runnerScore.begin(), runnerScore.end()); + + for (size_t k = 0; k < runners.size(); k++) { + runners[k] = pRunner(runnerScore[k].tr); + } +} + +template void GeneralResult::sort(vector &rt, SortOrder so) const { + PrincipalSort ps = ClassWise; + + if (so == CourseResult) + ps = CourseWise; + + else if (so == SortByName || so == SortByFinishTimeReverse || + so == SortByFinishTime || so == SortByStartTime) + ps = None; + + vector< pair > arr(rt.size()); + const int maxT = 3600 * 100; + for(size_t k = 0; k < rt.size(); k++) { + arr[k].first = 0; + if (ps == ClassWise) + arr[k].first = rt[k]->getClassRef() ? rt[k]->getClassRef()->getSortIndex() : 0; + else if (ps == CourseWise) { + oRunner *r = dynamic_cast(rt[k]); + arr[k].first = r && r->getCourse(false) ? r->getCourse(false)->getId() : 0; + } + arr[k].second = rt[k]; + int ord = 0; + const oAbstractRunner::TempResult &tr = rt[k]->getTempResult(0); + if (so == SortByFinishTime || so == ClassFinishTime) { + ord = tr.getFinishTime(); + if (ord == 0 || tr.getStatus()>1) + ord = maxT; + } + else if (so == SortByFinishTimeReverse) { + ord = tr.getFinishTime(); + if (ord == 0 || tr.getStatus()>1) + ord = maxT; + else + ord = maxT - ord; + } + else if (so == SortByStartTime || so == ClassStartTime || + so == ClassStartTimeClub) { + ord = tr.getStartTime(); + } + + arr[k].first = arr[k].first * maxT * 10 + ord; + } + + stable_sort(arr.begin(), arr.end()); + + for(size_t k = 0; k < rt.size(); k++) { + rt[k] = (T*)arr[k].second; + } +} + +void GeneralResult::calculateIndividualResults(vector &runners, oListInfo::ResultType resType, bool sortRunners, int inputNumber) const { + + if (runners.empty()) + return; + prepareCalculations(*runners[0]->oe, false, inputNumber); + //bool classSort = resType == oListInfo::Global ? false : true; + vector runnerScore(runners.size()); + for (size_t k = 0; k < runners.size(); k++) { + const oRunner *r = runners[k]; + if (resType == oListInfo::Classwise) { + runnerScore[k].principalSort = r->Class ? r->Class->getSortIndex() * 50000 + + r->Class->getId() : 0; + } + else if (resType == oListInfo::Legwise) { + runnerScore[k].principalSort = r->Class ? r->Class->getSortIndex() * 50000 + + r->Class->getId() : 0; + + int ln = r->getLegNumber(); + const oTeam *pt = r->getTeam(); + if (pt) { + const oClass *tcls = pt->getClassRef(); + if (tcls && tcls->getClassType() == oClassRelay) { + int dummy; + tcls->splitLegNumberParallel(r->getLegNumber(), ln, dummy); + } + } + runnerScore[k].principalSort = runnerScore[k].principalSort * 50 + ln; + } + else + runnerScore[k].principalSort = 0; + + int from = getListParamTimeFromControl(); + if (from <= 0) { + runners[k]->tmpResult.startTime = r->getStartTime(); + } + else { + int rt; + RunnerStatus stat; + runners[k]->getSplitTime(from, stat, rt); + if (stat == StatusOK) + runners[k]->tmpResult.startTime = runners[k]->getStartTime() + rt; + else + runners[k]->tmpResult.startTime = runners[k]->getStartTime(); + } + prepareCalculations(*runners[k]); + runners[k]->tmpResult.runningTime = deduceTime(*runners[k], runners[k]->tmpResult.startTime); + runners[k]->tmpResult.status = deduceStatus(*runners[k]); + runners[k]->tmpResult.points = deducePoints(*runners[k]); + + runnerScore[k].score = score(*runners[k], runners[k]->tmpResult.status, + runners[k]->tmpResult.runningTime, + runners[k]->tmpResult.points, false); + + storeOutput(runners[k]->tmpResult.outputTimes, + runners[k]->tmpResult.outputNumbers); + + runnerScore[k].tr = runners[k]; + + } + + ::sort(runnerScore.begin(), runnerScore.end()); + int place = 1; + int iPlace = 1; + int leadtime = 0; + for (size_t k = 0; k < runnerScore.size(); k++) { + if (k>0 && runnerScore[k-1].principalSort != runnerScore[k].principalSort) { + place = 1; + iPlace = 1; + } + else if (k>0 && runnerScore[k-1].score != runnerScore[k].score) { + place = iPlace; + } + + if (runnerScore[k].tr->tmpResult.status == StatusOK) { + runnerScore[k].tr->tmpResult.place = place; + iPlace++; + if (place == 1) { + leadtime = runnerScore[k].tr->tmpResult.runningTime; + runnerScore[k].tr->tmpResult.timeAfter = 0; + } + else { + runnerScore[k].tr->tmpResult.timeAfter = runnerScore[k].tr->tmpResult.runningTime - leadtime; + } + } + else { + runnerScore[k].tr->tmpResult.place = 0; + runnerScore[k].tr->tmpResult.timeAfter = 0; + } + } + + if (sortRunners) { + for (size_t k = 0; k < runnerScore.size(); k++) { + runners[k] = (oRunner *)runnerScore[k].tr; + } + } +} + +void GeneralResult::prepareCalculations(oEvent &oe, bool prepareForTeam, int inputNumber) const { +} + +void GeneralResult::prepareCalculations(oTeam &team) const { + int nr = team.getNumRunners(); + for (int j = 0; j < nr; j++) { + pRunner r = team.getRunner(j); + if (r) { + prepareCalculations(*r); + r->tmpResult.runningTime = deduceTime(*r, r->getStartTime()); //XXX + r->tmpResult.status = deduceStatus(*r); + r->tmpResult.place = 0;//XXX? + r->tmpResult.timeAfter = 0;//XXX? + r->tmpResult.points = deducePoints(*r); + r->tmpResult.internalScore = score(*r, r->tmpResult.status, + r->tmpResult.runningTime, + r->tmpResult.points, true); + + storeOutput(r->tmpResult.outputTimes, + r->tmpResult.outputNumbers); + } + } +} + +void GeneralResult::prepareCalculations(oRunner &runner) const { + int from = getListParamTimeFromControl(); + runner.tmpResult.startTime = runner.getStartTime(); + + if (from>0) { + int rt; + RunnerStatus stat; + runner.getSplitTime(from, stat, rt); + if (stat == StatusOK) + runner.tmpResult.startTime += rt; + } +} + +void GeneralResult::storeOutput(vector ×, vector &numbers) const { +} + +int GeneralResult::score(oTeam &team, RunnerStatus st, int rt, int points) const { + return (100*RunnerStatusOrderMap[st] + team.getNumShortening()) * 900000 + rt; +} + +RunnerStatus GeneralResult::deduceStatus(oTeam &team) const { + return team.getStatus(); +} + +int GeneralResult::deduceTime(oTeam &team) const { + return team.getRunningTime(); +} + +int GeneralResult::deducePoints(oTeam &team) const { + return team.getRogainingPoints(false); +} + +int GeneralResult::score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const { + if (asTeamMember) { + return runner.getLegNumber(); + } + else + return (RunnerStatusOrderMap[st]*100 + runner.getNumShortening()) * 900000 + time; +} + +RunnerStatus GeneralResult::deduceStatus(oRunner &runner) const { + return runner.getStatus(); +} + +int GeneralResult::deduceTime(oRunner &runner, int startTime) const { + return runner.getRunningTime(); +} + +int GeneralResult::deducePoints(oRunner &runner) const { + return runner.getRogainingPoints(false); +} + +int ResultAtControl::score(oTeam &team, RunnerStatus st, int time, int points) const { + return GeneralResult::score(team, st, time, points); +} + +RunnerStatus ResultAtControl::deduceStatus(oTeam &team) const { + return GeneralResult::deduceStatus(team); +} + +int ResultAtControl::deduceTime(oTeam &team) const { + return GeneralResult::deduceTime(team); +} + +int ResultAtControl::deducePoints(oTeam &team) const { + return GeneralResult::deducePoints(team); +} + +int ResultAtControl::score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const { + if (asTeamMember) + return runner.getLegNumber(); + const int TK = 3600 * 100; + if (st == StatusOK) + return time; + else + return TK + st; +} + +RunnerStatus TotalResultAtControl::deduceStatus(oRunner &runner) const { + RunnerStatus singleStat = ResultAtControl::deduceStatus(runner); + if (singleStat != StatusOK) + return singleStat; + + RunnerStatus inputStatus = StatusOK; + if (runner.getTeam() && getListParamTimeFromControl() <= 0) { + // Only use input time when start time is used + const pTeam t = runner.getTeam(); + if (runner.getLegNumber()>0 && t->getClassRef()) { + // Find base leg + int legIx = runner.getLegNumber(); + const pClass cls = t->getClassRef(); + while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx))) + legIx--; + if (legIx > 0) + inputStatus = t->getLegStatus(legIx-1, true); + } + else { + inputStatus = t->getInputStatus(); + } + } + else { + inputStatus = runner.getInputStatus(); + } + + return inputStatus; // Single status is OK. +} + +int TotalResultAtControl::deduceTime(oRunner &runner, int startTime) const { + int singleTime = ResultAtControl::deduceTime(runner, startTime); + + if (singleTime == 0) + return 0; + + int inputTime = 0; + if (runner.getTeam() && getListParamTimeFromControl() <= 0) { + // Only use input time when start time is used + const pTeam t = runner.getTeam(); + if (runner.getLegNumber()>0 && t->getClassRef()) { + // Find base leg + int legIx = runner.getLegNumber(); + const pClass cls = t->getClassRef(); + while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx))) + legIx--; + if (legIx > 0) + inputTime = t->getLegRunningTime(legIx-1, true); + } + else { + inputTime = t->getInputTime(); + } + } + else { + inputTime = runner.getInputTime(); + } + + return singleTime + inputTime; +} + +int TotalResultAtControl::score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const { + if (asTeamMember) + return runner.getLegNumber(); + const int TK = 3600 * 100; + RunnerStatus inputStatus = StatusOK; + + if (runner.getTeam()) { + const pTeam t = runner.getTeam(); + if (runner.getLegNumber()>0) { + inputStatus = t->getLegStatus(runner.getLegNumber()-1, true); + } + else { + inputStatus = t->getInputStatus(); + } + } + else { + inputStatus = runner.getInputStatus(); + } + + if (st != StatusUnknown) + st = max(inputStatus, st); + + if (st == StatusOK) { + return time; + } + else + return TK + st; +} + +RunnerStatus ResultAtControl::deduceStatus(oRunner &runner) const { + int fc = getListParamTimeToControl(); + if (fc > 0) { + RunnerStatus stat; + int rt; + runner.getSplitTime(fc, stat, rt); + return stat; + } + RunnerStatus st = runner.getStatus(); + if (st == StatusUnknown && runner.getRunningTime() > 0) + return StatusOK; + return st; +} + +int ResultAtControl::deduceTime(oRunner &runner, int startTime) const { + int fc = getListParamTimeToControl(); + + if (fc > 0) { + RunnerStatus stat; + int rt; + runner.getSplitTime(fc, stat, rt); + + if (stat == StatusOK) + return runner.getStartTime() + rt - startTime; + } + else if (runner.getFinishTime() > 0) { + return runner.getFinishTime() - startTime; + } + + return 0; +} + +int ResultAtControl::deducePoints(oRunner &runner) const { + return 0; +} + +int DynamicResult::instanceCount = 0; +map DynamicResult::symb2Method; +map > DynamicResult::method2SymbName; + +DynamicResult::DynamicResult() { + builtIn = false; + readOnly = false; + isCompiled = false; + methods.resize(_Mlast); + instanceCount++; + + if (method2SymbName.empty()) { + addSymbol(MDeduceRStatus, "RunnerStatus", "Status calculation for runner"); + addSymbol(MDeduceRTime, "RunnerTime", "Time calculation for runner"); + addSymbol(MDeduceRPoints, "RunnerPoints", "Point calculation for runner"); + addSymbol(MRScore, "RunnerScore", "Result score calculation for runner"); + + addSymbol(MDeduceTStatus, "TeamStatus", "Status calculation for team"); + addSymbol(MDeduceTTime, "TeamTime", "Time calculation for team"); + addSymbol(MDeduceTPoints, "TeamPoints", "Point calculation for team"); + addSymbol(MTScore, "TeamScore", "Result score calculation for team"); + } +} + +DynamicResult::DynamicResult(const DynamicResult &resIn) { + instanceCount++; + isCompiled = false; + name = resIn.name; + tag = resIn.tag; + readOnly = false; + + description = resIn.description; + origin = resIn.origin; + timeStamp = resIn.timeStamp; + annotation = resIn.annotation; + builtIn = resIn.builtIn; + methods.resize(_Mlast); + for (size_t k = 0; k < methods.size(); k++) { + methods[k].source = resIn.methods[k].source; + methods[k].description = resIn.methods[k].description; + } +} + +void DynamicResult::operator=(const DynamicResult &resIn) { + isCompiled = false; + name = resIn.name; + tag = resIn.tag; + description = resIn.description; + origin = resIn.origin; + timeStamp = resIn.timeStamp; + annotation = resIn.annotation; + readOnly = resIn.readOnly; + builtIn = resIn.builtIn; + methods.resize(_Mlast); + for (size_t k = 0; k < methods.size(); k++) { + methods[k].source = resIn.methods[k].source; + methods[k].description = resIn.methods[k].description; + methods[k].pn = 0; + } + +} + +void DynamicResult::addSymbol(DynamicMethods method, const char *symb, const char *name) { + if (method2SymbName.count(method) || symb2Method.count(symb)) + throw meosException("Method symbol used"); + method2SymbName[method] = make_pair(symb, name); + symb2Method[symb] = method; +} + +DynamicResult::~DynamicResult() { + instanceCount--; + if (instanceCount == 0) { + method2SymbName.clear(); + symb2Method.clear(); + } +} + +DynamicResult::MethodInfo::MethodInfo() { + pn = 0; +} + +DynamicResult::MethodInfo::~MethodInfo() { +} + +const ParseNode *DynamicResult::getMethod(DynamicMethods method) const { + return methods[method].pn; +} + +const string &DynamicResult::getMethodSource(DynamicMethods method) const { + return methods[method].source; +} + +void DynamicResult::setMethodSource(DynamicMethods method, const string &source) { + methods[method].source = source; + methods[method].pn = 0; + methods[method].pn = parser.parse(source); +} + +RunnerStatus DynamicResult::toStatus(int status) const { + switch (status) { + case StatusUnknown: + return StatusUnknown; + case StatusOK: + return StatusOK; + case StatusMP: + return StatusMP; + case StatusDNF: + return StatusDNF; + case StatusDNS: + return StatusDNS; + case StatusNotCompetiting: + return StatusNotCompetiting; + case StatusDQ: + return StatusDQ; + case StatusMAX: + return StatusMAX; + default: + throw meosException("Unknown status code X#" + itos(status)); + } +} + +int DynamicResult::score(oTeam &team, RunnerStatus st, int time, int points) const { + if (getMethod(MTScore)) { + parser.addSymbol("ComputedTime", time); + parser.addSymbol("ComputedStatus", st); + parser.addSymbol("ComputedPoints", points); + return getMethod(MTScore)->evaluate(parser); + } + else if (getMethodSource(MTScore).empty()) + return GeneralResult::score(team, st, time, points); + else throw meosException("Syntax error"); +} + +RunnerStatus DynamicResult::deduceStatus(oTeam &team) const { + if (getMethod(MDeduceTStatus)) + return toStatus(getMethod(MDeduceTStatus)->evaluate(parser)); + else if (getMethodSource(MDeduceTStatus).empty()) + return GeneralResult::deduceStatus(team); + else throw meosException("Syntax error"); +} + +int DynamicResult::deduceTime(oTeam &team) const { + if (getMethod(MDeduceTTime)) + return getMethod(MDeduceTTime)->evaluate(parser); + else if (getMethodSource(MDeduceTTime).empty()) + return GeneralResult::deduceTime(team); + else throw meosException("Syntax error"); +} + +int DynamicResult::deducePoints(oTeam &team) const { + if (getMethod(MDeduceTPoints)) + return getMethod(MDeduceTPoints)->evaluate(parser); + else if (getMethodSource(MDeduceTPoints).empty()) + return GeneralResult::deducePoints(team); + else throw meosException("Syntax error"); +} + +int DynamicResult::score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const { + if (getMethod(MRScore)) { + parser.addSymbol("ComputedTime", time); + parser.addSymbol("ComputedStatus", st); + parser.addSymbol("ComputedPoints", points); + return getMethod(MRScore)->evaluate(parser); + } + else if (getMethodSource(MRScore).empty()) + return GeneralResult::score(runner, st, time, points, asTeamMember); + else throw meosException("Syntax error"); +} + +RunnerStatus DynamicResult::deduceStatus(oRunner &runner) const { + if (getMethod(MDeduceRStatus)) + return toStatus(getMethod(MDeduceRStatus)->evaluate(parser)); + else if (getMethodSource(MDeduceRStatus).empty()) + return GeneralResult::deduceStatus(runner); + else throw meosException("Syntax error"); +} + +int DynamicResult::deduceTime(oRunner &runner, int startTime) const { + if (getMethod(MDeduceRTime)) + return getMethod(MDeduceRTime)->evaluate(parser); + else if (getMethodSource(MDeduceRTime).empty()) + return GeneralResult::deduceTime(runner, startTime); + else throw meosException("Syntax error"); +} + +int DynamicResult::deducePoints(oRunner &runner) const { + if (getMethod(MDeduceRPoints)) + return getMethod(MDeduceRPoints)->evaluate(parser); + else if (getMethodSource(MDeduceRPoints).empty()) + return GeneralResult::deducePoints(runner); + else throw meosException("Syntax error"); + +} + +void DynamicResult::save(const string &file) const { + xmlparser xml(0); + xml.openOutput(file.c_str(), true); + save(xml); + xml.closeOut(); +} + +extern oEvent *gEvent; + +void DynamicResult::save(xmlparser &xml) const { + xml.startTag("MeOSResultCalculationSet"); + xml.write("Name", name); + xml.write("Tag", tag); + xml.write("Description", description); + if (origin.empty()) + origin = gEvent->getName() + " (" + getLocalDate() + ")"; + xml.write("Origin", origin); + xml.write("Date", getLocalTime()); +// xml.write("Tag", tag); +// xml.write("UID", getUniqueId()); + + for (map::const_iterator it = symb2Method.begin(); it != symb2Method.end(); ++it) { + if (!methods[it->second].source.empty()) { + xml.startTag("Rule", "name", it->first); + xml.write("Description", methods[it->second].description); + xml.write("Method", methods[it->second].source); + xml.endTag(); + } + } + xml.endTag(); +} + +void DynamicResult::clear() { + parser.clear(); + for (size_t k = 0; k < methods.size(); k++) { + methods[k].pn = 0; + methods[k].source.clear(); + methods[k].description.clear(); + } +} + +void DynamicResult::load(const string &file) { + xmlparser xml(0); + xml.read(file.c_str()); + xmlobject xDef = xml.getObject("MeOSResultCalculationSet"); + load(xDef); +} + +void DynamicResult::load(const xmlobject &xDef) { + if (!xDef) + throw meosException("Ogiltigt filformat"); + + clear(); + + xDef.getObjectString("Name", name); + xDef.getObjectString("Description", description); + xDef.getObjectString("Tag", tag); + + xDef.getObjectString("Origin", origin); + xDef.getObjectString("Date", timeStamp); + //xDef.getObjectString("UID", uniqueIndex); + xmlList rules; + xDef.getObjects("Rule", rules); + for (size_t k = 0; k < rules.size(); k++) { + string rn; + rules[k].getObjectString("name", rn); + map::const_iterator res = symb2Method.find(rn); + if (res == symb2Method.end()) + throw meosException("Unknown result rule X.#" + rn); + + rules[k].getObjectString("Description", methods[res->second].description); + rules[k].getObjectString("Method", methods[res->second].source); + } +} + +void DynamicResult::compile(bool forceRecompile) const { + if (isCompiled) + return; + + for (size_t k = 0; k < methods.size(); k++) { + methods[k].pn = 0; + } + parser.clear(); + + pair err; + for (size_t k = 0; k < methods.size(); k++) { + if (!methods[k].source.empty()) { + try { + methods[k].pn = parser.parse(methods[k].source); + } + catch (const meosException &ex) { + if (err.first.empty()) { + err.first = method2SymbName[DynamicMethods(k)].second; + err.second = lang.tl(ex.what()); + } + } + } + } + if (!err.first.empty()) { + throw meosException("Error in result module X, method Y (Z)#" + name + "#" + err.first + "#" + err.second); + } +} + +void DynamicResult::getMethodTypes(vector< pair > &mt) const { + mt.clear(); + for (map >::const_iterator it = method2SymbName.begin(); it != method2SymbName.end(); ++it) + mt.push_back(make_pair(it->first, it->second.second)); + + return; +} + +void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const { + if (clear) + parser.clearSymbols(); + const bool isRunner = m == MRScore || + m == MDeduceRPoints || + m == MDeduceRStatus || + m == MDeduceRTime; + + parser.declareSymbol("Status", "Runner/team status", false); + parser.declareSymbol("Start", "Runner/team start time", false); + parser.declareSymbol("Finish", "Runner/team finish time", false); + parser.declareSymbol("Time", "Runner/team running time", false); + parser.declareSymbol("Place", "Runner/team place", false); + parser.declareSymbol("Points", "Runner/team rogaining points", false); + parser.declareSymbol("PointReduction", "Automatic rogaining point reduction", false); + parser.declareSymbol("PointOvertime", "Runner/team rogaining overtime", false); + parser.declareSymbol("PointGross", "Rogaining points before automatic reduction", false); + + parser.declareSymbol("PointAdjustment", "Runner/team rogaining points adjustment", false); + parser.declareSymbol("TimeAdjustment", "Runner/team time adjustment", false); + + parser.declareSymbol("TotalStatus", "Runner/team total status", false); + parser.declareSymbol("TotalTime", "Runner/team total running time", false); + parser.declareSymbol("TotalPlace", "Runner/team total place", false); + + parser.declareSymbol("InputStatus", "Runner/team input status", false); + parser.declareSymbol("InputTime", "Runner/team input running time", false); + parser.declareSymbol("InputPlace", "Runner/team input place", false); + parser.declareSymbol("InputPoints", "Runner/team input points", false); + + parser.declareSymbol("Fee", "Runner/team fee", false); + + parser.declareSymbol("ClubId", "Club id number", false); + parser.declareSymbol("DistrictId", "District id number", false); + parser.declareSymbol("Bib", "Nummerlapp", false); + + parser.declareSymbol("InputNumber", "User input number", false); + parser.declareSymbol("Shorten", "Number of shortenings", false); + + if (isRunner) { + parser.declareSymbol("CardPunches", "Runner's card, punch codes", true); + parser.declareSymbol("CardTimes", "Runner's card, punch times", true); + parser.declareSymbol("CardControls", "Runner's card, matched control ids (-1 for unmatched punches)", true); + + parser.declareSymbol("Course", "Runner's course", true); + parser.declareSymbol("CourseLength", "Length of course", false); + + parser.declareSymbol("SplitTimes", "Runner's split times", true); + parser.declareSymbol("SplitTimesAccumulated", "Runner's total running time to control", true); + + parser.declareSymbol("LegTimeDeviation", "Deviation +/- from expected time on course leg", true); + parser.declareSymbol("LegTimeAfter", "Time after leg winner", true); + parser.declareSymbol("LegPlace", "Place on course leg", true); + parser.declareSymbol("Leg", "Leg number in team, zero indexed", false); + parser.declareSymbol("BirthYear", "Year of birth", false); + } + else { + parser.declareSymbol("RunnerStatus", "Status for each team member", true); + parser.declareSymbol("RunnerTime", "Running time for each team member", true); + parser.declareSymbol("RunnerStart", "Start time for each team member", true); + parser.declareSymbol("RunnerFinish", "Finish time for each team member", true); + parser.declareSymbol("RunnerPoints", "Rogaining points for each team member", true); + + parser.declareSymbol("RunnerCardPunches", "Punch codes for each team member", true, true); + parser.declareSymbol("RunnerCardTimes", "Punch times for each team member", true, true); + parser.declareSymbol("RunnerCardControls", "Matched control ids (-1 for unmatched) for each team member", true, true); + + parser.declareSymbol("RunnerCourse", "Runner's course", true, true); + parser.declareSymbol("RunnerSplitTimes", "Runner's split times", true, true); + + parser.declareSymbol("RunnerOutputTimes", "Runner's method output times", true, true); + parser.declareSymbol("RunnerOutputNumbers", "Runner's method output numbers", true, true); + } + + parser.declareSymbol("MaxTime", "Maximum allowed running time", false); + + parser.declareSymbol("StatusUnknown", "Status code for an unknown result", false); + parser.declareSymbol("StatusOK", "Status code for a valid result", false); + parser.declareSymbol("StatusMP", "Status code for a missing punch", false); + parser.declareSymbol("StatusDNF", "Status code for not finishing", false); + parser.declareSymbol("StatusDNS", "Status code for not starting", false); + parser.declareSymbol("StatusMAX", "Status code for a time over the maximum", false); + parser.declareSymbol("StatusDQ", "Status code for disqualification", false); + parser.declareSymbol("StatusNotCompetiting", "Status code for not competing", false); + + parser.declareSymbol("ShortestClassTime", "Shortest time in class", false); + + if (m == MRScore || m == MTScore) { + parser.declareSymbol("ComputedTime", "Time as computed by your time method", false); + parser.declareSymbol("ComputedPoints", "Points as computed by your point method", false); + parser.declareSymbol("ComputedStatus", "Status as computed by your status method", false); + } +} + +void DynamicResult::getSymbols(vector< pair > &symb) const { + parser.getSymbols(symb); +} + +void DynamicResult::getSymbolInfo(int ix, string &name, string &desc) const { + parser.getSymbolInfo(ix, name, desc); +} + +void DynamicResult::prepareCalculations(oEvent &oe, bool prepareForTeam, int inputNumber) const { + compile(false); + oe.calculateResults(oEvent::RTClassResult); + oe.calculateResults(oEvent::RTTotalResult); + + declareSymbols(MRScore, true); + if (prepareForTeam) { + declareSymbols(MTScore, false); + vector t; + oe.getTeams(0, t, false); + for (size_t k = 0; k < t.size(); k++) + t[k]->resetResultCalcCache(); + + oe.calculateTeamResults(false); + oe.calculateTeamResults(true); + } + parser.addSymbol("StatusUnknown", StatusUnknown); + parser.addSymbol("StatusOK", StatusOK); + parser.addSymbol("StatusMP", StatusMP); + parser.addSymbol("StatusDNF", StatusDNF); + parser.addSymbol("StatusDNS", StatusDNS); + parser.addSymbol("StatusMAX", StatusMAX); + parser.addSymbol("StatusDQ", StatusDQ); + parser.addSymbol("StatusNotCompetiting", StatusNotCompetiting); + + parser.addSymbol("MaxTime", oe.getMaximalTime()); + parser.addSymbol("InputNumber", inputNumber); +} + +void DynamicResult::prepareCommon(oAbstractRunner &runner) const { + parser.clearVariables(); + int st = runner.getStatus(); + int ft = runner.getFinishTime(); + if (st == StatusUnknown && ft>0) + st = StatusOK; + parser.addSymbol("Status", st); + parser.addSymbol("Start", runner.getStartTime()); + parser.addSymbol("Finish", ft); + parser.addSymbol("Time", runner.getRunningTime()); + parser.addSymbol("Place", runner.getPlace()); + parser.addSymbol("Points", runner.getRogainingPoints(false)); + parser.addSymbol("PointReduction", runner.getRogainingReduction()); + parser.addSymbol("PointOvertime", runner.getRogainingOvertime()); + parser.addSymbol("PointGross", runner.getRogainingPointsGross()); + + parser.addSymbol("PointAdjustment", runner.getPointAdjustment()); + parser.addSymbol("TimeAdjustment", runner.getTimeAdjustment()); + + parser.addSymbol("TotalStatus", runner.getTotalStatus()); + parser.addSymbol("TotalTime", runner.getTotalRunningTime()); + parser.addSymbol("TotalPlace", runner.getTotalPlace()); + + parser.addSymbol("InputStatus", runner.getInputStatus()); + parser.addSymbol("InputTime", runner.getInputTime()); + parser.addSymbol("InputPlace", runner.getInputPlace()); + parser.addSymbol("InputPoints", runner.getInputPoints()); + parser.addSymbol("Shorten", runner.getNumShortening()); + + parser.addSymbol("Fee", runner.getDCI().getInt("Fee")); + + const pClub pc = runner.getClubRef(); + if (pc) { + parser.addSymbol("ClubId", pc->getId()); + parser.addSymbol("DistrictId", pc->getDCI().getInt("District")); + } + else { + parser.addSymbol("ClubId", 0); + parser.addSymbol("DistrictId", 0); + } + parser.addSymbol("Bib", atoi(runner.getBib().c_str())); +} + +void DynamicResult::prepareCalculations(oTeam &team) const { + GeneralResult::prepareCalculations(team); + prepareCommon(team); + int nr = team.getNumRunners(); + vector status(nr), time(nr), start(nr), finish(nr), points(nr); + vector< vector > runnerOutputTimes(nr); + vector< vector > runnerOutputNumbers(nr); + + for (int k = 0; k < nr; k++) { + pRunner r = team.getRunner(k); + if (r) { + oAbstractRunner::TempResult &res = r->getTempResult(); + status[k] = res.getStatus(); + time[k] = res.getRunningTime(); + if (time[k] > 0 && status[k] == StatusUnknown) + status[k] = StatusOK; + start[k] = res.getStartTime(); + finish[k] = res.getFinishTime(); + points[k] = res.getPoints(); + runnerOutputTimes[k] = res.outputTimes; + runnerOutputNumbers[k] = res.outputNumbers; + } + } + parser.removeSymbol("CardControls"); + parser.removeSymbol("CardPunches"); + parser.removeSymbol("CardTimes"); + parser.removeSymbol("Course"); + parser.removeSymbol("CourseLength"); + parser.removeSymbol("LegPlace"); + parser.removeSymbol("LegTimeAfter"); + parser.removeSymbol("LegTimeDeviation"); + parser.removeSymbol("Leg"); + parser.removeSymbol("SplitTimes"); + parser.removeSymbol("SplitTimesAccumulated"); + parser.removeSymbol("LegTimeDeviation"); + parser.removeSymbol("BirthYear"); + + parser.addSymbol("RunnerOutputNumbers", runnerOutputNumbers); + parser.addSymbol("RunnerOutputTimes", runnerOutputTimes); + + parser.addSymbol("RunnerStatus", status); + parser.addSymbol("RunnerTime", time); + parser.addSymbol("RunnerStart", start); + parser.addSymbol("RunnerFinish", finish); + parser.addSymbol("RunnerPoints", points); + + parser.addSymbol("RunnerCardPunches", team.getResultCache(oTeam::RCCCardPunches)); + parser.addSymbol("RunnerCardTimes", team.getResultCache(oTeam::RCCCardTimes)); + parser.addSymbol("RunnerCardControls", team.getResultCache(oTeam::RCCCardControls)); + + parser.addSymbol("RunnerCourse", team.getResultCache(oTeam::RCCCourse)); + parser.addSymbol("RunnerSplitTimes", team.getResultCache(oTeam::RCCSplitTime)); + + pClass cls = team.getClassRef(); + if (cls) { + int nl = max(1, cls->getNumStages()-1); + parser.addSymbol("ShortestClassTime", cls->getTotalLegLeaderTime(nl, false)); + + } +} + +void DynamicResult::prepareCalculations(oRunner &runner) const { + GeneralResult::prepareCalculations(runner); + prepareCommon(runner); + pCard pc = runner.getCard(); + if (pc) { + vector punches; + pc->getPunches(punches); + int np = 0; + for (size_t k = 0; k < punches.size(); k++) { + if (punches[k]->getTypeCode() >= 30) + np++; + } + vector times(np); + vector codes(np); + vector controls(np); + int ip = 0; + for (size_t k = 0; k < punches.size(); k++) { + if (punches[k]->getTypeCode() >= 30) { + times[ip] = punches[k]->getAdjustedTime(); + codes[ip] = punches[k]->getTypeCode(); + controls[ip] = punches[k]->isUsedInCourse() ? punches[k]->getControlId() : -1; + ip++; + } + } + parser.addSymbol("CardPunches", codes); + parser.addSymbol("CardTimes", times); + parser.addSymbol("CardControls", controls); + + pTeam t = runner.getTeam(); + if (t) { + int leg = runner.getLegNumber(); + t->setResultCache(oTeam::RCCCardTimes, leg, times); + t->setResultCache(oTeam::RCCCardPunches, leg, codes); + t->setResultCache(oTeam::RCCCardControls, leg, controls); + } + } + else { + vector e; + parser.addSymbol("CardPunches", e); + parser.addSymbol("CardTimes", e); + parser.addSymbol("CardControls", e); + } + + pCourse crs = runner.getCourse(true); + const vector &sp = runner.getSplitTimes(false); + + if (crs) { + vector eCrs; + vector eSplitTime; + vector eAccTime; + eCrs.reserve(crs->getNumControls()); + eSplitTime.reserve(crs->getNumControls()); + eAccTime.reserve(crs->getNumControls()); + int start = runner.getStartTime(); + int st = runner.getStartTime(); + for (int k = 0; k < crs->getNumControls(); k++) { + pControl ctrl = crs->getControl(k); + if (ctrl->isSingleStatusOK()) { + eCrs.push_back(ctrl->getFirstNumber()); + if (size_t(k) < sp.size()) { + if (sp[k].status == SplitData::OK) { + eAccTime.push_back(sp[k].time-start); + eSplitTime.push_back(sp[k].time-st); + st = sp[k].time; + } + else if (sp[k].status == SplitData::NoTime) { + eAccTime.push_back(st-start); + eSplitTime.push_back(0); + } + else if (sp[k].status == SplitData::Missing) { + eAccTime.push_back(0); + eSplitTime.push_back(-1); + } + } + } + } + if (runner.getFinishTime() > 0) { + eAccTime.push_back(runner.getFinishTime()-start); + eSplitTime.push_back(runner.getFinishTime()-st); + } + else if (!eAccTime.empty()) { + eAccTime.push_back(0); + eSplitTime.push_back(-1); + } + + parser.addSymbol("CourseLength", crs->getLength()); + parser.addSymbol("Course", eCrs); + parser.addSymbol("SplitTimes", eSplitTime); + parser.addSymbol("SplitTimesAccumulated", eAccTime); + pTeam t = runner.getTeam(); + if (t) { + int leg = runner.getLegNumber(); + t->setResultCache(oTeam::RCCCourse, leg, eCrs); + t->setResultCache(oTeam::RCCSplitTime, leg, eSplitTime); + } + } + else { + vector e; + parser.addSymbol("CourseLength", -1); + parser.addSymbol("Course", e); + parser.addSymbol("SplitTimes", e); + parser.addSymbol("SplitTimesAccumulated", e); + } + + pClass cls = runner.getClassRef(); + if (cls) { + int nl = runner.getLegNumber(); + parser.addSymbol("ShortestClassTime", cls->getBestLegTime(nl)); + } + vector delta; + vector place; + vector after; + runner.getSplitAnalysis(delta); + runner.getLegTimeAfter(after); + runner.getLegPlaces(place); + + parser.addSymbol("LegTimeDeviation", delta); + parser.addSymbol("LegTimeAfter", after); + parser.addSymbol("LegPlace", place); + parser.addSymbol("Leg", runner.getLegNumber()); + parser.addSymbol("BirthYear", runner.getBirthYear()); +} + +void DynamicResult::storeOutput(vector ×, vector &numbers) const { + parser.takeVariable("OutputTimes", times); + parser.takeVariable("OutputNumbers", numbers); +} + +int checksum(const string &str); + +long long DynamicResult::getHashCode() const { + long long hc = 1; + for (size_t k = 0; k < methods.size(); k++) { + hc = hc * 997 + checksum(methods[k].source); + } + return hc; +} + +string DynamicResult::undecorateTag(const string &inputTag) { + int ix = inputTag.rfind("-v"); + if (ix > 0 && ix != inputTag.npos) + return inputTag.substr(0, ix); + else + return inputTag; +} + +string DynamicResult::getName(bool withAnnotation) const { + if (annotation.empty() || !withAnnotation) + return name; + else + return name + " (" + annotation + ")"; +} + +void DynamicResult::debugDumpVariables(gdioutput &gdi, bool includeSymbols) const { + gdi.fillDown(); + gdi.dropLine(); + int c1 = gdi.getCX(); + int c2 = c1 + gdi.scaleLength(170); + if (includeSymbols) { + gdi.addString("", 1, "Symboler"); + parser.dumpSymbols(gdi, c1, c2); + gdi.dropLine(); + } + else { + gdi.addString("", 1, "Variabler"); + parser.dumpVariables(gdi, c1, c2); + gdi.dropLine(); + } +} diff --git a/code/generalresult.h b/code/generalresult.h new file mode 100644 index 0000000..75b3e6e --- /dev/null +++ b/code/generalresult.h @@ -0,0 +1,221 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "oBase.h" +#include "parser.h" +#include "oListInfo.h" + +class oAbstractRunner; +class oTeam; +class oRunner; +struct oListParam; +class xmlparser; +class xmlobject; + +class GeneralResult +{ +private: + const oListParam *context; + +protected: + + enum PrincipalSort {None, ClassWise, CourseWise}; + + virtual PrincipalSort getPrincipalSort() const {return ClassWise;} + + virtual int score(oTeam &team, RunnerStatus st, int time, int points) const; + virtual RunnerStatus deduceStatus(oTeam &team) const; + virtual int deduceTime(oTeam &team) const; + virtual int deducePoints(oTeam &team) const; + + virtual int score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const; + virtual RunnerStatus deduceStatus(oRunner &runner) const; + virtual int deduceTime(oRunner &runner, int startTime) const; + virtual int deducePoints(oRunner &runner) const; + + virtual void prepareCalculations(oEvent &oe, bool prepareForTeam, int inputNumber) const; + virtual void prepareCalculations(oTeam &team) const; + virtual void prepareCalculations(oRunner &runner) const; + virtual void storeOutput(vector ×, vector &numbers) const; + + int getListParamTimeToControl() const; + int getListParamTimeFromControl() const; + +public: + + void setContext(const oListParam *context); + void clearContext(); + + void calculateTeamResults(vector &teams, oListInfo::ResultType resType, bool sortTeams, int inputNumber) const; + void calculateIndividualResults(vector &runners, oListInfo::ResultType resType, bool sortRunners, int inputNumber) const; + void sortTeamMembers(vector &runners) const; + + template void sort(vector &rt, SortOrder so) const; + + GeneralResult(void); + virtual ~GeneralResult(void); +}; + +class ResultAtControl : public GeneralResult { +protected: + int score(oTeam &team, RunnerStatus st, int time, int points) const; + RunnerStatus deduceStatus(oTeam &team) const; + int deduceTime(oTeam &team) const; + int deducePoints(oTeam &team) const; + + int score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const; + RunnerStatus deduceStatus(oRunner &runner) const; + int deduceTime(oRunner &runner, int startTime) const; + int deducePoints(oRunner &runner) const; +}; + +class TotalResultAtControl : public ResultAtControl { +protected: + int deduceTime(oRunner &runner, int startTime) const; + RunnerStatus deduceStatus(oRunner &runner) const; + int score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const; +}; + +class DynamicResult : public GeneralResult { +public: + + enum DynamicMethods { + MTScore, + MDeduceTStatus, + MDeduceTTime, + MDeduceTPoints, + + MRScore, + MDeduceRStatus, + MDeduceRTime, + MDeduceRPoints, + _Mlast + }; + +private: + + static map symb2Method; + static map > method2SymbName; + static int instanceCount; + + class MethodInfo { + string source; + mutable ParseNode *pn; + string description; + public: + friend class DynamicResult; + MethodInfo(); + ~MethodInfo(); + }; + + vector methods; + mutable bool isCompiled; + mutable Parser parser; + string name; + string tag; + string description; + string annotation; + mutable string origin; + string timeStamp; + bool builtIn; + mutable bool readOnly; + + + const ParseNode *getMethod(DynamicMethods method) const; + void addSymbol(DynamicMethods method, const char *symb, const char *name); + RunnerStatus toStatus(int status) const; + + void prepareCommon(oAbstractRunner &runner) const; + + static string getInternalPath(const string &tag); +public: + + void setReadOnly() const {readOnly = true;} + + bool isReadOnly() const {return readOnly;} + + const string &getTimeStamp() const {return timeStamp;} + + static string undecorateTag(const string &inputTag); + + long long getHashCode() const; + + void getSymbols(vector< pair > &symb) const; + void getSymbolInfo(int ix, string &name, string &desc) const; + + void declareSymbols(DynamicMethods m, bool clear) const; + + void prepareCalculations(oEvent &oe, bool prepareForTeam, int inputNumber) const; + void prepareCalculations(oTeam &team) const; + void prepareCalculations(oRunner &runner) const; + void storeOutput(vector ×, vector &numbers) const; + + int score(oTeam &team, RunnerStatus st, int time, int points) const; + RunnerStatus deduceStatus(oTeam &team) const; + int deduceTime(oTeam &team) const; + int deducePoints(oTeam &team) const; + + int score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const; + RunnerStatus deduceStatus(oRunner &runner) const; + int deduceTime(oRunner &runner, int startTime) const; + int deducePoints(oRunner &runner) const; + + DynamicResult(); + DynamicResult(const DynamicResult &resIn); + void operator=(const DynamicResult &ctr); + + ~DynamicResult(); + + bool hasMethod(DynamicMethods method) const {return getMethod(method) != 0;} + + + const string &getMethodSource(DynamicMethods method) const; + void setMethodSource(DynamicMethods method, const string &source); + + void getMethodTypes(vector< pair > &mt) const; + //const string &getMethodName(DynamicMethods method) const; + + const string &getTag() const {return tag;} + void setTag(const string &t) {tag = t;} + void setBuiltIn() {builtIn = true;} + bool isBuiltIn() const {return builtIn;} + string getName(bool withAnnotation) const; + void setName(const string &n) {name = n;} + void setAnnotation(const string &a) {annotation = a;} + const string &getDescription() const {return description;} + void setDescription(const string &n) {description = n;} + + void save(const string &file) const; + void save(xmlparser &xml) const; + + void load(const string &file); + void load(const xmlobject &xDef); + + void compile(bool forceRecompile) const; + + void debugDumpVariables(gdioutput &gdi, bool includeSymbols) const; + + void clear(); +}; + diff --git a/code/german.lng b/code/german.lng new file mode 100644 index 0000000..d6b52f7 --- /dev/null +++ b/code/german.lng @@ -0,0 +1,1027 @@ +%s m = %s m +%s meter = %s Meter +%s, block: %d = %s, Block: %d +X: Y. Tryck för att spara = X: Y. Zum Speichern Eingabetaste drücken +(lokalt) = (Lokal) +(okänd) stämplade vid = (Unbekannt) stempelte bei +(på server) = (am Server) +(sekunder) = (Sekunden) +Föregående = Vorhergehende +Lägg till = Hinzufügen +Lägg till alla = Alle hinzufügen +Lägg till stämpling = Stempel hinzufügen +ALLA( = Alle( +API-nyckel = API-Schlüssel +Adress = Adresse +Adress och kontakt = Adresse und Kontakt +Aktivera = Aktivieren +Alla deltagare måste ha ett namn = Alle Teilnehmer müssen einen Namen haben +Alla fakturor = Alle Rechnungen +Alla händelser = Alle Ereignisse +Alla lag måste ha ett namn = Alle Teams müssen einen Namen haben +Alla listor = Alle Listen +Alla lopp = Alle Läufe +Alla sträckor/lopp i separata filer = Alle Strecken/Läufe in seperaten Dateien +Alla typer = Alle Arten +Andel vakanser = Anteil an Vakantplätzen +Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar = Erste Startnummer angeben; leer lassen wenn keine Startnummern verwendet werden +Ange om kontrollen fungerar och hur den ska användas = Gebe an ob der Posten funktioniert und wie er verwendet werden soll +Anm. avg. = Nenng. +Anm. avgift = Nenngeld +Anm. datum = Angemeldet am +Anmälda = Nennungen +Anmälda per distrikt = Nennungen nach Region/Bundesland +Anmälningar = Nennungen +Anmälningar (IOF (xml) eller OE-CSV) = Nennungen (IOF (xml) oder OE-CSV) +Anmälningsavgift = Nenngeld +Anmälningsläge = Schneller Eingabemodus +Anslut = Verbinden +Anslut till en server = Verbindung mit einem Server herstellen +Ansluten till = Verbunden mit +Ansluter till Internet = Verbindet mit Internet +Anslutna klienter = Verbundene Klienten +Anslutningar = Verbindungen +Anslutningsinställningar = Verbindungseinstellungen +Antal = Anzahl +Antal besökare X, genomsnittlig bomtid Y, största bomtid Z = Anzahl Besucher X, durchschnittliche Fehlerzeit Y, größte Fehlerzeit Z +Antal ignorerade: X = Anzahl ignorierte Nennungen: X +Antal importerade = Anzahl importiert +Antal kartor = Anzahl Karten +Antal klasser = Anzahl Kategorien +Antal löpare = Anzahl Läufer +Antal misslyckade: X = Anzahl fehlgeschlagen: X +Antal startande per block = Anzahl Starter pro Startblock +Antal startande per intervall (inklusive redan lottade) = Anzahl Starter pro Intervall (inklusive bereits geloste) +Antal sträckor = Streckenanzahl +Antal vakanser = Anzahl Vakantplätze +Antal: %d = Anzahl: %d +Antal: X = Anzahl: X +Antalet rader i urklipp får inte plats i selektionen = Die Anzahl der Zeilen in der Zwischenablage passt nicht in die Auswahl +Använd Eventor = Eventor verwenden +Använd banpool = Bahnenpool verwenden +Använd löpardatabasen = Läuferdatenbank verwenden +Använd speakerstöd = Speakerunterstützung verwenden +Använd stor font = Große Schrift verwenden +Användarnamn = Benutzername +Arrangör = Veranstalter +Att betala = Offen +Att betala: X = Offen: X +Automater = Dienste +Automatisera = Automatisch +Automatisk lottning = Automatische Auslosung +Automatisk utskrift = Automatischer Druck +Automatisk utskrift / export = Automatischer Druck / Export +Av MeOS: www.melin.nu/meos = von MeOS: www.melin.nu/meos +Avancerat = Erweitert +Avbryt = Abbrechen +Avgift = Gebühr +Avgifter = Gebühren +Avgiftshöjning (procent) = Gebührenerhöhung (Prozent) +Avgjorda klasser (prisutdelningslista) = Fertige Kategorien (Siegerehrungsliste) +Avgjorda placeringar - %s = Endgültige Platzierungen - %s +Avgörande händelser = Entscheidende Ereignisse +Avgörs kl = Entschieden um +Avläsning/radiotider = Auslesen/Funkposten +Avmarkera allt = Alles demarkieren +Avrundad tävlingsavgift = Wettkampfgebühr, gerundet +Avsluta = Beenden +Bana = Bahn +Bana %d = Bahn %d +Banan används och kan inte tas bort = Die Bahn ist in Verwendung und kann nicht gelöscht werden +Banan måste ha ett namn = Die Bahn muss einen Namen haben +Banmall = Bahnvorlage +Banor = Bahnen +Banor (antal kontroller) = Bahnen (Anzahl Posten) +Banor för %s, sträcka %d = Bahnen für %s, Strecke %d +Banpool = Bahnenpool +Banpool, gemensam start = Bahnenpool, Massenstart +Banpool, lottad startlista = Bahnenpool, geloste Startliste +Bantilldelning = Bahnzuordnung +Bantilldelning, individuell = Bahnzuordnung, Einzel +Bantilldelning, stafett = Bahnzuordnung, Staffel +Bantilldelningslista - %s = Zugeordnete Bahnen - %s +Basintervall (min) = Basisintervall (min) +Begränsa antal per klass = Limitiere Anzahl pro Kategorie +Begränsa per klass = Limitiere pro Kategorie +Begränsning, antal visade per klass = Max. Anzahl angezeigte pro Kategorie +Behandlar löpardatabasen = Läuferdatenbank wird verarbeitet +Behandlar tävlingsdata = Wettkampfdaten werden verarbeitet +Bekräfta att %s byter klass till %s = Bitte bestätige, dass %s zur Kategorie %s wechselt +Bekräfta att deltagaren har lämnat återbud = Bitte bestätige, dass sich dieser Läufer abgemeldet hat +Betalat = Bezahlt +Betalningsinformation = Bezahlungsinformationen + +Bevakar händelser i X = Beobachte Ereignisse in X +Bevakningsprioritering = Wähle Läufer zum Beobachten + +Block = Block +Bläddra = Blättern +Bomfritt lopp / underlag saknas = Fehlerfreier Lauf / Daten fehlen +Bommade kontroller = Posten mit Fehlern +Bomtid = Zeit verloren +Bricka = SI-Card +Bricka %d används redan av %s och kan inte tilldelas = SI-Card %d ist in Verwendung von %s und kann nicht zugeteilt werden +Brickan redan inläst = SI-Card wurde bereits eingelesen +Brickhyra = Leihgebühr +Brickor = SI-Cards +Bygg databaser = Erstelle Datenbanken +COM-Port = COM-Schnittstelle +Databasanslutning = Datenbankverbindung +Datorröst som läser upp förvarningar = Computerstimme liest Läufer bei Funkposten vor +Datum = Datum +Dela = Teilen +Deltagare = Teilnehmer +Deltagare %d = Teilnehmer %d +Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = 'X' startet in der Paarlaufkategorie 'Y', hat aber keinen Partner. Das Ergebnis in dieser Kategorie kann daher fehlerhaft sein +Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = 'X' startet in der Staffelkategorie 'Y', hat aber kein Team. Das Ergebnis in dieser Kategorie kann daher fehlerhaft sein +Deltagaren 'X' saknar klass = 'X' ist keiner Kategorie zugeteilt +Destinationskatalog = Zielordner +Det här programmet levereras utan någon som helst garanti. Programmet är = Dieses Programm kommt ohne jegliche Garantie. +Direktanmälan = Direktanmeldung +Disk. = Disqu. +Distriktskod = Regionnummer +Du kan importera banor och klasser från OCADs exportformat = Bahnen und Kategorie können aus OCAD exportiert und in MeOS importiert werden +Du måste välja en klass = Es muss eine Kategorie ausgewählt werden +E-post = E-Mail +Efter = Rückstand +Efteranmälda (efter ordinarie) = Nachnennungen (hinten) +Efteranmälda (före ordinarie) = Nachnennungen (vorne) +Efteranmälda före ordinarie = Nachnennungen vorne +Egen listrubrik = Benutzerdefinierter Titel +Eget fönster = Neues Fenster +Ej lottade = Nicht geloste +Ej lottade, efter = Nicht geloste, hinten +Ej lottade, före = Nicht geloste, vorne +Ej start = Nicht Ang. +Ej tidtagning = Ohne Zeitnehmung +Ekonomisk sammanställning = Gebührenübersicht +Elit = Elite +Elitavgift = Elitegebühr +Elitklasser = Elitekategorien +En klubb kan inte slås ihop med sig själv = Ein Verein kann nicht mit sich selbst zusammengefügt werden +Endast en bana = Nur eine Bahn +Enhetstyp = Einheit +Eventorkoppling = Eventorverbindung +Export av resultat/sträcktider = Ergebnisse/Zwischenzeiten exportieren +Exportera = Exportieren +Exportera / Säkerhetskopiera = Exportieren / Sicherheitskopie erstellen +Exportera datafil = Daten exportieren +Exportera inställningar och löpardatabaser = Einstellungen und Datenbanken exportieren +Exportera löpardatabas = Läuferdatenbank exportieren +Exportera nu = Jetzt exportieren +Exportera resultat på fil = Ergebnisse exportieren und als Datei speichern +Exportera startlista på fil = Startliste exportieren und als Datei speichern +Exportera sträcktider = Zwischenzeiten exportieren +Exportera tävlingsdata = Wettkampfdaten exportieren +Externt Id = Externe ID +Extra = Extra +Extra stämplingar = Zusätzliche Stempel +Extralöparstafett = Staffel mit zusätzlichen Läufern auf einer Strecke +FAKTURA = RECHNUNG +FEL, inget svar = Fehler, keine Antwort +FEL: Porten kunde inte öppnas = Fehler: Schnittstelle konnte nicht geöffnet werden +Failed to generate card = Cardgenerierung fehlgeschlagen +Faktura = Rechnung +Faktura nr = Rechnungsnummer +Faktureras = Wird in Rechnung gestellt +Fakturor = Rechnungen +Fel: X = Fehler: X +Fel: hittar inte filen X = Fehler. Datei nicht gefunden 'X' +Felaktig kontroll = Falscher Posten +Felaktig nyckel = Falscher Schlüssel +Felaktig sträcka = Falsche Strecke +Felaktigt filformat = Ungültiges Dateiformat +Felst. = Fehlst. +Fil att exportera till = Datei zum Exportieren +Fil: X = Datei: X +Filnamn = Dateiname +Filnamn (OCAD banfil) = Dateinahme (OCAD Bahndatei) +Filnamn IOF (xml) med klubbar = Dateiname IOF (xml) mit Vereinen +Filnamn IOF (xml) med löpare = Dateiname IOF (xml) mit Läufern +Filnamnet får inte vara tomt = Der Dateiname darf nicht leer sein +Filtrering = Filterung +Flera banor = Mehrere Bahnen +Flera banor / stafett / patrull / banpool = Mehrere Bahnen / Staffel / Paarlauf / Bahnenpool +Flera banor/stafett = Mehrere Bahnen / Staffel +Formulärläge = Formularmodus +Fortsätt = Fortsetzen +Fri anmälningsimport = Freier Nennungsimport +Fria starttider = Freie Startzeiten +Från kontroll = Ab Posten +Till kontroll = Bis Posten +Funktioner = Funktionen +Födelseår = Geburtsjahr +För att ändra måltiden måste löparens målstämplingstid ändras = Um die Zielzeit zu ändern muss die Zielstempelzeit des Läufers geändert werden +För många kontroller = Zu viele Posten +Fördefinierade tävlingsformer = Vorgegebene Wettkampfformen +Fördela starttider = Startzeiten verteilen +Förhandsgranskning, import = Vorschau (Import) +Förhöjd avgift = Nachnenngebühr +Först-i-mål, gemensam = Massenstart +Först-i-mål, klassvis = Massenstart nach Kategorien +Första (ordinarie) start = Erster Start +Första ordinarie starttid = Erste (normale) Startzeit +Första start = Erste Startzeit +Första sträckan kan inte vara parallell = Die erste Strecke kann nicht parallel sein +Försöket misslyckades = Der Versuch ist fehlgeschlagen +Förvarning på (SI-kod): alla stämplingar = Vorwarnung bei (SI-Nummer): allen Stempeln +Förvarningsröst = Stimme bei Vorwarnung +Förväntad andel efteranmälda = Erwartete Anzahl Nachnennungen +Gata = Straße +Gemensam start = Massenstart +Generera = Erstellen +Generera testtävling = Testwettkampf erstellen +Genererad = Erstellt um +Geografisk fördelning = Geographische Verteilung +Godkänd API-nyckel = API-Schlüssel akzeptiert +Granska inmatning = Vorschau +Grund avg. = Grundgeb. +Grundavgift = Grundgebühr +Hantera brickor = SI-Cards verwalten +Hantera flera etapper = Mehrere Etappen verwalten +Hantera klubbar och ekonomi = Vereine und Startgelder verwalten +Hantera kvar-i-skogen = Fehlende Läufer verwalten +Hantera löparbrickor = SI-Cards verwalten +Hantera vakanser = Vakantplätze verwalten +Hemsida = Webseite +Hyravgift = Leihgebühr +Hyrbricka = Leihchip +Hyrbricksrapport = Leihchip Bericht +Hyrbricksrapport - %s = Geliehene SI-Cards - %s +Hyrd = geliehen +Hämta (efter)anmälningar från Eventor = Lade (Nach)nennungen von Eventor +Hämta data från Eventor = Lade Daten von Eventor (Schweden) +Hämta efteranmälningar = Lade Nachnennungen +Hämta löpardatabasen = Lade Läuferdatenbank +Hämta tävlingsdata = Lade Wettkampfdaten +Hämta tävlingsdata för X = Lade Wettkampfdaten für X +Hämtar anmälda = Nennungen werden geladen +Hämtar information om = Informationen werden geladen in +Hämtar klasser = Kategorien werden geladen +Hämtar klubbar = Vereine werden geladen +Hämtar löpardatabasen = Läuferdatenbank wird geladen +Hämtar tävling = Wettkampf wird geladen +Händelser = Ereignisse +Hög avgift = Nachnennungsgebühr +IP-adress eller namn på en MySQL-server = IP-Adresse oder MySQL-Servername +Importera = Importieren +Importera anmälningar = Nennungen importieren +Importera banor = Bahnen importieren +Importera banor/klasser = Bahnen/Kategorien importieren +Importera en tävling från fil = Wettkampf aus Datei importieren +Importera fil = Datei importieren +Importera från OCAD = Aus OCAD importieren +Importera från fil = Aus Datei importieren +Importera löpardatabas = Läuferdatenbank importieren +Importera löpare = Läufer importieren +Importera löpare och klubbar / distriktsregister = Läufer und Vereine importieren +Importera stämplingar = Stempel importieren +Importera tävling = Wettkampf importieren +Importera tävlingsdata = Wettkampfdaten importieren +Importerar OCAD csv-fil = OCAD CSV Datei wird importiert +Importerar OE2003 csv-fil = OE2003 CSV Datei wird importiert +Importerar OS2003 csv-fil = OS2003 CSV Datei wird importiert +Importerar anmälningar (IOF, xml) = Nennunen werden importiert (IOF, xml) +Importerar banor (IOF, xml) = Bahnen werden importiert (IOF, xml) +Importerar klasser (IOF, xml) = Kategorien werden importiert (IOF, xml) +Importerar klubbar (IOF, xml) = Vereine werden importiert (IOF, xml) +Importerar tävlingsdata (IOF, xml) = Wettkampfdaten werden importiert (IOF, xml) +Index = Index +Individuell = Individuell +Individuell resultatlista, alla lopp = Individuelle Ergebnisliste, alle Läufe +Individuell resultatlista, sammanställning av flera lopp = Individuelle Ergebnisliste, Zusammenfassung von mehreren Läufen +Individuell resultatlista, visst lopp = Individuelle Ergebnisliste, Lauf +Individuell resultatlista, visst lopp (STOR) = Individuelle Ergebnisliste, Lauf (GROSS) +Individuell startlista, visst lopp = Individuelle Startliste, Lauf +Individuella deltagare = Individuelle Teilnehmer +Info = Information +Inga deltagare = Keine Teilnehmer +Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning = Keine Vakantplätze verfügbar. Vakantplätze werden üblicherweise bei der Verlosung erstellt +Ingen = Keine +Ingen bana = Keine Bahn +Ingen klass = Keine Kategorie +Ingen löpare saknar bricka = Alle Läufer haben eine SI-Card +Inkommande = Eingehende +Inläst bricka ställd i kö = Eingelesene SI-Card ist in die Warteschlange gestellt worden +Inlästa brickor = Eingelesene SI-Cards +Inmatning av mellantider = Zwischenzeiten eingeben +Inspekterar klasser = Überprüfe Kategorien +Installera = Installieren +Inställningar = Einstellungen +Inställningar MeOS = MeOS Programmeinstellungen +Interaktiv inläsning = Interaktives Einlesen +Intervall = Intervall +Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras = Intervall (Sekunden). Freilassen um bei geänderten Wettkampfdaten zu aktualisieren +Intervallet måste anges på formen MM:SS = Intervall in der Form MM:SS angegeben +Jag sköter lottning själv = Ich lose selbst +Jaktstart = Jagdstart +Klart = Abgeschlossen +Klart. Antal importerade: X = Abgeschlossen. Anzahl Nennungen importiert: X +Klart. X deltagare importerade = Abgeschlossen. X Teilnehmer importiert +Klart. X lag importerade = Abgeschlossen. X Teams importiert +Klart. X patruller importerade = Abgeschlossen. X Paare importiert +Klart: alla klasser lottade = Abgechlossen: alle Kategorien ausgelost +Klart: inga klasser behövde lottas = Abgeschlossen: keine Kategorien mussten ausgelost werden +Klass = Kategorie +Klass %d = Kategorie %d +Klass att slå ihop = Kategorie zum Zusammenlegen +Klassbyte = Kategorie wechseln +Klassen 'X' har jaktstart/växling på första sträckan = Kategorie 'X' hat Jagdstart/Übergabe auf der ersten Strecke +Klassen används och kan inte tas bort = Kategorie in Verwendung und kann nicht gelöscht werden +Klassen måste ha ett namn = Kategorie muss einen Namen haben +Klassens bana = Bahn der Kategorie +Klasser = Kategorien +Klasser (IOF, xml) = Kategorien (IOF, xml) +Klassinställningar = Kategorie-Einstellungen +Klassnamn = Kategoriename +Klasstyp = Kategorieart +Klientnamn = Klientenname +Klistra in = Einfügen +Klistra in data från urklipp (X) = Aus Zwischenablage (X) einfügen +Klubb = Verein +Klubb att ta bort = Verein löschen +Klubb: X = Verein: X +KlubbId = Vereinsnummer +Klubbar = Vereine +Klubbar (IOF, xml) = Vereine (IOF, xml) +Klubblös = vereinslos +Klubbresultat = Vereins-Ergebnis +Klubbresultatlista = Vereins-Ergebnisliste +Klubbresultatlista - %s = Vereins-Ergebnisliste - %s +Klubbstartlista = Vereins-Startliste +Klubbstartlista - %s = Vereins-Startliste - %s +Klungstart = Gruppierter Start +Knyt löpare till sträckan = Läufer mit Strecke verknüpfen +Knyt löparna till banor från en pool vid målgång = Läufer mit Bahnen aus Bahnenpool beim Einlesen mit Bahnen verknüpfen +Kommunikation = Kommunikation +Kontant = Bar +Kontant betalning = Barbezahlung +Konto = Konto +Kontroll = Posten +Kontroll %s = Posten %s +Kontroll inför tävlingen = Test vor dem Wettkampf +Kontrollen används och kan inte tas bort = Posten in Verwendung und kann nicht gelöscht werden +Kontrollens ID-nummer = Postennummer +Kontroller = Posten +Kontrollnamn = Postenname +Kopiera länken till urklipp = Link zur Zwischenablage kopieren +Kopiera selektionen till urklipp (X) = Auswahl zur Zwischenablage (X) kopieren +Koppla ifrån = Verbindung trennen +Koppla ner databas = Verbindung zur Datenbank trennen +Kopplar ifrån SportIdent på = Verbindung zur Sportident-Einheit trennen bei +Kunde inte ansluta till Eventor = Konnte keine Verbindung zu Eventor herstellen +Kvar-i-skogen = Fehlende Läufer +Källkatalog = Quellordner +Kön = Geschlecht +Kör kontroll inför tävlingen = Führe einen Test vor dem Wettkampf durch +Ladda upp öppnad tävling på server = Wettkampf auf Server hochladen +Lag = Teams +Lag %d = Team %d +Lag: = Teams: +Laget 'X' saknar klass = Team 'X' hat keine Kategorie +Laget hittades inte = Team wurde nicht gefunden +Lagnamn = Teamname +Lagrade säkerhetskopior = Gespeicherte Sicherheitskopien +Lista = Liste +Lista av typ 'X' = Liste von Art 'X' +Lista med mellantider = Liste mit Zwischenzeiten +Lista med sträcktider = Liste mit Zwischenzeiten +Listor = Listen +Listor och sammanställningar = Listen und Berichte +Listval = Listenwahl +Ljudfiler, baskatalog = Audiodateien, Basisordner +Lokalt = Lokal +Lopp %d = Lauf %d +Lopp %s = Lauf %s +Lopp X = Lauf X +Lotta = Auslosen +Lotta flera klasser = Mehrere Kategorien auslosen +Lotta klassen = Kategorie auslosen +Lotta klassen X = Kategorie 'X' auslosen +Lotta löpare som saknar starttid = Läufer ohne Startzeit auslosen +Lotta om hela klassen = Ganze Kategorie neu auslosen +Lottad = Ausgelost +Lottad startlista = Ausgeloste Startliste +Lottar efteranmälda = Nachnennungen auslosen +Lottar: X = Wird ausgelost: X +Lottning = Zufällige Auslosung +Lyssna = Höre +Lägg till en ny rad i tabellen (X) = Neue Reihe in Tabelle (X) einfügen +Lägger till klubbar = Vereine werden hinzugefügt +Lägger till löpare = Läufer werden hinzugefügt +Längd (m) = Länge (m) +Länk till resultatlistan = Link zur Ergebnisliste +Länk till startlistan = Link zur Startliste +Läs brickor = SI-Cards einlesen +Läser klubbar = Vereine lesen +Läser löpare = Läufer lesen +Låt klassen ha mer än en bana eller sträcka = Ermögliche mehr als eine Bahn oder Strecke für eine Kategorie +Löpande information om viktiga händelser i tävlingen = Laufende Benachrichtigungen über wichtige Ereignisse im Wettkampf +Löparbricka %d = SI-Card %d +Löpardatabasen = Läuferdatenbank +Löpare = Läufer +Löpare saknar klass eller bana = Läufer ohne Kategorie oder Bahn +Löpare som förekommer i mer än ett lag = Läufer kommt in mehr als einem Team vor +Löpare utan SI-bricka: %d = Läufer ohne SI-Card: %d +Löpare utan bana: %d = Läufer ohne Bahn: %d +Löpare utan klass: %d = Läufer ohne Kategorie: %d +Löpare utan klubb: %d = Läufer ohne Verein: %d +Löpare utan starttid: %d = Läufer ohne Startzeit: %d +Löpare, Status Okänd, med registrering (kvar-i-skogen) = Läufer, Status unbekannt, mit Registrierung (nicht im Ziel) +Löpare, Status Okänd, som saknar registrering = Läufer, Status unbekannt, ohne Registrierung +Löpare: = Läufer: +Löpare: X, kontroll: Y, kl Z = Teilnehmer: X, Posten: Y, Uhrzeit: Z +Löparen hittades inte = Läufer nicht gefunden +Löptid = Laufzeit +Lösenord = Passwort +Manuell lottning = Manuelle Verlosung +Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar = Erste Startnummer angeben oder leer lassen um Startnummern zu entfernen +Mata in radiotider manuellt = Zeiten bei Funkposten manuell eintragen +Max parallellt startande = Max. Anzahl zugleich Startende +Max. vakanser (per klass) = Max. Vakantplätze (pro Kategorie) +Maxtid = Maximalzeit +MeOS = MeOS +MeOS lokala datakatalog är = MeOS lokaler Datenordner ist +Med stafettklasser = Mit Staffelkategorien +Med sträcktidsanalys = Mit Zwischenzeitenanalyse +Medlöpare = Mitläufer +Mellantider visas för namngivna kontroller = Zwischenzeiten werden für benannte Posten angezeigt +Metod = Methode +Min. vakanser (per klass) = Min. Vakantplätze (pro Kategorie) +Minsta intervall i klass = Kürzestes Intervall in Kategorie +Minsta startintervall = Kürzestes Startintervall +Minsta sträcktid = Kürzeste Zwischenzeit +Minutstartlista = Minuten-Startliste +Motion = Hobby +Multipel = Mehrere +MySQL Server / IP-adress = MySQL Server / IP-Adresse +Mål = Ziel +Målstämpling saknas = Zielstempel fehlt +Måltid = Zielzeit +Namn = Name +Nationalitet = Nationalität +Nollställ avgifter = Gebühren zurücksetzen +Nollställ databaser = Datenbanken zurücksetzen +Nolltid = Nullzeit +Normal = Normal +Normalavgift = Normalgebühr +Not implemented = Nicht implementiert +Nummerlapp = Startnummer +Nummerlappar = Startnummern +Nummerlappar i X = Startnummern für X +Nuvarande innehavare: X = Derzeitiger Besitzer: X +Ny bana = Neue Bahn +Ny deltagare = Neuer Teilnehmer +Ny klass = Neue Kategorie +Ny klubb = Neuer Verein +Ny kontroll = Neuer Posten +Ny tävling = Neuer Wettkampf +Nyckel för Eventor = Eventor-Schlüssel +Nytt fönster = Neues Fenster +Nytt lag = Neues Team +Nästa = Nächste +Nästa försök = Nächster Versuch +OK = OK +Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y' = Ungültige Bahnendatei. Posten bei Position X erwartet, stattdessen 'Y' gefunden +Ogiltig första starttid. Måste vara efter nolltid = Ungültige erste Startzeit. Muss nach der Nullzeit sein +Ogiltig starttid i 'X' på sträcka Y = Ungültige Startzeit in 'X' auf Strecke Y +Ogiltig starttid: X = Ungültige Startzeit: X +Ogiltig tid = Ungültige Zeit +Ogiltigt bricknummer X = Ungültige SI-Cardnummer X +Okänd bricka = Unbekannte SI-Card +Okänd funktion = Unbekannte Funktion +Okänd klass = Unbekannte Kategorie +Om MeOS = Über MeOS +Om MeOS – ett Mycket Enkelt OrienteringsSystem = Über MeOS – Moderne und einfache Orientierungslauf-Software +Omstart = Neustart +Omstart i stafettklasser = Staffel-Neustart +Omstartstid = Neustartzeit +Oparad = Ungepaart +Operationen misslyckades = Operation erfolglos +Operationen stöds ej = Operation nicht unterstützt +Optimerar startfördelning = Startverteilung wird optimiert +Ordinarie anmälningsdatum = Nennschluss +Ordinarie avgift = Normalgebühr +Oväntad kontroll 'X' i bana Y = Unerwarteter Posten 'X' in Bahn Y +Packar upp löpardatabas = Läuferdatenbank wird geöffnet +Par- eller singelklass = Paarlauf- oder Einzelkategorie +Para ihop = paaren +Para ihop bricka X med en deltagare = SI-Card X mit Teilnehmer paaren +Parallell = Parallel +Patrull = Paarlauf +Patrull, 1 SI-pinne = Paarlauf, 1 SI-Card +Patrull, 2 SI-pinnar = Paarlauf, 2 SI-Cards +Patrullresultat (STOR) = Paarlaufergebnis (GROSS) +Plac. = Rang +Placering in = Rang ein +Plats = Ort +Port = Schnittstelle (Port) +Port för TCP = TCP-Schnittstelle +Postadress = Postadresse +Postkod = PLZ +Poäng = Punkte +Poäng in = Punkte ein +Poängavdrag (per minut) = Punkteabzug (pro Minute) +Poänggräns = Punktelimit +Prel. bomtid = Vorl. Fehlerzeit +Prel. placering = Vorl. Rang +Prioritering = Priorität +Prisutdelningslista = Siegerehrungsliste +Prolog + jaktstart = Prolog + Jagdstart +Publicera resultat = Ergebnis publizieren +Publicera resultat och sträcktider på Eventor och WinSplits online = Ergebnisse und Zwischenzeiten auf Eventor und WinSplits online publizieren +Publicera startlista = Startliste publizieren +Publicera startlistan på Eventor = Startliste auf Eventor publizieren +Publicerar resultat = Ergebnis wird publiziert +Publicerar startlistan = Startliste wird publiziert +Radera = Löschen +Radera tävlingen = Wettkampf löschen +Radera vakanser = Vakantplätze löschen +Radiotider, kontroll = Funkposten-Zeiten, Posten +Ranking = Ranking +Ranking (IOF, xml) = Ranking (IOF, xml) +Rapport inför = Bericht für +Rapporter = Berichte +Redigera deltagaren = Teilnehmer bearbeiten +Rep = Übergabestopp +Repdragningstid = Übergabestopp-Zeit +Reserverade = Reserviert +Resultat = Ergebnis +Resultat && sträcktider = Ergebnis && Zwischenzeiten +Resultat (STOR) = Ergebnis (GROSS) +Resultat - %s = Ergebnis - %s +Resultat - X = Ergebnis - X +Resultat efter sträcka X = Ergebnis nach Strecke X +Resultat efter sträckan = Ergebnis nach Strecke +Resultat för ett visst lopp = Ergebnis für einen bestimmen Lauf +Resultat lopp X - Y = Ergebnis Lauf X - Y +Resultat, generell = Ergebnis, allgemein +Resultat, individuell = Ergebnis, Einzel +Resultat, patrull = Ergebnis, Paarlauf +Resultatlista - %s = Ergebnisse - %s +Resultatlista – inställningar = Ergebnis – Einstellungen +Resultatlistor = Ergebnisse +Resultatutskrift = Ergebnis drucken +Resultatutskrift / export = Ergebnisdruck / Export +Rogaining = Rogaining +Rogaining, individuell = Rogaining, Einzel +Rogaining-poäng = Rogaining Punkte +SI X inläst. Brickan tillhör Y som saknar klass = SI X wurde eingelesen. Die SI-Card gehört Y und ist keiner Kategorie zugeordnet +SI X inläst. Brickan är inte knuten till någon löpare (i skogen) = SI X wurde eingelesen. Die SI-Card ist zu keinem Läufer (nicht im Ziel) gebunden +SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen = SI X wurde bereits eingelesen. Interaktives Einlesen verwenden um SI-Chip nochmals einzulesen +SI X är redan inläst. Ska den läsas in igen? = SI X wurde bereits eingelesen. Nochmals einlesen? +SI på = SI an +SI-dubbletter: %d = SI-Duplikate: %d +SOFT-avgift = SOFT Gebühr +SOFT-lottning = Schwedische Losungsmethode +Saknad starttid = Fehlende Startzeit +Sammanställning = Zusammenfassung +Sammanställning, ekonomi = Zusammenfassung, Nenngelder +Sammanställning, klasser = Zusammenfassung, Kategorien +Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? = Größe der Auswahl stimmt nicht mit der aus der Zwischenablage überein. Trotzdem einfügen? +Server = Server +Server: [X] Y = Server: [X] Y +Sidbrytning mellan klasser = Seitenumbruch zwischen Kategorien +Sidbrytning mellan klasser / klubbar = Seitenumbruch zwischen Kategorien / Vereinen +Simulera inläsning av stämplar = SI-Einlesen simulieren +Sista betalningsdatum = Zahlbar bis +Sista datum för ordinarie anmälan (ÅÅÅÅ-MM-DD) = Letztes Datum zu normalem Nenngeld (JJJJ-MM-TT) +Sista ordinarie anmälningsdatum = Letztes Datum zu normalem Nenngeld +Sista start (nu tilldelad) = Letzter Start (zugeteilt) +Sista start (nu tilldelad): X = Letzter Start (zugeteilt): X +Sista sträckan = Letzte Strecke +Ska X raderas från tävlingen? = X vom Wettkampf löschen? +Skapa en ny tävling med data från Eventor = Erstelle einen neuen Wettkampf mit Daten aus Eventor +Skapa en ny, tom, tävling = Erstelle einen neuen, leeren Wettkampf +Skapa generell lista = Allgemeine Liste erstellen +Skapa listan = Liste erstellen +Skapa ny klass = Neue Kategorie erstellen +Skapad av = Erstellt von +Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) = Eine Bahn für die Kategorie %s mit %d Posten in SI-Card %d wurde erstellt. +Skapar ny tävling = Neuer Wettkampf wird erstellt +Skapar saknad klass = Fehlende Kategorie wird erstellt +Skippar lottning = Auslosung überspringen +Skript att köra efter export = Script nach dem Export ausführen +Skriv endast ut ändade sidor = Nur geänderte Seiten ausdrucken +Skriv första starttid på formen HH:MM:SS = Erste Startzeit in HH:MM:SS angeben +Skriv ut = Drucken +Skriv ut eller exportera listan automatiskt = Liste automatisch Drucken oder Exportieren +Skriv ut fakturan = Rechnung drucken +Skriv ut listan = Liste drucken +Skriv ut nu = Jetzt drucken +Skriv ut rapporten = Bericht drucken +Skriv ut sträcktider = Zwischenzeiten drucken +Skriv ut tabellen = Tabelle drucken +Skriv ut tabellen (X) = Tabelle (X) drucken +Skriv över existerande bricknummer? = Bestehende SI-Cardnummer überschreiben? +Skrivare = Drucker +Skrivarinställningar för sträcktider = Druckeinstellungen für Zwischenzeiten +Skriver sträcktider om = Zwischenzeiten werden gedruckt in +Slå ihop = Zusammenlegen +Slå ihop klubb = Verein zusammenlegen +Snabbinställningar = Schnell-Einstellungen +Sortering = Sortierung +Sortering: %s, antal rader: %d = Sortierung: %s, Anzahl Reihen: %d +Spara = Speichern +Spara anmälningar = Nennungen speichern +Spara för webben = Für Webseite speichern +Spara sträcktider till en fil för automatisk synkronisering med WinSplits = Zur automatischen Synchronisierung mit WinSplits Zwischenzeiten als Datei speichern +Speaker = Speaker +Speakerstöd = Speakerunterstützung +SportIdent = Sportident +Språk = Sprache +Stad = Ort +Stafett = Staffel +Stafett (sammanställning) = Staffel (Zusammenfassung) +Stafett - sammanställning = Staffel - Zusammenfassung +Stafett - sträcka = Staffel - Strecke +Stafett - total = Staffel - Gesamt +Stafettklasser = Staffel-Kategorien +Stafettresultat, delsträckor = Staffelergebnis, Strecken +Stafettresultat, lag = Staffelergebnis, Team +Stafettresultat, sträcka = Staffelergebnis, Strecke +Stafettresultat, sträcka (STOR) = Staffelergebnis, Strecke (GROSS) +Start = Start +Starta = Starten +Starta automaten = Automatischen Dienst starten +Starta en guide som hjälper dig göra klassinställningar = Kategorien-Guide starten +Startade automater = Gestartete automatisierte Dienste +Startande = Starter +Startar SI på = Starte SI auf +Startblock = Startblock +Startblock: %d = Startblock: %d +Startintervall (min) = Startintervall (min) +Startlista = Startliste +Startlista %%s - sträcka %d = Startliste %%s - Strecke %d +Startlista - %s = Startliste - %s +Startlista - X = Startliste - X +Startlista ett visst lopp = Startliste für einen bestimmten Lauf +Startlista lopp X - Y = Startliste Lauf X - Y +Startlista, individuell = Startliste, Einzel +Startlista, patrull = Startliste, Paarlauf +Startlista, stafett (lag) = Startliste, Staffel (Team) +Startlista, stafett (sträcka) = Startliste, Staffel (Strecke) +Startlistor = Startlisten +Startmetod = Startmethode +Startnamn = Startname +Startnummer = Startnummer +Starttid = Startzeit +Starttid (HH:MM:SS) = Startzeit (HH:MM:SS) +Starttiden är upptagen = Startzeit nicht verfügbar +Starttyp = Startart +Status = Status +Status OK = Status OK +Status in = Status Eingabe +Stoppa automaten = Automatisierten Dienst stoppen +Stor = Groß +Str. = Str. +Str. %d = Str. %d +Strukturerat exportformat = Strukturiertes Exportformat +Sträcka = Strecke +Sträcka %d = Strecke %d +Sträcka X = Strecke X +Sträckans banor = Bahnen für Strecke +Sträcktider = Zwischenzeiten +Sträcktider (WinSplits) = Zwischenzeiten (WinSplits) +Sträcktider / WinSplits = Zwischenzeiten / WinSplits +Sträcktider/WinSplits = Zwischenzeiten/WinSplits +Sträcktidsfil = Dateiname +Sträcktidsutskrift = Zwischenzeiten drucken +Sträcktidsutskrift[check] = Zwischenzeiten drucken +Sträcktilldelning, stafett = Streckeneinteilung, Staffel +Sträcktyp = Streckenart +Sträng = Beenden +Stämpelkod(er) = Stempelcode/s +Stämplar om = Stempelt um +Stämplingar = Stempel +Stämplingar saknas: X = Fehlende Stempel: X +Stämplingsautomat = Stempelautomat +Stämplingsintervall (MM:SS) = Stempelintervall (MM:SS) +Stämplingstest = Stempeltest +Stämplingstest [!] = Stempeltest [!] +Stäng = Schließen +Stäng tävlingen = Wettkampf schließen +Större = Größer +Störst = Größte +Största intervall i klass = Größtes Intervall in Kategorie +Summera = Summieren +Synkronisera med Eventor = Mit Eventor synchronisieren +Säkerhetskopiera = Sicherheitskopie +Sätt okända löpare utan registrering till = Setze Status für Läufer ohne Registrierung +Sätt som oparad = Setze als ungepaart +Sök = Suche +Sök deltagare = Suche Teilnehmer +Sök och starta automatiskt = Suche und starte automatisch +Sök på namn, bricka eller startnummer = Suche nach Name, SI-Card oder Startnummer +Söker efter SI-enheter = Suche nach SI-Einheiten +TCP: Port %d, Nolltid: %s = TCP: Port %d, Nullzeit: %s +TRASIG( = Kaputt( +Ta bort / slå ihop = Löschen / Zusammenlegen +Ta bort markerad = Markierte löschen +Ta bort stämpling = Stempel löschen +Ta bort valda rader från tabellen (X) = Lösche gewählte Reihen von der Tabelle (X) +Tabellverktyg = Tabellenwerkzeug +Tabelläge = Tabellenmodus +Telefon = Telefon +Test = Test +Test av stämplingsinläsningar = Teststempel +Testa rösten = Stimme testen +Textstorlek = Textgröße +Tid = Zeit +Tid efter: X = Rückstand: X +Tid efter: X; har tagit in Y = Rückstand: X; hat Y gut gemacht +Tid efter: X; har tappat Y = Rückstand: X; hat Y verloren +Tid in = Zeit ein +Tidsavdrag: X poäng = Zeitabzug: X Punkte +Tidsgräns = Zeitlimit +Tidsinmatning = Zeit manuell eingeben +Tidsintervall (MM:SS) = Zeitintervall (MM:SS) +Tidsjustering = Zeitkorrektur +Till huvudsidan = Zur Hauptseite +Tilldela = Zuweisen +Tilldela avgifter = Gebühren zuweisen +Tilldela hyrbrickor = Leihchips zuweisen +Tilldela nummerlappar = Startnummern zuweisen +Tilldelning av hyrbrickor = Leichips zuweisen +Tillgängliga automater = Verfügbare automatisierte Dienste +Tillsatte vakans = Vakantplatz zugewiesen +Tillsätt vakans = Vakantplatz zuweisen +Tillämpa parstart = Paarweise Starten +Tillåt direktanmälan = Erlaube Direktanmeldung +Topplista, N bästa = Topliste, N Besten +Total tävlingsavgift = Summe Wettkampfgebühr +Totalresultat = Gesamtergebnis +Totalt = Summe +Totalt faktureras = Summe in Rechnung stellen +Totalt kontant = Summe bar +Trasig = Fehlerhaft +Träning = Training +Tvåmannastafett = 2-Mann Staffel (Teamsprint) +Typ = Typ +Typ av delning = Teilungsart +Typ av export = Exportart +Typ av lista = Listenart +Tävling = Wettkampf +Tävling från Eventor = Wettkampf von Eventor +Tävlingen innehåller inga resultat = Es sind noch keine Ergebnisse vorhanden +Tävlingen måste ha ett namn = Wettkampf muss einen Namen haben +Tävlingens namn: X = Name des Wettkampfes: X +Tävlingsdata har sparats = Wettkampfdaten wurden gespeichert +Tävlingsinställningar = Wettkampfeinstellungen +Tävlingsinställningar (IOF, xml) = Wettkampfeinstellungen (IOF, xml) +Tävlingsnamn = Wettkampfname +Tävlingsrapport = Wettkampfbericht +Tävlingsstatistik = Wettkampfstatistik +Underlag för tävlingsavgift = Daten für Wettkampfgebühr +Undre ålder = Min. Alter +Ungdom = Jugend +Ungdomsavgift = Jugendgebühr +Ungdomsklasser = Jugendkategorien +Uppdatera = Aktualisieren +Uppdatera alla klubbar = Alle Vereine aktualisieren +Uppdatera alla värden i tabellen = Tabelle aktualisieren +Uppdatera alla värden i tabellen (X) = Tabelle (X) aktualisieren +Uppdatera fördelning = Zuweisung aktualisieren +Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan = Aktualisiere die Zuweisung der Startzeiten mit Rücksicht auf die oben angegebenen, manuellen Änderungen. +Uppdatera klubbar && löpare = Vereine && Läufer aktualisieren +Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret = Angaben über Vereine und Läufer mittels Daten der Läuferdatenbank aktualisieren. +Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret = Vereine mittels Daten der Läuferdatenbank aktualisieren +Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret = Vereinsangaben mittels Daten der Läuferdatenbank aktualisieren +Uppdatera löpardatabasen = Läuferdatenbank aktualisieren +Urval = Auswahl +Urval %c%s = Auswahl %c%s +Utan inställningar = Ohne Einstellungen +Utan tidtagning = Ohne Zeitnehmung +Utbyt tävlingsdata med Eventor = Wettkampfdaten mit Eventor austauschen +Utför lottning = Auslosung durchführen +Utfört = Fertig +Utg. = Aufg. +Utskrift / export = Drucken / Exportieren +Utskriftsintervall (MM:SS) = Druckintervall (MM:SS) +Utökat protokoll = Erweitertes Protokoll +VALFRI( = EinerVon( +Vak. ranking = Vakantplatz-Reihenfolge +Vakanser = Vakantplätze +Vakanser / klassbyte = Vakantplätze / Kategorientausch +Vakant = Vakant +Valbar = Optional +Vald bricka = Gewählte SI-Card +Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) = Warnung: Kein Veranstalter angegeben (siehe Wettkampfeinstellungen) +Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Warnung: Keine Kontonummer angegeben (siehe Wettkampfeinstellungen) +Varning: Inget sista betalningsdatum angivet (Se tävlinginställningar) = Warnung: Kein Fälligkeitsdatum angegeben (siehe Wettkampfeinstellungen) +Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Warnung: Ein Teilnehmer ohne Namen wurde gefunden. MeOS benötigt einen Namen und hat dem Teilnehmer daher den Namen 'N.N.' zugewiesen. +Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Warnung: Ein Team ohne Namen wurde gefunden. MeOS benötigt einen Namen und hat dem Team daher den Namen 'N.N.' zugewiesen. +Verkställ = Ausführen +Version X = Version X +Vi stöder MeOS = Wir unterstützen MeOS +Viktiga händelser = Wichtige Ereignisse +Vill du klistra in X nya rader i tabellen? = X neue Reihen in die Tabelle einfügen? +Vill du radera X rader från tabellen? = X Reihen der Tabelle löschen? +Vill du radera alla vakanser från tävlingen? = Alle Vakantplätze des Wettkampfes löschen? +Vill du skapa en ny klass? = Neue Kategorie erstellen? +Vill du verkligen radera tävlingen? = Wettkampf endgültig löschen? +Vill du verkligen stänga MeOS? = MeOS beenden? +Vill du verkligen ta bort laget? = Team endgültig löschen? +Vill du verkligen ta bort löparen? = Läufer endgültig löschen? +Visa avancerade funktioner = Erweiterte Einstellungen anzeigen +Visa en tabell över alla stämplingar = Tabelle mit allen Stempeln zeigen +Visa mellantider = Zwischenzeiten anzeigen +Visa startlistan = Startliste anzeigen +Visa tillgängliga säkerhetskopior = Zeige verfügbare Sicherheitskopien +Visar de X bästa = Zeige die X besten +Vuxen = Erwachsener +Vuxenklasser = Erwachsenen-Kategorien +Vuxna = Erwachsene +Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad = zum Sichern der SI-Cards wählen. Interaktives Einlesen ist NICHT aktiviert +Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad = zum Sichern der SI-Cards wählen. Interaktives Einlesen ist aktiviert +Välj alla = Alle auswählen +Välj alla klasser = Alle Kategorien auswählen +Välj allt = Alles auswählen +Välj automatiskt = Automatisch auswählen +Välj en vakant plats nedan = Wähle einen Vakantplatz unten aus +Välj inget = Nichts auswählen +Välj klass = Kategorie auswählen +Välj klass och starttid nedan = Kategorie und Startzeit unten auswählen +Välj klasser där alla löpare saknar starttid = Kategorien, bei denen alle Läufer keine Startzeit haben auswählen +Välj klasser där någon löpare saknar starttid = Kategorien, bei denen eine Startzeit eines Läufers fehlt auswählen +Välj kolumner = Spalten auswählen +Välj kolumner att visa = Spalten zum Anzeigen auswählen +Välj kolumner för tabellen X = Spalten für Tabelle X auswählen +Välj lopp = Lauf auswählen +Välj löpare = Läufer auswählen +Välj löpare att prioritera bevakning för = Läufer zum Beobachten auswählen +Välj löpare för sträcka X = Läufer für Strecke X auswählen +Välj skrivare = Drucker auswählen +Välj tävling = Wettkampf auswählen +Välj vilka klasser och kontroller du vill bevaka = Kategorien und Posten zum Überwachen auswählen +Välj vilka klasser och kontroller som bevakas = Kategorien und Posten zum Überwachen auswählen +Välj vilka kolumner du vill visa = Spalten zum Anzeigen auswählen +Välj vy = Ansicht auswählen +Välkommen till MeOS = Willkommen bei MeOS +Vänligen betala senast = Bitte bezahle spätestens +Vänligen återlämna hyrbrickan = Bitte Leihchip zurückgeben +Växling = Übergabe +Webb = Webdokument +X har startat = X ist/sind gestartet +X meter = X Meter +X poäng fattas = X Punkte fehlen +X rader kunde inte raderas = X Reihe/n konnten nicht gelöscht werden +X senaste = X letzten +Zooma in (Ctrl + '+') = Einzoomen (Strg + '+') +Zooma ut (Ctrl + '-') = Auszoomen (Strg + '-') +[Bevaka] = [Beobachten] +[Flytta ner] = [Nach unten] +[Klassens bana] = [Bahn der Kategorie] +[Uppdaterad anmälan] = [Anmeldung aktualisiert] +[VARNING] ingen/okänd = [WARNUNG] keine/unbekannt +[Återställ] = [Zurücksetzen] +andra = 2. +ask:addpunches = Keine SI-Card wurde für diesen Teilnehmer eingelesen. Stempel manuell eintragen? +ask:missingcourse = Manche Kategorien (X) haben keine Bahn.\n\nMeOS verwendet die Bahnen bei der Auslosung um zu verhindern, dass Läufer mit dem gleichen ersten Posten zugleich starten.\n\nTrotzdem fortfahren? +ask:overwrite_server = Der Wettkampf ist bereits am Server. Wettkampf am Server überschreiben? +backup = Backup +c/o = c/o +ej aktiv = inaktiv +elfte = 11. +elva = 11. +ett Mycket Enkelt OrienteringsSystem = Moderne und einfache Orientierungslauf-Software +eventor:help = Wenn du MeOS für Orientierungsläufe in Schweden verwendest, wird die Verbindung zu Eventor empfohlen. +eventor:question = X\n\nMöchtest du die Eventorverbindung verwenden? +femma = 5. +femte = 5. +fjärde = 4. +fritt att använda och du är välkommen att distribuera det under vissa villkor = Kostenlos zu benützen und kann unter gewissen Bedingungen weitergegeben werden +fyra = 4. +går i mål på X plats med tiden Y = kommt ins Ziel als X. mit einer Zeit von Y +går i mål på X plats, efter Y, på tiden Z = kommt ins Ziel als X. hinter Y, mit einer Zeit von Z +går upp i delad ledning med tiden X = übernimmt die Führung (ex aequo) mit einer Zeit von X +handskakning = Handshake +har startat = ist gestartet +help:10000 = Ein Dienst in MeOS ist ein kleines Programm, das automatisch etwas macht sobald im Wettkampf Daten geändert werden. +help:12138 = Wähle eine Kategorie aus um sie mit der gewählten Kategorie zu verbinden. Wenn Startzeten bereits gelost wurden, solltest du sie erneut losen. +help:12290 = Der gewählte Wettkampf ist von einer anderen MeOS Version erstellt worden und kann nicht von einem Server geöffnet werden. Der Wettkampf kann jedoch von einer Datei importiert werden. +help:12352 = Diese Aktion löscht den ausgewählten Verein (%s, id=%d) und verschiebt alle Läufer von diesem Verein zu dem Verein, der unten ausgewählt wird. Diese Aktion kann nicht rückgängig gemacht werden. +help:12662 = Posten hinzufügen, indem eine Abfolge von Postennummern angegeben wird. Das Ziel muss nicht angegeben werden. z.B.: 31, 50, 36, 50, 37, 100. +help:14070 = Die TCP Schnittstelle wird verwendet um Stempel über TCP von anderen Systemen zu empfangen. Verwendete Schnittstelle (Port) angeben. Die Nullzeit des Protokolls ist 00:00:00. +help:14343 = Eine Liste mit eingelesenen SI-cards wird gezeigt. Um einen Läufer mit einer anderen SI-Card zu verknüpfen, klicke doppelt auf die SI-Card oder den Läufer der verknüpft werden soll. +help:146122 = MeOS kann Daten über Läufer, Vereine und Kategorien sammeln, indem er MeOS oder IOF (xml) Datenbanken durchsucht.\n\nFortfahren? +help:14692 = Posten (Postennummer), Läufer (Startnummer oder SI-Cardnummer) und Uhrzeit (HH:MM:SS) angeben. Feld leer lassen, dann wird die Computerzeit benützt. +help:15491 = Einstellungen, Vereins- und Läuferdatenbanken können zu einem ausgewählten Ordner exportiert werden. Diese Einstellungen und Datenbanken können bei einem anderen Computer importiert werden. +help:21576 = Klicke auf den Namen des Läufers um die Nennung zu ändern. Läufer-Seite verwenden um Nennungen zu löschen. Um eine Kategorie in der Liste (unten) zu sehen, muss Direktanmeldung in der Kategorien-Seite markiert sein. +help:25041 = Hier werden die Bahnen definiert. Eine Bahn wird anschließend mit einer oder mehreren Kategorien (oder Läufern) verknüpft. Es ist auch möglich Bahnen aus OCAD zu importieren. Bei Angabe der Kartenanzahl kontrolliert MeOS im Direktanmeldungsformular ob genügend Karten vorhanden sind. +help:26963 = Der Bahnenpool wird verwendet um einen Pool (eine Auswahl) an Bahnen für eine Strecke zu definieren. Anhand der auf der im Ziel ausgelesenen SI-Card erkennt MeOS welche Bahn der Läufer gelaufen ist und verknüpft diese automatisch. Bahnen im Pool werden definiert indem sie unter Mehrere Bahnen / Staffel hinzugefügt werden. Ein [S] nach der Kategorie bedeutet dass alle Teilnehmer eine Startzeit haben. +help:29191 = Es ist möglich Einstellungen, Vereins- und Läuferdatenbank von einem benutzerdefinierten Ordner zu installieren. Die lokalen Einstellungen werden beim Import überschrieben. MeOS sollte nach der Installation neu gestartet werden.\n\n führt dich zu einer Seite bei der die derzeitigen Einstellungen exportiert werden können. +help:29758 = Hier werden Vereine verwaltet und Rechnungen ausgedruckt. Es können Nenngelder anhand der Kategorie und des Meldedatums definiert, doppelte Vereine zusammengefügt und Vereinsadressen bearbeitet werden. +help:30750 = Es können viele verschiedene Listen und Berichte erstellt werden. Diese können auf dem Bildschirm gezeigt, gedruckt oder als Webseite gespeichert werden. Die Listen werden automatisch aktualisiert sobald sich die Wettkampfdaten ändern. Automatisierter Ergebnisausdruck wird unter Dienste konfiguriert. Wettkampfdaten (z.B. Zwischenzeiten) können im Menüpunkt Wettkampf exportiert werden. +help:31661 = Ein Neustart wird durch eine Übergabestopp-Zeit und einer Neustart-Startzeit definiert. Zur Übergabestopp-Zeit wird die Übergabezone geschlossen und keine Wettkämpfer dürfen auf ihre Strecke gehen. Die restlichen Läufer starten dann zur Neustartzeit. Es ist möglich verschiedene Neustartzeiten für verschiedene Strecken einzustellen. Mit dieser Funktion wird eine Neustartzeit für ganze Kategorien definiert. +help:33940 = Nennungen in Freitext importieren. Nennungen können in dieser Form angegeben werden: Name, Verein, Kategorie und SI-Card (eventuell auch Startzeit), am besten mittels Komma getrennt, eine Person (Team) pro Reihe. Es ist auch möglich mehrere Teilnehmer des selben Vereins/Kategorie einzufügen, indem die Felder Verein/Kategorie (teilweise) ausgelassen werden. Daten können auch in anderen Formaten importiert werden. +help:41072 = Zum Ändern oder Löschen eines Stempels, Stempel aus der Liste wählen. Fehlende Stempel können über die Bahnvorlage hinzugefügt werden. Fehlt die Zielzeit eines Läufers bekommt dieser den Status Aufgegeben. Fehlt ein Stempel erhält der Läufer den Status Fehlstempel. Es ist nicht möglich einen Status zu setzen der mit den vorhandenen Stempeln nicht übereinstimmt. Ist eine Zielzeit vorhanden, muss diese geändert werden um die Zielzeit zu ändern; das gleiche gilt für die Startzeit bei Startstempel. +help:41641 = Erste Startzeit und Startintervall angeben. Auslosung ergibt zufällige Losung. Schwedische Losung verteilt Läufer des selben Vereins. Gruppierter Start bedeutet, dass die ganze Kategorie in Kleingruppen laut vorgegebenem Intervall startet (verteilter Massenstart).\n\nIntervall 0 wird für Massenstart angeben.\n\nStartnummern: Erste Nummer angeben oder leer lassen wenn keine Startnummern verwendet werden. Im Feld Strecke wird angegeben welche Strecke gelost werden soll (wenn die Kategorie mehrere Strecken hat). +help:425188 = Nicht angetretene Läufer können verwaltet werden, indem SI-Einheiten (Löschen/Prüfen/Start/Posten) im SI-Manager eingelesen werden, der Import als Semikolon-getrennte Textdatei gespeichert wird und in MeOS importiert wird. Die Läufer, die im Import vorhanden sind erhalten eine Registrierung. Läufer ohne Registrierung können anschließend als gesetzt werden.Werden später weitere Läufer importiert, können Läufer, die den Status erhalten haben, auf Status geändert werden. +help:471101 = SI-Einheit aktivieren, indem die COM-Schnittstelle ausgewählt oder nach angeschlossenen SI-Einheiten gesucht wird. Information wählen um den Status für die ausgewählte Schnittstelle zu erhalten.\n\nInteraktives Einlesen lässt die direkte Bearbeitung von Problemen, wie z.B. falscher SI-Nummer zu. Diese Option nur verwenden, wenn die Läufer mit Problemen nicht besonders behandelt werden.\n\nDie Läuferdatenbank wird verwendet wenn neue Teilnehmer automatisch hinzugefügt werden sollen. Die Stempel auf der SI-Card werden verwendet um die richtige Kategorie zu finden (erraten). +help:50431 = Mit keinem Server verbunden. Um einen Wettkampf am Server zu öffnen, aus der Liste auswählen und auf öffnen klicken. Um einen Wettkampf auf den Server hochzuladen, Wettkampf lokal öffnen und hochladen wählen. Wenn ein Wettkampf am Server geöffnet ist, sind alle verbundenen MeOS Klienten sichtbar. +help:52726 = Verbindung mit einem Server.\n\nInstallation\nMySQL 5 (Community Edition) von www.mysql.com herunterladen und installieren. Es können die Standardeinstellungen verwendet werden. Es ist nur notwendig MySQL auf dem Computer, der die Funktion des Servers übernimmt zu installieren. Sobald MySQL installiert ist, MySQL Command Line Client starten und und ein Benutzerkonto für MeOS erstellen. So kann die Kommandozeile lauten:\n\n> CREATE USER meos;\nGRANT ALL ON *.* TO meos;\n\nEin Benutzer meos ohne Passwort wurde erstellt. Namen des Servers angeben (Firewalls müssen eventuell konfiguriert werden um den Datenverkehr zu erlauben).\n\n Alternativ kann der MySQL Root-Account verwendet werden. Der Benutzername ist 'root' und das Passwort ist das bei der Installation von MySQL angegebene. +help:5422 = Keine SI-Einheiten gefunden. Sind sie verbunden und aktiviert? +help:59395 = Mit diesem Formular können Einstellungen für mehrere Kategorien in einem Schritt durchgeführt werden.\n\nStart ist der Name des Starts - so wie er in der Startliste erscheinen soll.\n\nStartblock ist eine Nummer zwischen 0 und 100, die eine noch feinere Verteilung der Läufer bietet. Kategorien mit dem gleichen Block werden auf der selben Minuten-Startliste gedruckt.\n\nIndex ist ein Sortierungsschlüssel. Die Kategorien werden nach diesem Schlüssel in allen Listen sortiert.\n\nDie Bahn kann für Kategorien, die exakt eine Bahn haben spezifiziert werden. Wenn es mehrere mögliche Bahnen gibt muss das normale Kategorieformular verwendet werden. \n\nDirektanmeldung bestimmt ob die Kategorie Direktanmeldungen annimmt. +help:runnerdatabase = Durch Import von Läufer- und Vereinsdatenbank verknüpft MeOS automatisch SI-Cardnummern mit Läufern beim Einlesen der Chips und Adressen/Kontaktangaben der Vereine werden angezeigt.\n\nMeOS kann IOF (xml) Dateien importieren.\n\nWähle bei einem Computer wo die Datenbank installiert ist. Die Datenbank kann unter (verfügbar wenn kein Wettkampf ausgewählt ist) installiert werden. +help:7618 = Die Anzahl an Läufern in einem Team wird im Menüpunkt Kategorien definiert. +help:7620 = Intervall (Sekunden). Feld freilassen um zu aktualisieren, sobald der Wettkampf verändert wird. +help:89064 = Für jeden Posten wird eine oder mehrere Postennummern angegeben (SI Nummern). Bei der Bahnlegung wird zur Identifizierung die Posten ID verwendet. Normalerweise muss kein Posten hinzugefügt werden, da MeOS verwendete Posten automatisch hinzufügt.\n\nMehrere Postennummern sind nützlich wenn fehlerhafte Posten ersetzt werden oder um einfache Gabelungen zu ermöglichen. Für einen normalen Posten genügt es, dass der Läufer einen von den angegebenen Posten besucht hat. Wird der Status auf Mehrere geändert muss der Läufer alle gelisteten Posten in freiher Reihenfolge anlaufen.\n\nWenn der Postenstatus auf 'Fehlerhaft' geändert wird, wird dieser nicht für die Stempelkontrolle verwendet.\n\nEin Posten kann einen Namen erhalten, z.B. 'Zuschauerposten'. Es ist möglich Ergebnislisten mit Zwischenzeiten für Posten mit Namen zu drucken.\n\nDie Zeitkorrektur wird verwendet wenn sich herausstellt, dass die interne Uhr eines Postens falsch ist. Das Format ist +/-MM:SS oder +/-HH:MM:SS.\n\nKürzeste Zwischenzeit wird zum Beispiel bei einem Straßenübergang verwendet. Kein Läufer kann eine bessere Zeit zum Posten haben als die angegebene Zeit. Ist die Zeit des Läufers länger als die angegebene Zeit, wird die aktuelle Zeit des Läufers verwendet. +help:9373 = Eine oder mehrere Postennummern, die von diesem Posten verwendet werden, angeben.\nBeispiel: 31, 32, 33. Das Feld Punkte wird für Rogaining-Posten verwendet. +help:9615 = Keine Antwort erhalten. Soll die Schnittstelle in passivem Modus geöffnet werden; soll MeOS auf eingehende Stempel warten? +help:baudrate = Übertragungsgeschwindigkeit/Baudrate: verwende 4800 oder 38400. +help:computer_voice = Eingehende Stempel werden mit Startnummern verglichen und die Datei (N ist die Startnummer) wird abgespielt. Die Dateien werden vom unten angegebenen Ordner geladen. Wenn der Läufer/Team einer Nation (NAT) angehört, wird zuerst die passende Nationsdatei abgespielt. +help:dbage = Die Läuferdatenbank ist älter als zwei Monate. Neue Datenbank von Eventor herunterladen? +help:eventorkey = Eventor API-Schlüssel des Veranstalter-Vereins (Schweden) angeben. Den API-Schlüssel hat der Eventor-Vereinsadministrator. +help:import_entry_data = Läufer, Kategorien, Vereine und Nennungen können von diversen Text- und XML-Dateien importiert werden. Es ist nicht notwendig alle Dateien anzugeben. Zum Beispiel beinhaltet eine OE-CSV Datei für Nennungen auch Kategorien und Vereine. In diesem Fall sollten die Felder Kategorien und Vereine leer gelassen werden.\n\nWenn derselbe Teilnehmer zwei Mal importiert wird, wird dieser beim zweiten Mal aktualisiert. Es entstehen keine Kopien der Teilnehmer. Das bedeutet, dass Nachnennungen durch eine erweiterte Datei mit Nennungen importiert werden kann. +help:importcourse = Bahnen und Kategorien können von einer OCAD Exportdatei importiert werden. +help:ocad13091 = Wenn es bereits Bahnen gibt (z.B. OCAD), Namen der Bahndatei hier angeben. Bahnen können auch später hinzugefügt werden. +help:relaysetup = Anleitung verwenden um aus mehreren vordefinierten Wettkampfformen zu wählen. Bei Klick auf Ausführen werden die Einstellungen gespeichert. Danach können manuelle Einstellungen für jede Strecke gemacht werden und Bahnen gewählt werden.\n\nErläuterungen:\n- Staffel wird für Staffeln in verschiedenen Formen verwendet.\n- 2-Mann Staffel (Teamsprint-Staffel) bedeutet, dass zwei Läufer ein Team bilden und abwechselnd eine Strecke laufen.\n- Staffel mit zusätzlichen Läufern auf einer Strecke wird manchmal in Jugendklassen verwendet und erlaubt mehrere Läufer auf den mittleren Strecken (der/die Erste im Ziel übergibt an den nächsten Läufer).\n- Paarlauf kann mit zwei SI-Cards (jeder Läufer stempelt) oder mit einer SI-Card pro Paar gelaufen werden.\n- Prolog + Jagdstart bedeutet, dass ein Läufer zuerst einen Prolog (Vorlauf) und danach einen Jagdstart nach dem Ergebnis des Prologs läuft.\n- Bahnenpool ist eine Gabelungsmethode, bei der im Vorfeld nicht bestimmt werden muss wer welche Bahn läuft. Im Ziel erkennt MeOS welche Bahn gelaufen wurde. +help:restore_backup = Durch Auswahl der Zeit, an der eine Sicherheitskopie erstellt wurde kann sie wiederhergestellt werden. +help:save = MeOS speichert die Einstellungen automatisch. +help:speaker_setup = Wähle welche Kategorien und Bahnen beobachtet werden sollen. +help:speakerprio = Markiere die Läufer/Teams, die beobachten werden sollen solange sie gut laufen. Markiere zwei Kontrollkästchen um sie auch zu beobachten wenn das Ergebnis nicht so gut ist. Keine Markierung bedeutet, dass der Läufer/das Team nur beobachtet wird wenn es gut geht (nicht vom Start weg). +help:splitexport = Gesamtergebnisse oder Einzel-Ergebnisse für jeden einzelnen Lauf exportieren? Wenn alle Läufe gewählt werden, werden die Dateien nummeriert. +help:startmethod = MeOS wird automatisch die gewählte Startmethode anwenden. Egal welche Methode hier gewählt wird, sie kann später immer noch geändert werden und Startzeiten neu ausgelost werden. +help:winsplits_auto = Dieser Dienst sichert Zwischenzeiten in eine IOF (xml) Datei in regelmäßigen Intervallen. Wenn diese Datei in WinSplits eingelesen wird, werden die Zwischenzeiten in WinSplits online live aktualisiert. +help:zero_time = Setze die Nullzeit eine Stunde vor dem ersten geplanten Start. +help_autodraw = Erste (normale) Startzeit, das kürzeste Startintervall (in einer Kategorie) und den Anteil an Vakantplätzen angeben. Wähle eine Losungsmethode und ob Nachnennungen vorne oder hinten starten sollen. Die erste Startzeit muss nach der Nullzeit des Wettkampfes sein.\n\nWenn automatisches Auslosen gewählt wird, wird MeOS alle Kategorien auslosen. Kategorien, die noch nicht gelost worden sind, werden gelost. MeOS lost jeden Start einzeln und versucht eine gleichmäßige Verteilung der Starter zu schaffen. MeOS sorgt auch dafür, dass Kategorien mit der selben Bahn nicht gleichzeitig starten und wenn möglich, dass Läufer mit demselben ersten Posten nicht gleichzeitig starten. Außerdem wird ein Freiraum gelassen, damit Nachnennungen unter denselben Voraussetzungen gelost werden können.\n\nIn bereits ausgelosten Kategorien werden Nachnennungen vor oder nach den normalen Nennungen gelost. Die bereits gelosten Läufer behalten ihre Startzeit. Es ist auch möglich gewisse Kategorien manuell zu losen und MeOS anschließend die restlichen Kategorien automatisch auslosen zu lassen.\n\nWenn stattdessen die manuelle Auslosung gewählt wird, kann ausgewählt werden welche Kategorien gelost werden sollen und es gibt weitere Einstellungen. +help_draw = Die Auslosung der Startliste ist ein zweistufiges Verfahren. Zuerst werden die Kategorien, die ausgelost werden sollen ausgewählt und grundlegende Einstellungen vorgenommen. Wenn gewählt wird, wird MeOs die Einstellungen verwenden um die Startzeitblöcke zwischen den Kategorien zu verteilen. MeOS sorgt dafür, dass Kategorien mit ähnlichen Bahnen nicht zur gleichen Zeit starten, wobei bereits gezogene Kategorien berücksichtigt werden. Ein Ziel ist eine gleichmäßige Verteilung der Starter.\n\nDie berechnete Verteilung ist in einer Tabelle dargestellt, wo Änderungen vorgenommen werden können. Wenn die Verteilung zufriedenstellend ist, erlaube MeOS die ausgewählten Kategorien auszulosen.\n\nDie benötigten Grundeinstellungen sind eine erste Startzeit und das kürzeste Startintervall. Die maximale Anzahl der parallel Startenden bestimmt, wie viele Läufer gleichzeitig starten dürfen. Ein erhöhter Wert gibt eine kürzere Starttiefe.\n\nDer Anteil an Vakantplätzen steuert die Anzahl an Vakantplätzen. Wenn keine Vakantplätze benötigt werden, 0% angeben. Für die erwartete Anzahl an Nachnennungen reserviert MeOS einen Freiraum in der Startliste. +inforestwarning = Alle Läufer sind im Ziel. Da die Daten hinter dieser Folgerung fehlerhaft sein können sollte sichergestellt werden, dass alle Läufer im Ziel sind. +kartor = Karten +klar = fertig +kontroll = Posten +localhost = localhost +lopp = Lauf +mål = Ziel +målet = das Ziel +nia = 9. +nionde = 9. +radio X = Funkposten X +saknas = fehlt +se license.txt som levereras med programmet = Siehe license.txt, die mit dem Programm mitgeliefert ist +serverbackup = Server-Sicherheitskopie +sexa = 6. +sjua = 7. +sjunde = 7. +sjätte = 6. +skicka stämplar = sende Stempel +sortering: X, antal rader: Y = Sortierung: X, Anzahl Reihen: Y +sträcka X = Strecke X +stämplade vid = stempelte bei +stämplar vid X som Y, på tiden Z = stempelt bei X als Y. mit der Zeit Z +tia = 10. +till = bis +tionde = 10. +tolfte = 12. +tolva = 12. +tooltip:analyze = Analysiere Daten und zeige eine Vorschau. +tooltip:builddata = Erlaube MeOS mehr über Läufer, Vereine und Kategorien zu erfahren, indem MeOS die Wettkampfdaten analysiert. +tooltip:import = Importiere Nennungen aus Datei. +tooltip:inforest = Liste von Läufern nicht-im-Ziel und Läufern, die nicht gestartet sind. +tooltip:paste = Nennungen aus Zwischenablage einfügen. +tooltip:resultprint = Drucke Ergebnisse um auf Bildschirm zu zeigen +tooltip:voice = Computerstimme liest Zeiten von der Vorwarnung. +trea = 3. +tredje = 3. +tvåa = 2. +väntas till X om någon minut = wird demnächst bei X erwartet +väntas till X om någon minut, och kan i så fall ta en Y plats = wird demnächst bei X erwartet und kann einen Y. Rang einnehmen. +väntas till X om någon minut, och kan i så fall ta ledningen = wird demnächst bei X erwartet und kann die Führung übernehmen. +växeln = Übergabe +växlar på X plats, efter Y, på tiden Z = übergibt an X. Stelle (hinter Y) mit einer Zeit von Z +warning:has_entries = Kategorie hat bereits Läufer. Die Streckenverteilung zu diesem Zeitpunkt zu ändern kann zu einem Datenverlust führen.\n\nTrotzdem fortfahren? +warning:has_results = Kategorie hat bereits Ergebnisse. Die Streckenverteilung zu diesem Zeitpunkt zu ändern ist unüblich.\n\nTrotzdem fortfahren? +Äldre protokoll = Älteres Protokoll +Ändra = Ändern +Ändra grundläggande inställningar och gör en ny fördelning = Grundlegende Einstellungen bearbeiten und neue Zuweisung machen +Ändra inställningar = Einstellungen ändern +Ändra klassinställningar = Kategorieneinstellungen bearbeiten +Ändra lag = Team bearbeiten +Ändra sträckindelning = Streckeneinteilung bearbeiten +Ändrad = Bearbeitet +Ångra = Rückgängig machen +Återbud = Abmelden +Återgå = Zurück +Återställ = Zurücksetzen +Återställ löpare med registrering till = Läufer die sind, zu ändern +Återställ säkerhetskopia = Sicherheitskopie wiederherstellen +Återställ tabeldesignen och visa allt = Tabellendesign wiederherstellen und alles zeigen +Öppen = Offen +Öppen klass = Offene Kategorie +Öppna = Öffnen +Öppna i ett nytt fönster = In neuem Fenster öffnen +Öppna klasser, ungdom = Offene Kategorien, Jugend +Öppna klasser, vuxna = Offene Kategorien, Erwachsene +Öppna tävling = Wettkampf öffnen +Öppna vald tävling = Öffne gewählten Wettkampf +Öppnad tävling = Offener Wettkampf +Övre ålder = Max. Alter +Övriga = Übrige +är först i mål med tiden X = ist als 1. im Ziel mit der Zeit X +är först vid X med tiden Y = ist als 1. bei X mit der Zeit Y +är först vid växeln med tiden X = ist als 1. bei der Übergabe mit der Zeit X +är inte godkänd = ist disqualifiziert +återställd = wiederhergestellt +åtta = 8. +åttonde = 8. diff --git a/code/guihandler.h b/code/guihandler.h new file mode 100644 index 0000000..fa6bacc --- /dev/null +++ b/code/guihandler.h @@ -0,0 +1,45 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#ifndef MEOS_GUI_HANDLER +#define MEOS_GUI_HANDLER + +enum GuiEventType {GUI_BUTTON=1, GUI_INPUT=2, GUI_LISTBOX=3, + GUI_INFOBOX=4, GUI_CLEAR=5, GUI_INPUTCHANGE=6, + GUI_COMBO, GUI_COMBOCHANGE, GUI_EVENT, GUI_LINK, + GUI_TIMEOUT, GUI_POSTCLEAR, GUI_FOCUS, GUI_TIMER, + GUI_LISTBOXSELECT //DBL-click +}; + +class gdioutput; +class BaseInfo; + +class GuiHandler { +public: + GuiHandler() {} + virtual ~GuiHandler() = 0 {} + virtual void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) = 0; +}; + +#endif diff --git a/code/importformats.cpp b/code/importformats.cpp new file mode 100644 index 0000000..69e8017 --- /dev/null +++ b/code/importformats.cpp @@ -0,0 +1,110 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oEvent.cpp: implementation of the oEvent class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" + +#include "localizer.h" +#include "importformats.h" +#include "oEvent.h" + +/* +void ImportFormats::getImportFormats(vector< pair > &formats) { + formats.clear(); + formats.push_back(make_pair(lang.tl("Standard"), Default)); + formats.push_back(make_pair(lang.tl("French Orienteering Federation"), FrenchFederationMapping)); +} + +int ImportFormats::getDefault(oEvent &oe) { + return oe.getPropertyString("Language", "English") == "Français" ? FrenchFederationMapping : Default; +} +*/ +void ImportFormats::getExportFormats(vector< pair > &types, bool exportFilter) { + types.clear(); + + string v; + if (exportFilter) + v = "Resultat"; + else + v = "Startlista"; + + types.push_back(make_pair(lang.tl("IOF " + v + ", version 3.0 (xml)"), IOF30)); + types.push_back(make_pair(lang.tl("IOF " + v + ", version 2.0.3 (xml)"), IOF203)); + types.push_back(make_pair(lang.tl("OE Semikolonseparerad (csv)"), OE)); + types.push_back(make_pair(lang.tl("Webbdokument (html)"), HTML)); +} + +void ImportFormats::getExportFilters(bool exportFilters, vector< pair > &ext) { + string v; + if (exportFilters) + v = "Resultat"; + else + v = "Startlista"; + + ext.push_back(make_pair("IOF " + v + ", version 3.0 (xml)", "*.xml")); + ext.push_back(make_pair("IOF " + v + ", version 2.0.3 (xml)", "*.xml")); + ext.push_back(make_pair("OE Semikolonseparerad (csv)", "*.csv")); + ext.push_back(make_pair("OE/French Federation of Orienteering (csv)", "*.csv")); + ext.push_back(make_pair("Webbdokument (html)", "*.html")); +} + +ImportFormats::ExportFormats ImportFormats::getDefaultExportFormat(oEvent &oe) { + int def = IOF30; + return (ExportFormats)oe.getPropertyInt("ExportFormat", def); +} + +ImportFormats::ExportFormats ImportFormats::setExportFormat(oEvent &oe, int raw) { + oe.setProperty("ExportFormat", raw); + return (ExportFormats)raw; +} + +void ImportFormats::getOECSVLanguage(vector< pair > &typeLanguages) { + typeLanguages.push_back(make_pair("English", 1)); + typeLanguages.push_back(make_pair("Svenska", 2)); + typeLanguages.push_back(make_pair("Deutsch", 3)); + typeLanguages.push_back(make_pair("Dansk", 4)); + typeLanguages.push_back(make_pair("Français", 5)); + typeLanguages.push_back(make_pair("Russian", 6)); +} + +int ImportFormats::getDefaultCSVLanguage(oEvent &oe) { + string currentLanguage = oe.getPropertyString("Language", "English"); + int defaultLanguageType = 1; + + if (currentLanguage == "English") + defaultLanguageType = 1; + else if (currentLanguage == "Svenska") + defaultLanguageType = 2; + else if (currentLanguage == "Deutsch") + defaultLanguageType = 3; + else if (currentLanguage == "Dansk") + defaultLanguageType = 4; + else if (currentLanguage == "Français") + defaultLanguageType = 5; + else if (currentLanguage == "Russian(ISO 8859 - 5)") + defaultLanguageType = 6; + + return defaultLanguageType; +} diff --git a/code/importformats.h b/code/importformats.h new file mode 100644 index 0000000..fb4fa24 --- /dev/null +++ b/code/importformats.h @@ -0,0 +1,64 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class oEvent; + +/** Support for context specific interpretation of import/export data*/ +class ImportFormats { +public: + enum ImportFormatOptions { + Default + }; + + //static void getImportFormats(vector< pair > &formats); + + //static int getDefault(oEvent &oe); + + enum ExportFormats { + IOF30 = 1, + IOF203 = 2, + OE = 3, + HTML = 5 + }; + + static void getExportFormats(vector< pair > &types, bool exportFilter); + + static void getExportFilters(bool exportFilters, vector< pair > &ext); + + static ExportFormats getDefaultExportFormat(oEvent &oe); + + static ExportFormats setExportFormat(oEvent &oe, int raw); + + ImportFormats(int opt) : option((ImportFormatOptions)opt) {} + + ImportFormatOptions getOption() const { + return option; + } + + static void getOECSVLanguage(vector< pair > &typeLanguages); + + static int getDefaultCSVLanguage(oEvent &oe); + + private: + ImportFormatOptions option; +}; diff --git a/code/infoserver.cpp b/code/infoserver.cpp new file mode 100644 index 0000000..1c61860 --- /dev/null +++ b/code/infoserver.cpp @@ -0,0 +1,688 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + +#include "stdafx.h" +#include "meos_util.h" +#include "infoserver.h" +#include "xmlparser.h" +#include "oEvent.h" +#include "download.h" +#include "progress.h" +#include "meosException.h" +#include "gdioutput.h" + +void base64_encode(const vector &input, string &output); + +// Encode a vector vector int {{1}, {1,2,3}, {}, {4,5}} as "1;1,2,3;;4,5" +static void packIntInt(vector< vector > v, string &def) { + for (size_t j = 0; j < v.size(); j++) { + if (j>0) + def += ";"; + for (size_t k = 0; k < v[j].size(); k++) { + if (k>0) + def += ","; + def += itos(v[j][k]); + } + } +} + +InfoBase::InfoBase(int idIn) : id(idIn), committed(false){ +} + +InfoBase::InfoBase(const InfoBase &src) : id(src.id), committed(src.committed){ +} + +void InfoBase::operator=(const InfoBase &src) { +} + +InfoBase::~InfoBase() { +} + +int InfoBase::convertRelativeTime(const oBase &elem, int t) { + return t+elem.getEvent()->getZeroTimeNum(); +} + +InfoCompetition::InfoCompetition(int id) : InfoBase(id) { + forceComplete = true; +} + +InfoRadioControl::InfoRadioControl(int id) : InfoBase(id) { +} + +InfoClass::InfoClass(int id) : InfoBase(id) { +} + +InfoOrganization::InfoOrganization(int id) : InfoBase(id) { +} + +InfoBaseCompetitor::InfoBaseCompetitor(int id) : InfoBase(id) { + organizationId = 0; + classId = 0; + status = 0; + startTime = 0; + runningTime = 0; +} + +InfoCompetitor::InfoCompetitor(int id) : InfoBaseCompetitor(id) { + totalStatus = 0; + inputTime = 0; +} + +InfoTeam::InfoTeam(int id) : InfoBaseCompetitor(id) { +} + + +bool InfoCompetition::synchronize(oEvent &oe, const set &includeCls) { + bool changed = false; + if (oe.getName() != name) { + name = oe.getName(); + changed = true; + } + + if (oe.getDate() != date) { + date = oe.getDate(); + changed = true; + } + + if (oe.getDCI().getString("Organizer") != organizer) { + organizer = oe.getDCI().getString("Organizer"); + changed = true; + } + + if (oe.getDCI().getString("Homepage") != homepage) { + homepage = oe.getDCI().getString("Homepage"); + changed = true; + } + + if (changed) + needCommit(*this); + + vector ctrl; + oe.getControls(ctrl, true); + set knownId; + for (size_t k = 0; k < ctrl.size(); k++) { + if (ctrl[k]->isValidRadio()) { + vector ids; + ctrl[k]->getCourseControls(ids); + for (size_t j = 0; j < ids.size(); j++) { + int id = ids[j]; + knownId.insert(id); + map::iterator res = controls.find(id); + if (res == controls.end()) + res = controls.insert(make_pair(id, InfoRadioControl(id))).first; + if (res->second.synchronize(*ctrl[k], ids.size() > 1 ? j+1 : 0)) + needCommit(res->second); + } + } + } + + // Check if something was deleted + for (map::iterator it = controls.begin(); it != controls.end();) { + if (!knownId.count(it->first)) { + controls.erase(it++); + forceComplete = true; + } + else + ++it; + } + knownId.clear(); + + vector cls; + oe.getClasses(cls, false); + for (size_t k = 0; k < cls.size(); k++) { + int id = cls[k]->getId(); + if (!includeCls.count(id)) + continue; + knownId.insert(id); + map::iterator res = classes.find(id); + if (res == classes.end()) + res = classes.insert(make_pair(id, InfoClass(id))).first; + if (res->second.synchronize(*cls[k])) + needCommit(res->second); + } + + // Check if something was deleted + for (map::iterator it = classes.begin(); it != classes.end();) { + if (!knownId.count(it->first)) { + classes.erase(it++); + forceComplete = true; + } + else + ++it; + } + knownId.clear(); + + vector clb; + oe.getClubs(clb, false); + for (size_t k = 0; k < clb.size(); k++) { + int id = clb[k]->getId(); + knownId.insert(id); + map::iterator res = organizations.find(id); + if (res == organizations.end()) + res = organizations.insert(make_pair(id, InfoOrganization(id))).first; + if (res->second.synchronize(*clb[k])) + needCommit(res->second); + } + + // Check if something was deleted + for (map::iterator it = organizations.begin(); it != organizations.end();) { + if (!knownId.count(it->first)) { + organizations.erase(it++); + forceComplete = true; + } + else + ++it; + } + knownId.clear(); + + vector t; + oe.getTeams(0, t, false); + for (size_t k = 0; k < t.size(); k++) { + if (!includeCls.count(t[k]->getClassId())) + continue; + int id = t[k]->getId(); + knownId.insert(id); + map::iterator res = teams.find(id); + if (res == teams.end()) + res = teams.insert(make_pair(id, InfoTeam(id))).first; + if (res->second.synchronize(*t[k])) + needCommit(res->second); + } + + // Check if something was deleted + for (map::iterator it = teams.begin(); it != teams.end();) { + if (!knownId.count(it->first)) { + teams.erase(it++); + forceComplete = true; + } + else + ++it; + } + knownId.clear(); + + vector r; + oe.getRunners(0, 0, r, false); + for (size_t k = 0; k < r.size(); k++) { + if (!includeCls.count(r[k]->getClassId())) + continue; + int id = r[k]->getId(); + knownId.insert(id); + map::iterator res = competitors.find(id); + if (res == competitors.end()) + res = competitors.insert(make_pair(id, InfoCompetitor(id))).first; + if (res->second.synchronize(*this, *r[k])) + needCommit(res->second); + } + + // Check if something was deleted + for (map::iterator it = competitors.begin(); it != competitors.end();) { + if (!knownId.count(it->first)) { + competitors.erase(it++); + forceComplete = true; + } + else + ++it; + } + knownId.clear(); + + return !toCommit.empty() || forceComplete; +} + +void InfoCompetition::needCommit(InfoBase &obj) { + toCommit.push_back(&obj); +} + +bool InfoRadioControl::synchronize(oControl &c, int number) { + string n = c.hasName() ? c.getName() : c.getString(); + if (number > 0) + n = n + "-" + itos(number); + if (n == name) + return false; + else { + name = n; + modified(); + } + return true; +} + +void InfoRadioControl::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > prop; + prop.push_back(make_pair("id", itos(getId()))); + xml.write("ctrl", prop, name); +} + +bool InfoClass::synchronize(oClass &c) { + const string &n = c.getName(); + int no = c.getSortIndex(); + bool mod = false; + vector< vector > rc; + size_t s = c.getNumStages(); + + if (s > 0) { + linearLegNumberToActual.clear(); + + for (size_t k = 0; k < s; k++) { + if (!c.isParallel(k) && !c.isOptional(k)) { + pCourse pc = c.getCourse(k, 0, true); // Get a course representative for the leg. + + rc.push_back(vector()); + if (pc) { + vector ctrl; + pc->getControls(ctrl); + for (size_t j = 0; j < ctrl.size(); j++) { + if (ctrl[j]->isValidRadio()) { + rc.back().push_back(pc->getCourseControlId(j)); + } + } + } + } + // Setup transformation map (flat to 2D) + linearLegNumberToActual.push_back(max(0, rc.size()-1)); + + } + } + else { + // Single stage + linearLegNumberToActual.resize(1, 0); + pCourse pc = c.getCourse(true); // Get a course representative for the leg. + rc.push_back(vector()); + if (pc) { + vector ctrl; + pc->getControls(ctrl); + for (size_t j = 0; j < ctrl.size(); j++) { + if (ctrl[j]->isValidRadio()) { + //rc.back().push_back(pc->getCourseControlId(ctrl[j]->getId()); + rc.back().push_back(pc->getCourseControlId(j)); + } + } + } + } + + if (radioControls != rc) { + radioControls = rc; + mod = true; + } + + if (n != name || no != sortOrder) { + name = n; + sortOrder = no; + mod = true; + } + + if (mod) + modified(); + return mod; +} + +void InfoClass::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > prop; + prop.push_back(make_pair("id", itos(getId()))); + prop.push_back(make_pair("ord", itos(sortOrder))); + string def; + packIntInt(radioControls, def); + prop.push_back(make_pair("radio", def)); + xml.write("cls", prop, name); +} + +bool InfoOrganization::synchronize(oClub &c) { + const string &n = c.getDisplayName(); + if (n == name) + return false; + else { + name = n; + modified(); + } + return true; +} + +void InfoOrganization::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > prop; + prop.push_back(make_pair("id", itos(getId()))); + xml.write("org", prop, name); +} + +void InfoCompetition::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > prop; + prop.push_back(make_pair("date", date)); + prop.push_back(make_pair("organizer", organizer)); + prop.push_back(make_pair("homepage", homepage)); + xml.write("competition", prop, name); +} + +void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > prop; + prop.push_back(make_pair("org", itos(organizationId))); + prop.push_back(make_pair("cls", itos(classId))); + prop.push_back(make_pair("stat", itos(status))); + prop.push_back(make_pair("st", itos(startTime))); + prop.push_back(make_pair("rt", itos(runningTime))); + xml.write("base", prop, name); +} + +bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) { + const string &n = bc.getName(); + bool ch = false; + if (n != name) { + name = n; + ch = true; + } + + int cid = bc.getClubId(); + if (cid != organizationId) { + organizationId = cid; + ch = true; + } + + int cls = bc.getClassId(); + if (cls != classId) { + classId = cls; + ch = true; + } + + int s = bc.getStatus(); + if (status != s) { + status = s; + ch = true; + } + + int st = -1; + if (bc.startTimeAvailable()) + st = convertRelativeTime(bc, bc.getStartTime()) * 10; + + if (st != startTime) { + startTime = st; + ch = true; + } + + int rt = bc.getRunningTime() * 10; + if (rt != runningTime) { + runningTime = rt; + ch = true; + } + return ch; +} + +bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) { + bool ch = synchronizeBase(r); + + changeTotalSt = r.getEvent()->hasPrevStage() || r.getLegNumber()>0; // Always write full attributes + int s = r.getTotalStatusInput(); + if (totalStatus != s) { + totalStatus = s; + ch = true; + changeTotalSt = true; + } + + int legInput = r.getTotalTimeInput() * 10; + if (legInput != inputTime) { + inputTime = legInput; + ch = true; + changeTotalSt = true; + } + + vector newRT; + if (r.getClassId() > 0) { + const vector &radios = cmp.getControls(r.getClassId(), r.getLegNumber()); + for (size_t k = 0; k < radios.size(); k++) { + RadioTime radioTime; + RunnerStatus s_split; + radioTime.radioId = radios[k]; + r.getSplitTime(radioTime.radioId, s_split, radioTime.runningTime); + + if (radioTime.runningTime > 0) { + radioTime.runningTime*=10; + newRT.push_back(radioTime); + } + } + } + changeRadio = radioTimes.size() > 0;//false; // Always write full attributes + if (newRT != radioTimes) { + ch = true; + changeRadio = true; + radioTimes.swap(newRT); + } + + if (ch) + modified(); + return ch; +} + +void InfoCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > sprop; + sprop.push_back(make_pair("id", itos(getId()))); + xmlbuffer &subTag = xml.startTag("cmp", sprop); + InfoBaseCompetitor::serialize(subTag, diffOnly); + if (radioTimes.size() > 0 && (!diffOnly || changeRadio)) { + string radio; + radio.reserve(radioTimes.size() * 12); + for (size_t k = 0; k < radioTimes.size(); k++) { + if (k>0) + radio+=";"; + radio+=itos(radioTimes[k].radioId); + radio+=","; + radio+=itos(radioTimes[k].runningTime); + } + vector< pair > eprop; + subTag.write("radio", eprop, radio); + } + if (!diffOnly || changeTotalSt) { + vector< pair > prop; + prop.push_back(make_pair("it", itos(inputTime))); + prop.push_back(make_pair("tstat", itos(totalStatus))); + subTag.write("input", prop, ""); + } + xml.endTag(); +} + + +bool InfoTeam::synchronize(oTeam &t) { + bool ch = synchronizeBase(t); + + const pClass cls = t.getClassRef(); + if (cls) { + vector< vector > r; + + size_t s = cls->getNumStages(); + for (size_t k = 0; k < s; k++) { + pRunner rr = t.getRunner(k); + int rid = rr != 0 ? rr->getId() : 0; + + if (cls->isParallel(k) || cls->isOptional(k)) { + if (r.empty()) + r.push_back(vector()); // This is not a valid case, really + r.back().push_back(rid); + } + else + r.push_back(vector(1, rid)); + } + + if (r != competitors) { + r.swap(competitors); + ch = true; + } + + } + if (ch) + modified(); + return ch; +} + +void InfoTeam::serialize(xmlbuffer &xml, bool diffOnly) const { + vector< pair > prop; + prop.push_back(make_pair("id", itos(getId()))); + xmlbuffer &sub = xml.startTag("tm", prop); + InfoBaseCompetitor::serialize(sub, diffOnly); + string def; + packIntInt(competitors, def); + prop.clear(); + sub.write("r", prop, def); + sub.endTag(); +} + +const vector &InfoCompetition::getControls(int classId, int legNumber) const { + map::const_iterator res = classes.find(classId); + + if (res != classes.end()) { + if (size_t(legNumber) < res->second.linearLegNumberToActual.size()) + legNumber = res->second.linearLegNumberToActual[legNumber]; + else + legNumber = 0; + const vector< vector > &c = res->second.radioControls; + if (size_t(legNumber) < c.size()) + return c[legNumber]; + } + throw meosException("Internal class definition error"); +} + +void InfoCompetition::getCompleteXML(xmlbuffer &xml) { + xml.setComplete(true); + serialize(xml, false); + + for(map::iterator it = controls.begin(); it != controls.end(); ++it) { + it->second.serialize(xml, false); + } + + for(map::iterator it = classes.begin(); it != classes.end(); ++it) { + it->second.serialize(xml, false); + } + + for(map::iterator it = organizations.begin(); it != organizations.end(); ++it) { + it->second.serialize(xml, false); + } + + for(map::iterator it = teams.begin(); it != teams.end(); ++it) { + it->second.serialize(xml, false); + } + + for(map::iterator it = competitors.begin(); it != competitors.end(); ++it) { + it->second.serialize(xml, false); + } +} + +void InfoCompetition::getDiffXML(xmlbuffer &xml) { + if (forceComplete) { + getCompleteXML(xml); + return; + } + xml.setComplete(false); + for (list::iterator it = toCommit.begin(); it != toCommit.end(); ++it) { + (*it)->serialize(xml, true); + } +} + +void InfoCompetition::commitComplete() { + toCommit.clear(); + forceComplete = false; +} + +static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; + +static int mod_table[] = {0, 2, 1}; + +void base64_encode(const vector &input, string &encoded_data) { + + size_t input_length = input.size(); + size_t output_length = 4 * ((input_length + 2) / 3); + encoded_data.resize(output_length); + + for (size_t i = 0, j = 0; i < input_length;) { + unsigned octet_a = i < input_length ? input[i++] : 0; + unsigned octet_b = i < input_length ? input[i++] : 0; + unsigned octet_c = i < input_length ? input[i++] : 0; + + unsigned triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; + } + + for (int i = 0; i < mod_table[input_length % 3]; i++) + encoded_data[output_length - 1 - i] = '='; +} + +xmlbuffer &xmlbuffer::startTag(const char *tag, const vector< pair > &prop) { + blocks.push_back(block()); + blocks.back().tag = tag; + blocks.back().prop = prop; + blocks.back().subValues.push_back(xmlbuffer()); + return blocks.back().subValues.back(); +} + +void xmlbuffer::endTag() { +} + +void xmlbuffer::write(const char *tag, + const vector< pair > &prop, + const string &value) { + blocks.push_back(block()); + blocks.back().tag = tag; + blocks.back().prop = prop; + blocks.back().value = value; +} + +void xmlbuffer::startXML(xmlparser &xml, const string &dest) { + xml.openOutput(dest.c_str(), false); + if (complete) { + xml.startTag("MOPComplete", "xmlns", "http://www.melin.nu/mop"); + complete = false; + } + else + xml.startTag("MOPDiff", "xmlns", "http://www.melin.nu/mop"); +} + +bool xmlbuffer::commit(xmlparser &xml, int count) { + while (count>0 && !blocks.empty()) { + block &block = blocks.front(); + + if (block.subValues.empty()) { + xml.write(block.tag.c_str(), block.prop, block.value); + } + else { + vector p2; + for (size_t k = 0; k< block.prop.size(); k++) { + p2.push_back(block.prop[k].first); + p2.push_back(block.prop[k].second); + } + xml.startTag(block.tag.c_str(), p2); + + for (size_t k = 0; k < block.subValues.size(); k++) + block.subValues[k].commit(xml, numeric_limits::max()); + + xml.endTag(); + } + + count--; + blocks.pop_front(); + } + + return !blocks.empty(); +} diff --git a/code/infoserver.h b/code/infoserver.h new file mode 100644 index 0000000..23f521f --- /dev/null +++ b/code/infoserver.h @@ -0,0 +1,219 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +/** Class for keeping an external information server (online results) up-to-date */ + +#include +#include +#include + +class oBase; +class oEvent; +class oClass; +class oAbstractRunner; +class oRunner; +class oTeam; +class oClub; +class oControl; +class xmlparser; +class gdioutput; + + +class xmlbuffer { +private: + struct block { + string tag; + vector> prop; + string value; + vector subValues; + }; + + list blocks; + bool complete; +public: + void setComplete(bool c) {complete = c;} + xmlbuffer &startTag(const char *tag, const vector< pair > &prop); + void endTag(); + void write(const char *tag, + const vector< pair > &prop, + const string &value); + + size_t size() const {return blocks.size();} + bool commit(xmlparser &xml, int count); + + void startXML(xmlparser &xml, const string &dest); +}; + +class InfoBase +{ +private: + bool committed; + const int id; +protected: + void modified() {committed = false;} + virtual void serialize(xmlbuffer &xml, bool diffOnly) const = 0; + + // Converts a relative time to absolute time: + // number of tenths of a second since 00:00:00 on the day of + // the zero time of the competition + int convertRelativeTime(const oBase &elem, int t); +public: + + int getId() const {return id;} + bool isCommitted() const {return committed;} + + InfoBase(int id); + InfoBase(const InfoBase &in); + void operator=(const InfoBase &in); + virtual ~InfoBase(); + + friend class InfoCompetition; +}; + +typedef InfoBase * pInfoBase; + +class InfoRadioControl : public InfoBase { + protected: + string name; + bool synchronize(oControl &c, int number); + void serialize(xmlbuffer &xml, bool diffOnly) const; + public: + InfoRadioControl(int id); + virtual ~InfoRadioControl() {} + + friend class InfoCompetition; +}; + +class InfoClass : public InfoBase { + protected: + string name; + int sortOrder; + vector< vector > radioControls; + vector linearLegNumberToActual; + bool synchronize(oClass &c); + void serialize(xmlbuffer &xml, bool diffOnly) const; + public: + InfoClass(int id); + virtual ~InfoClass() {} + + friend class InfoCompetition; +}; + +class InfoOrganization : public InfoBase { + protected: + string name; + bool synchronize(oClub &c); + void serialize(xmlbuffer &xml, bool diffOnly) const; + public: + InfoOrganization(int id); + virtual ~InfoOrganization() {} + + friend class InfoCompetition; +}; + +struct RadioTime { + int radioId; + int runningTime; + + bool operator==(const RadioTime &t) const { + return radioId == t.radioId && runningTime == t.runningTime; + } +}; + +class InfoBaseCompetitor : public InfoBase { + protected: + string name; + int organizationId; + int classId; + + int status; + int startTime; + int runningTime; + void serialize(xmlbuffer &xml, bool diffOnly) const; + bool synchronizeBase(oAbstractRunner &bc); + public: + InfoBaseCompetitor(int id); + virtual ~InfoBaseCompetitor() {} +}; + +class InfoCompetitor : public InfoBaseCompetitor { + protected: + vector radioTimes; + int inputTime; + int totalStatus; + bool synchronize(const InfoCompetition &cmp, oRunner &c); + void serialize(xmlbuffer &xml, bool diffOnly) const; + bool changeTotalSt; + bool changeRadio; + public: + InfoCompetitor(int id); + virtual ~InfoCompetitor() {} + + friend class InfoCompetition; +}; + +class InfoTeam : public InfoBaseCompetitor { + protected: + // The outer level holds legs, the inner level holds (parallel/patrol) runners on each leg. + vector< vector > competitors; + bool synchronize(oTeam &t); + void serialize(xmlbuffer &xml, bool diffOnly) const; + public: + InfoTeam(int id); + virtual ~InfoTeam() {} + friend class InfoCompetition; +}; + +class InfoCompetition : public InfoBase { +private: + string name; + string date; + string organizer; + string homepage; +protected: + bool forceComplete; + + list toCommit; + + map controls; + map classes; + map organizations; + map competitors; + map teams; + + void needCommit(InfoBase &obj); + void serialize(xmlbuffer &xml, bool diffOnly) const; + + + public: + const vector &getControls(int classId, int legNumber) const; + bool synchronize(oEvent &oe, const set &classes); + + void getCompleteXML(xmlbuffer &xml); + void getDiffXML(xmlbuffer &xml); + + void commitComplete(); + + InfoCompetition(int id); + //InfoCompetition(const InfoCompetition &in); + virtual ~InfoCompetition() {} +}; diff --git a/code/inthashmap.h b/code/inthashmap.h new file mode 100644 index 0000000..38909d9 --- /dev/null +++ b/code/inthashmap.h @@ -0,0 +1,27 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "intkeymap.hpp" + +typedef intkeymap inthashmap; diff --git a/code/intkeymap.hpp b/code/intkeymap.hpp new file mode 100644 index 0000000..197e8e3 --- /dev/null +++ b/code/intkeymap.hpp @@ -0,0 +1,78 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2015 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Stigbergsvägen 7, SE-75242 UPPSALA, Sweden + +************************************************************************/ + +template class intkeymap { +private: + const static KEY NoKey = -1013; + + struct keypair { + KEY key; + T value; + }; + T dummy; + T tmp; + keypair *keys; + unsigned siz; + unsigned used; + intkeymap *next; + intkeymap *parent; + double allocFactor; + T noValue; + unsigned hash1; + unsigned hash2; + int level; + static int optsize(int arg); + + T &rehash(int size, KEY key, const T &value); + T &get(const KEY key); + + const intkeymap &operator=(const intkeymap &co); + void *lookup(KEY key) const; +public: + virtual ~intkeymap(); + intkeymap(int size); + intkeymap(); + intkeymap(const intkeymap &co); + + bool empty() const; + int size() const; + int getAlloc() const {return siz;} + void clear(); + + void resize(int size); + int count(KEY key) { + return lookup(key, dummy) ? 1:0; + } + bool lookup(KEY key, T &value) const; + + void insert(KEY key, const T &value); + void remove(KEY key); + void erase(KEY key) {remove(key);} + const T operator[](KEY key) const + {if (lookup(key,tmp)) return tmp; else return T();} + + T &operator[](KEY key) { + return get(key); + } +}; diff --git a/code/intkeymapimpl.hpp b/code/intkeymapimpl.hpp new file mode 100644 index 0000000..f73d88f --- /dev/null +++ b/code/intkeymapimpl.hpp @@ -0,0 +1,374 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2015 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Stigbergsvägen 7, SE-75242 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "intkeymap.hpp" + + + +template intkeymap::intkeymap() { + siz = 17; + allocFactor = 1.5; + keys = new keypair[siz]; + hash1 = siz / 2 + 3; + hash2 = siz / 3 + 2; + used = 0; + next = 0; + level = 0; + parent = 0; + dummy = 0; + noValue = 0; + clear(); +} + +template intkeymap::intkeymap(int _size) +{ + allocFactor = 1.3; + siz = optsize(_size); + keys = new keypair[siz]; + hash1 = siz / 2 + 3; + hash2 = siz / 3 + 2; + used = 0; + next = 0; + level = 0; + parent = 0; + dummy = T(); + noValue = T(); + clear(); +} + +template intkeymap::intkeymap(const intkeymap &co) +{ + allocFactor = co.allocFactor; + siz = co.siz; + keys = new keypair[siz]; + hash1 = co.hash1; + hash2 = co.hash2; + used = co.used; + level = co.level; + dummy = co.dummy; + noValue = co.noValue; + + for (unsigned k=0; k(*co.next); + next->parent = this; + } +} + +template intkeymap::~intkeymap() +{ + delete[] keys; + if (next) + delete next; +} + +template void intkeymap::clear() +{ + for (unsigned k=0;k void intkeymap::insert(KEY key, const T &value) +{ + if (key == NoKey) { + noValue = value; + return; + } + + keypair *ptr = (keypair *)lookup(key); + if (ptr) { + ptr->key = key; + ptr->value = value; + return; + } + + unsigned hk = unsigned(key) % siz; + + if (keys[hk].key == NoKey) + used++; + if (keys[hk].key == NoKey || keys[hk].key == key) { + keys[hk].key = key; + keys[hk].value = value; + return; + } + + hk = unsigned(key + hash1) % siz; + + if (keys[hk].key == NoKey) + used++; + if (keys[hk].key == NoKey || keys[hk].key == key) { + keys[hk].key = key; + keys[hk].value = value; + return; + } + + hk = unsigned(key + hash2) % siz; + + if (keys[hk].key == NoKey) + used++; + if (keys[hk].key == NoKey || keys[hk].key == key) { + keys[hk].key = key; + keys[hk].value = value; + return; + } + + if (next) { + next->insert(key, value); + return; + } + else if (level < 3) { + next = new intkeymap(siz/2); + next->level = level + 1; + next->parent = this; + next->insert(key, value); + return; + } + + rehash(0, key, value); +} + +template T &intkeymap::get(KEY key) +{ + keypair *ptr = (keypair *)lookup(key); + if (ptr) + return ptr->value; + + if (key == NoKey) + return noValue; + + unsigned hk = unsigned(key) % siz; + + if (keys[hk].key == NoKey) { + used++; + keys[hk].value = T(); + } + if (keys[hk].key == NoKey || keys[hk].key == key) { + keys[hk].key = key; + return keys[hk].value; + } + + hk = unsigned(key + hash1) % siz; + + if (keys[hk].key == NoKey) { + used++; + keys[hk].value = T(); + } + if (keys[hk].key == NoKey || keys[hk].key == key) { + keys[hk].key = key; + return keys[hk].value; + } + + hk = unsigned(key + hash2) % siz; + + if (keys[hk].key == NoKey) { + keys[hk].value = T(); + used++; + } + if (keys[hk].key == NoKey || keys[hk].key == key) { + keys[hk].key = key; + return keys[hk].value; + } + + if (next) { + return next->get(key); + } + else if (level < 3) { + next = new intkeymap(siz/2); + next->level = level + 1; + next->parent = this; + return next->get(key); + } + + return rehash(0, key, T()); +} + + +template void intkeymap::remove(KEY key) +{ + unsigned hk = unsigned(key) % siz; + if (keys[hk].key == key) { + keys[hk].key = NoKey; + used--; + return; + } + + hk = unsigned(key + hash1) % siz; + if (keys[hk].key == key) { + keys[hk].key = NoKey; + used--; + return; + } + + hk = unsigned(key + hash2) % siz; + if (keys[hk].key == key) { + keys[hk].key = NoKey; + used--; + return; + } + + if (next) { + next->remove(key); + return; + } +} + +template T &intkeymap::rehash(int _siz, KEY key, const T &value) +{ + if (parent) + return parent->rehash(_siz+used, key, value); + else { + intkeymap nm(int((_siz+used)*allocFactor)); + if (key != NoKey) + nm.insert(key, value); + + intkeymap *tmap = this; + while (tmap) { + int tsize = tmap->siz; + keypair *tkeys = tmap->keys; + for (int k=0; knext; + } + + // Swap + keypair *oldkeys = keys; + + //Take next + delete next; + next = nm.next; + nm.next = 0; + if (next) + next->parent = this; + + //Take keys + keys = nm.keys; + nm.keys = 0; + delete[] oldkeys; + + // Copy relevant data + siz = nm.siz; + used = nm.used; + hash1 = nm.hash1; + hash2 = nm.hash2; + + if (key!=NoKey) + return get(key); + return dummy; + } +} + +template bool intkeymap::lookup(KEY key, T &value) const +{ + keypair *ptr = (keypair *)lookup(key); + if (ptr) { + value = ptr->value; + return true; + } + else { + value = T(); + return false; + } +} + +template void *intkeymap::lookup(KEY key) const +{ + if (key == NoKey) { + return 0; + } + + unsigned hk = unsigned(key) % siz; + if (keys[hk].key == key) { + return (void *)&keys[hk]; + } + + hk = unsigned(key + hash1) % siz; + if (keys[hk].key == key) { + return (void *)&keys[hk]; + } + + hk = unsigned(key + hash2) % siz; + if (keys[hk].key == key) { + return (void *)&keys[hk]; + } + + if (next) + return next->lookup(key); + else + return 0; +} + +template int intkeymap::optsize(int a) { + if (a<5) + a = 5; + + if ((a&1) == 0) + a++; + + while (true) { + if (a%3 == 0) + a+=2; + else if (a%5 == 0) + a+=2; + else if (a%7 == 0) + a+=2; + else if (a%11 == 0) + a+=2; + else if (a%13 == 0) + a+=2; + else + return a; + } +} + +template int intkeymap::size() const +{ + if (next) + return used + next->size(); + else + return used; +} + +template bool intkeymap::empty() const +{ + return used==0 && (next==0 || next->empty()); +} + +template void intkeymap::resize(int size) +{ + allocFactor = 1.0; + rehash(size, NoKey, 0); + allocFactor = 1.3; +} diff --git a/code/iof30interface.cpp b/code/iof30interface.cpp new file mode 100644 index 0000000..c2c9d7f --- /dev/null +++ b/code/iof30interface.cpp @@ -0,0 +1,3508 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include + +#include "iof30interface.h" +#include "oEvent.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "xmlparser.h" +#include "RunnerDB.h" +#include "meos_util.h" +#include "meosException.h" +#include "localizer.h" + +string &getFirst(string &inout, int maxNames); +string getMeosCompectVersion(); + +IOF30Interface::IOF30Interface(oEvent *oe, bool forceSplitFee) : oe(*oe), useGMT(false), teamsAsIndividual(false), + entrySourceId(1), unrollLoops(true), + includeStageRaceInfo(true) { + cachedStageNumber = -1; + splitLateFee = forceSplitFee || oe->getPropertyInt("SplitLateFees", false) == 1; +} + +void IOF30Interface::readCourseData(gdioutput &gdi, const xmlobject &xo, bool updateClass, + int &courseCount, int &failed) { + string ver; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + courseCount = 0; + failed = 0; + xmlList xl; + xo.getObjects("RaceCourseData", xl); + xmlList::const_iterator it; + xmlobject xRaceCourses; + if (xl.size() == 1) { + xRaceCourses = xl[0]; + } + else { + int nr = getStageNumber(); + int ix = -1; + for (size_t k = 0; k < xl.size(); k++) { + if (xl[k].getObjectInt("raceNumber") == nr) { + ix = k; + break; + } + } + if (ix == -1) + throw meosException("Filen innehåller flera uppsättningar banor, men ingen har samma etappnummer som denna etapp (X).#" + itos(nr)); + else + xRaceCourses = xl[ix]; + } + + xmlList xControls, xCourse, x; + xRaceCourses.getObjects("Control", xControls); + xRaceCourses.getObjects("Course", xCourse); + + for (size_t k = 0; k < xControls.size(); k++) { + readControl(xControls[k]); + } + + map courses; + map > coursesFamilies; + + for (size_t k = 0; k < xCourse.size(); k++) { + pCourse pc = readCourse(xCourse[k]); + if (pc) { + courseCount++; + if (courses.count(pc->getName())) + gdi.addString("", 0, "Varning: Banan 'X' förekommer flera gånger#" + pc->getName()); + + courses[pc->getName()] = pc; + + string family; + xCourse[k].getObjectString("CourseFamily", family); + + if (!family.empty()) { + coursesFamilies[family].push_back(pc); + } + } + else + failed++; + } + + if (!updateClass) + return; + + + xmlList xClassAssignment, xTeamAssignment, xPersonAssignment; + xRaceCourses.getObjects("ClassCourseAssignment", xClassAssignment); + if (xClassAssignment.size() > 0) + classCourseAssignment(gdi, xClassAssignment, courses, coursesFamilies); + + xRaceCourses.getObjects("PersonCourseAssignment", xPersonAssignment); + if (xPersonAssignment.size() > 0) + personCourseAssignment(gdi, xPersonAssignment, courses); + + xRaceCourses.getObjects("TeamCourseAssignment", xTeamAssignment); + if (xTeamAssignment.size() > 0) + teamCourseAssignment(gdi, xTeamAssignment, courses); + + xmlList xAssignment; + xRaceCourses.getObjects("CourseAssignment", xAssignment); + if (xAssignment.size() > 0) { + classAssignmentObsolete(gdi, xAssignment, courses, coursesFamilies); + } + +} + +void IOF30Interface::classCourseAssignment(gdioutput &gdi, xmlList &xAssignment, + const map &courses, + const map > &coursesFamilies) { + + map< pair, vector > classIdLegToCourse; + + for (size_t k = 0; k < xAssignment.size(); k++) { + xmlobject &xClsAssignment = xAssignment[k]; + map > cls2Stages; + + xmlList xClsId; + xClsAssignment.getObjects("ClassId", xClsId); + for (size_t j = 0; j ())); + } + + if (cls2Stages.empty()) { + string cname; + xClsAssignment.getObjectString("ClassName", cname); + if (cname.length() > 0) { + pClass pc = oe.getClassCreate(0, cname); + if (pc) + cls2Stages.insert(make_pair(pc->getId(), vector()) ); + } + } + + if (cls2Stages.empty()) { + gdi.addString("", 0, "Klass saknad").setColor(colorRed); + continue; + } + + // Allowed on leg + xmlList xLeg; + xClsAssignment.getObjects("AllowedOnLeg", xLeg); + + for (map >::iterator it = cls2Stages.begin(); it != cls2Stages.end(); ++it) { + pClass defClass = oe.getClass(it->first); + vector &legs = it->second; + + // Convert from leg/legorder to real leg number + for (size_t j = 0; j getNumStages() > 0) { + for (unsigned i = 0; i < defClass->getNumStages(); i++) { + int realLeg, legIx; + defClass->splitLegNumberParallel(i, realLeg, legIx); + if (realLeg == leg) + legs.push_back(i); + } + } + else + legs.push_back(leg); + } + if (legs.empty()) + legs.push_back(-1); // All legs + } + // Extract courses / families + xmlList xCourse; + xClsAssignment.getObjects("CourseName", xCourse); + + xmlList xFamily; + string t, t1, t2; + xClsAssignment.getObjects("CourseFamily", xFamily); + + for (map >::iterator it = cls2Stages.begin(); it != cls2Stages.end(); ++it) { + const vector &legs = it->second; + for (size_t m = 0; m < legs.size(); m++) { + int leg = legs[m]; + for (size_t j = 0; j < xFamily.size(); j++) { + for (size_t i = 0; i < xCourse.size(); i++) { + string crs = constructCourseName(xFamily[j].getObjectString(0, t1), + xCourse[i].getObjectString(0, t2)); + classIdLegToCourse[make_pair(it->first, leg)].push_back(crs); + } + } + if (xFamily.empty()) { + for (size_t i = 0; i < xCourse.size(); i++) { + string crs = constructCourseName("", xCourse[i].getObjectString(0, t)); + classIdLegToCourse[make_pair(it->first, leg)].push_back(crs); + } + } + if (xCourse.empty()) { + for (size_t j = 0; j < xFamily.size(); j++) { + map >::const_iterator res = + coursesFamilies.find(xFamily[j].getObjectString(0, t)); + + + if (res != coursesFamilies.end()) { + const vector &family = res->second; + for (size_t i = 0; i < family.size(); i++) { + classIdLegToCourse[make_pair(it->first, leg)].push_back(family[i]->getName()); + } + } + } + } + } + } + } + + map< pair, vector >::iterator it; + for (it = classIdLegToCourse.begin(); it != classIdLegToCourse.end(); ++it) { + pClass pc = oe.getClass(it->first.first); + if (pc) { + pc->setCourse(0); + for (size_t k = 0; k < pc->getNumStages(); k++) + pc->clearStageCourses(k); + } + } + for (it = classIdLegToCourse.begin(); it != classIdLegToCourse.end(); ++it) { + pClass pc = oe.getClass(it->first.first); + unsigned leg = it->first.second; + const vector &crs = it->second; + vector pCrs; + for (size_t k = 0; k < crs.size(); k++) { + map::const_iterator res = courses.find(crs[k]); + pCourse c = res != courses.end() ? res->second : 0; + if (c == 0) + gdi.addString("", 0, "Varning: Banan 'X' finns inte#" + crs[k]).setColor(colorRed); + pCrs.push_back(c); + } + if (pCrs.empty()) + continue; + + if (leg == -1) { + if (pCrs.size() > 1) { + if (!pc->hasMultiCourse()) { + pc->setNumStages(1); + } + } + + if (pc->hasMultiCourse()) { + for (size_t k = 0; k < pc->getNumStages(); k++) { + for (size_t j = 0; j < pCrs.size(); j++) + pc->addStageCourse(k, pCrs[j]); + } + } + else + pc->setCourse(pCrs[0]); + } + else if (leg == 0 && pCrs.size() == 1) { + if (pc->hasMultiCourse()) + pc->addStageCourse(0, pCrs[0]); + else + pc->setCourse(pCrs[0]); + } + else { + if (leg >= pc->getNumStages()) + pc->setNumStages(leg+1); + + for (size_t j = 0; j < pCrs.size(); j++) + pc->addStageCourse(leg, pCrs[j]); + } + } +} + +void IOF30Interface::personCourseAssignment(gdioutput &gdi, xmlList &xAssignment, + const map &courses) { + vector allR; + oe.getRunners(0, 0, allR, false); + map bib2Runner; + multimap name2Runner; + for (size_t k = 0; k < allR.size(); k++) { + string bib = allR[k]->getBib(); + if (!bib.empty()) + bib2Runner[bib] = allR[k]; + + name2Runner.insert(make_pair(allR[k]->getName(), allR[k])); + } + + for (size_t k = 0; k < xAssignment.size(); k++) { + xmlobject &xPAssignment = xAssignment[k]; + pRunner r = 0; + + string runnerText; + string bib; + xPAssignment.getObjectString("BibNumber", bib); + + if (!bib.empty()) { + runnerText = bib; + r = bib2Runner[bib]; + } + + if (r == 0) { + int id = xPAssignment.getObjectInt("EntryId"); // This assumes entryId = personId, which may or may not be the case. + if (id != 0) { + runnerText = "Id = "+itos(id); + r = oe.getRunner(id, 0); + } + } + + if (r == 0) { + string person; + xPAssignment.getObjectString("PersonName", person); + if (!person.empty()) { + runnerText = person; + string cls; + xPAssignment.getObjectString("ClassName", cls); + multimap::const_iterator res = name2Runner.find(person); + while (res != name2Runner.end() && person == res->first) { + if (cls.empty() || res->second->getClass() == cls) { + r = res->second; + break; + } + ++res; + } + } + } + + if (r == 0) { + gdi.addString("", 0, "Varning: Deltagaren 'X' finns inte.#" + runnerText).setColor(colorRed); + continue; + } + + pCourse c = findCourse(gdi, courses, xPAssignment); + if (c == 0) + continue; + + r->setCourseId(c->getId()); + } +} + +pCourse IOF30Interface::findCourse(gdioutput &gdi, + const map &courses, + xmlobject &xPAssignment) { + string course; + xPAssignment.getObjectString("CourseName", course); + string family; + xPAssignment.getObjectString("CourseFamily", family); + string fullCrs = constructCourseName(family, course); + + map::const_iterator res = courses.find(fullCrs); + pCourse c = res != courses.end() ? res->second : 0; + if (c == 0) { + gdi.addString("", 0, "Varning: Banan 'X' finns inte.#" + fullCrs).setColor(colorRed); + } + return c; +} + +void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment, + const map &courses) { + vector allT; + oe.getTeams(0, allT, false); + + map bib2Team; + map, pTeam> nameClass2Team; + for (size_t k = 0; k < allT.size(); k++) { + string bib = allT[k]->getBib(); + if (!bib.empty()) + bib2Team[bib] = allT[k]; + + nameClass2Team[make_pair(allT[k]->getName(), allT[k]->getClass())] = allT[k]; + } + + for (size_t k = 0; k < xAssignment.size(); k++) { + xmlobject &xTAssignment = xAssignment[k]; + pTeam t = 0; + string teamText; + string bib; + xTAssignment.getObjectString("BibNumber", bib); + + if (!bib.empty()) { + teamText = bib; + t = bib2Team[bib]; + } + + if (t == 0) { + string team; + xTAssignment.getObjectString("TeamName", team); + if (!team.empty()) { + string cls; + xTAssignment.getObjectString("ClassName", cls); + t = nameClass2Team[make_pair(team, cls)]; + teamText = team + " / " + cls; + } + } + + if (t == 0) { + gdi.addString("", 0, "Varning: Laget 'X' finns inte.#" + teamText).setColor(colorRed); + continue; + } + + xmlList teamMemberAssignment; + xTAssignment.getObjects("TeamMemberCourseAssignment", teamMemberAssignment); + assignTeamCourse(gdi, *t, teamMemberAssignment, courses); + } +} + +void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAssignment, + const map &courses) { + + if (!team.getClassRef()) + return; + for (size_t k = 0; k getLegNumberLinear(leg, legorder); + if (legId>=0) { + pRunner r = team.getRunner(legId); + if (r == 0) { + r = oe.addRunner(lang.tl("N.N."), team.getClubId(), team.getClassId(), 0, 0, false); + if (r) { + r->setEntrySource(entrySourceId); + r->flagEntryTouched(true); + } + team.setRunner(legId, r, false); + r = team.getRunner(legId); + } + if (r) { + r->setCourseId(c->getId()); + } + } + else + gdi.addString("", 0, "Bantilldelning för 'X' hänvisar till en sträcka som inte finns#" + team.getClass()).setColor(colorRed); + } + else { + string name; + xAssignment[k].getObjectString("TeamMemberName", name); + if (!name.empty()) { + for (int j = 0; j < team.getNumRunners(); j++) { + pRunner r = team.getRunner(j); + if (r && r->getName() == name) { + r->setCourseId(c->getId()); + break; + } + } + } + } + } +} + + +void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignment, + const map &courses, + const map > &coursesFamilies) { + map > class2Courses; + map > class2Families; + + multimap bib2Runners; + typedef multimap::iterator bibIterT; + bool b2RInit = false; + + map, pTeam> clsName2Team; + typedef map, pTeam>::iterator teamIterT; + bool c2TeamInit = false; + + for (size_t k = 0; k < xAssignment.size(); k++) { + string name = constructCourseName(xAssignment[k]); + string family; + xAssignment[k].getObjectString("CourseFamily", family); + + if ( courses.find(name) == courses.end() ) + gdi.addString("", 0, "Varning: Banan 'X' finns inte#" + name); + else { + pCourse pc = courses.find(name)->second; + xmlList xCls, xPrs; + xAssignment[k].getObjects("Class", xCls); + xAssignment[k].getObjects("Person", xPrs); + + for (size_t j = 0; j < xCls.size(); j++) { + string cName; + xCls[j].getObjectString("Name", cName); + int id = xCls[j].getObjectInt("Id"); + pClass cls = oe.getClassCreate(id, cName); + if (cls) { + class2Courses[cls->getId()].push_back(pc); + + if (!family.empty()) { + class2Families[cls->getId()].insert(family); + } + } + } + + for (size_t j = 0; j < xPrs.size(); j++) { + string bib; + int leg = xPrs[j].getObjectInt("Leg"); + int legOrder = xPrs[j].getObjectInt("LegOrder"); + + xPrs[j].getObjectString("BibNumber", bib); + if (!bib.empty()) { + if (!b2RInit) { + // Setup bib2runner map + vector r; + oe.getRunners(0, 0, r); + for (size_t i = 0; i < r.size(); i++) { + string b = r[i]->getBib(); + if (!b.empty()) + bib2Runners.insert(make_pair(b, r[i])); + } + b2RInit = true; + } + + pair range = bib2Runners.equal_range(bib); + for (bibIterT it = range.first; it != range.second; ++it) { + int ln = it->second->getLegNumber(); + int rLegNumber = 0, rLegOrder = 0; + if (it->second->getClassRef()) + it->second->getClassRef()->splitLegNumberParallel(ln, rLegNumber, rLegOrder); + bool match = true; + if (leg != 0 && leg != rLegNumber+1) + match = false; + if (legOrder != 0 && legOrder != rLegOrder+1) + match = false; + + if (match) { + it->second->setCourseId(pc->getId()); + it->second->synchronize(); + } + } + continue; + } + + string className, teamName; + xPrs[j].getObjectString("ClassName", className); + xPrs[j].getObjectString("TeamName", teamName); + + if (!teamName.empty()) { + if (!c2TeamInit) { + vector t; + oe.getTeams(0, t); + for (size_t i = 0; i < t.size(); i++) + clsName2Team[make_pair(t[i]->getClass(), t[i]->getName())] = t[i]; + c2TeamInit = true; + } + + teamIterT res = clsName2Team.find(make_pair(className, teamName)); + + if (res != clsName2Team.end()) { + pClass cls = res->second->getClassRef(); + if (cls) { + int ln = cls->getLegNumberLinear(leg, legOrder); + pRunner r = res->second->getRunner(ln); + if (r) { + r->setCourseId(pc->getId()); + r->synchronize(); + } + } + } + continue; + } + + // Note: entryId is assumed to be equal to personId, + // which is the only we have. This might not be true. + int entryId = xPrs[j].getObjectInt("EntryId"); + pRunner r = oe.getRunner(entryId, 0); + if (r) { + r->setCourseId(pc->getId()); + r->synchronize(); + } + } + } + } + + if (!class2Families.empty()) { + vector c; + oe.getClasses(c, false); + for (size_t k = 0; k < c.size(); k++) { + bool assigned = false; + + if (class2Families.count(c[k]->getId())) { + const set &families = class2Families[c[k]->getId()]; + + if (families.size() == 1) { + int nl = c[k]->getNumStages(); + const vector &crsFam = coursesFamilies.find(*families.begin())->second; + if (nl == 0) { + if (crsFam.size() == 1) + c[k]->setCourse(crsFam[0]); + else { + c[k]->setNumStages(1); + c[k]->clearStageCourses(0); + for (size_t j = 0; j < crsFam.size(); j++) + c[k]->addStageCourse(0, crsFam[j]->getId()); + } + } + else { + int nFam = crsFam.size(); + for (int i = 0; i < nl; i++) { + c[k]->clearStageCourses(i); + for (int j = 0; j < nFam; j++) + c[k]->addStageCourse(i, crsFam[(j + i)%nFam]->getId()); + } + } + assigned = true; + } + else if (families.size() > 1) { + int nl = c[k]->getNumStages(); + if (nl == 0) { + c[k]->setNumStages(families.size()); + nl = families.size(); + } + + set::const_iterator fit = families.begin(); + for (int i = 0; i < nl; i++, ++fit) { + if (fit == families.end()) + fit = families.begin(); + c[k]->clearStageCourses(i); + const vector &crsFam = coursesFamilies.find(*fit)->second; + int nFam = crsFam.size(); + for (int j = 0; j < nFam; j++) + c[k]->addStageCourse(i, crsFam[j]->getId()); + } + + assigned = true; + } + } + + if (!assigned && class2Courses.count(c[k]->getId())) { + const vector &crs = class2Courses[c[k]->getId()]; + int nl = c[k]->getNumStages(); + + if (crs.size() == 1 && nl == 0) { + c[k]->setCourse(crs[0]); + } + else if (crs.size() > 1) { + int nCrs = crs.size(); + for (int i = 0; i < nl; i++) { + c[k]->clearStageCourses(i); + for (int j = 0; j < nCrs; j++) + c[k]->addStageCourse(i, crs[(j + i)%nCrs]->getId()); + } + } + } + c[k]->synchronize(); + } + } +} + +void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount) { + if (!xo) + return; + + string ver; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for (it=xl.begin(); it != xl.end(); ++it) { + if (it->is("Competitor")) { + if (readXMLCompetitorDB(*it)) + personCount++; + } + } +} + +void IOF30Interface::readClubList(gdioutput &gdi, const xmlobject &xo, int &clubCount) { + if (!xo) + return; + + string ver; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + for (it=xl.begin(); it != xl.end(); ++it) { + if (it->is("Organisation")) { + if (readOrganization(gdi, *it, true)) + clubCount++; + } + } +} + + +void IOF30Interface::readEntryList(gdioutput &gdi, xmlobject &xo, bool removeNonexiting, + int &entRead, int &entFail, int &entRemoved) { + string ver; + entRemoved = 0; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + + xmlobject xEvent = xo.getObject("Event"); + map > teamClassConfig; + map > bibPatterns; + oClass::extractBibPatterns(oe, bibPatterns); + + if (xEvent) { + readEvent(gdi, xEvent, teamClassConfig); + } + + vector allR; + vector allT; + oe.getRunners(0, 0, allR, false); + for (size_t k = 0; k < allR.size(); k++) { + if (allR[k]->getEntrySource() == entrySourceId) + allR[k]->flagEntryTouched(false); + } + + oe.getTeams(0, allT, false); + for (size_t k = 0; k < allT.size(); k++) { + if (allT[k]->getEntrySource() == entrySourceId) + allT[k]->flagEntryTouched(false); + } + + xmlList pEntries; + xo.getObjects("PersonEntry", pEntries); + map > > personId2TeamLeg; + for (size_t k = 0; k < pEntries.size(); k++) { + if (readPersonEntry(gdi, pEntries[k], 0, teamClassConfig, personId2TeamLeg)) + entRead++; + else + entFail++; + } + + xo.getObjects("TeamEntry", pEntries); + for (size_t k = 0; k < pEntries.size(); k++) { + setupClassConfig(0, pEntries[k], teamClassConfig); + } + + // Get all classes, and use existing leg info + vector allCls; + oe.getClasses(allCls, false); + for (size_t k = 0; k < allCls.size(); k++) { + if (allCls[k]->getNumStages() > 1) { + for (size_t j = 0; j < allCls[k]->getNumStages(); j++) { + int number; + int order; + allCls[k]->splitLegNumberParallel(j, number, order); + vector &li = teamClassConfig[allCls[k]->getId()]; + + if (size_t(number) >= li.size()) + li.resize(number+1); + + if (allCls[k]->getLegType(j) == LTExtra || allCls[k]->getLegType(j) == LTIgnore || allCls[k]->getLegType(j) == LTParallelOptional) + li[number].setMaxRunners(order+1); + else + li[number].setMinRunners(order+1); + } + } + } + + setupRelayClasses(teamClassConfig); + + for (size_t k = 0; k < pEntries.size(); k++) { + if (readTeamEntry(gdi, pEntries[k], bibPatterns, teamClassConfig, personId2TeamLeg)) + entRead++; + else + entFail++; + } + + bool hasMulti = false; + for (map > >::iterator it = personId2TeamLeg.begin(); + it != personId2TeamLeg.end(); ++it) { + if (it->second.size() > 1) { + hasMulti = true; + break; + } + } + + // Analyze equivalences of legs + map > > classLegEqClasses; + + for (map > >::iterator it = personId2TeamLeg.begin(); + it != personId2TeamLeg.end(); ++it) { + const vector< pair > &teamLeg = it->second; + if (teamLeg.empty()) + continue; // Should not happen + int minLeg = teamLeg.front().second; + int teamId = teamLeg.front().first; + bool inconsistentTeam = false; + + for (size_t i = 1; i < teamLeg.size(); i++) { + if (teamLeg[i].first != teamId) { + inconsistentTeam = true; + break; + } + if (teamLeg[i].second < minLeg) + minLeg = teamLeg[i].second; + } + + if (!inconsistentTeam) { + pTeam t = oe.getTeam(teamId); + if (t) { + if (minLeg != teamLeg.front().second) { + pRunner r = t->getRunner(teamLeg.front().second); + t->setRunner(minLeg, r, true); + t->synchronize(true); + } + + // If multi, for each class, store how the legs was multiplied + if (hasMulti) { + vector key(it->second.size()); + for (size_t j = 0; j < key.size(); j++) + key[j] = it->second[j].second; + + sort(key.begin(), key.end()); + classLegEqClasses[t->getClassId()].insert(key); + } + } + } + } + + for (map > >::const_iterator it = classLegEqClasses.begin(); + it != classLegEqClasses.end(); ++it) { + const set< vector > &legEq = it->second; + pClass cls = oe.getClass(it->first); + if (!cls) + continue; + bool invalid = false; + vector specification(cls->getNumStages(), -2); + for (set< vector >::const_iterator eqit = legEq.begin(); eqit != legEq.end(); ++eqit) { + const vector &eq = *eqit; + for (size_t j = 0; j < eq.size(); j++) { + size_t ix = eq[j]; + if (ix >= specification.size()) { + invalid = true; + break; // Internal error? + } + if (j == 0) { // Base leg + if (specification[ix] >= 0) { + invalid = true; + break; // Inconsistent specification + } + else { + specification[ix] = -1; + } + } + else { // Duplicated leg + if (specification[ix] == -1 || (specification[ix] >= 0 && specification[ix] != eq[0])) { + invalid = true; + break; // Inconsistent specification + } + else { + specification[ix] = eq[0]; // Specify duplication of base leg + } + } + } + } + if (invalid) + continue; + + vector teams; + oe.getTeams(it->first, teams); + + // Check that the guessed specification is compatible with all current teams + for (size_t j = 0; j < specification.size(); j++) { + if (specification[j] >= 0) { + // Check that leg is not occupied + for (size_t i = 0; i < teams.size(); i++) { + if (teams[i]->getRunner(j) && teams[i]->getRunner(j)->getRaceNo() == 0) { + invalid = true; + break; + } + } + } + } + + if (invalid) + continue; + + for (size_t j = 0; j < specification.size(); j++) { + if (specification[j] >= 0) { + cls->setLegRunner(j, specification[j]); + } + } + oe.adjustTeamMultiRunners(cls); + } + + if (removeNonexiting && entRead > 0) { + for (size_t k = 0; k < allT.size(); k++) { + if (allT[k]->getEntrySource() == entrySourceId && !allT[k]->isEntryTouched()) { + oe.removeTeam(allT[k]->getId()); + gdi.addString("", 0, "Tar bort X#" + allT[k]->getName()); + entRemoved++; + } + /*else { + for (int i = 0; i < allT[k]->getNumRunners(); i++) { + pRunner r = allT[k]->getRunner(i); + if (r) + r->flagEntryTouched(true); + } + }*/ + } + + vector rids; + for (size_t k = 0; k < allR.size(); k++) { + if (allR[k]->getEntrySource() == entrySourceId && !allR[k]->isEntryTouched() && !allR[k]->getTeam()) { + entRemoved++; + gdi.addString("", 0, "Tar bort X#" + allR[k]->getCompleteIdentification()); + rids.push_back(allR[k]->getId()); + } + } + if (!rids.empty()) + oe.removeRunner(rids); + } +} + + +void IOF30Interface::readStartList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail) { + string ver; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + + map > teamClassConfig; + + xmlobject xEvent = xo.getObject("Event"); + if (xEvent) { + readEvent(gdi, xEvent, teamClassConfig); + } + + xmlList cStarts; + xo.getObjects("ClassStart", cStarts); + + struct RaceInfo { + int courseId; + int length; + int climb; + string startName; + }; + + for (size_t k = 0; k < cStarts.size(); k++) { + xmlobject &xClassStart = cStarts[k]; + + pClass pc = readClass(xClassStart.getObject("Class"), + teamClassConfig); + int classId = pc ? pc->getId() : 0; + + + map raceToInfo; + + xmlList courses; + xClassStart.getObjects("Course", courses); + for (size_t k = 0; k < courses.size(); k++) { + int raceNo = courses[k].getObjectInt("raceNumber"); + if (raceNo > 0) + raceNo--; + RaceInfo &raceInfo = raceToInfo[raceNo]; + + raceInfo.courseId = courses[k].getObjectInt("Id"); + raceInfo.length = courses[k].getObjectInt("Length"); + raceInfo.climb = courses[k].getObjectInt("Climb"); + } + + xmlList startNames; + xClassStart.getObjects("StartName", startNames); + for (size_t k = 0; k < startNames.size(); k++) { + int raceNo = startNames[k].getObjectInt("raceNumber"); + if (raceNo > 0) + raceNo--; + RaceInfo &raceInfo = raceToInfo[raceNo]; + startNames[k].getObjectString(0, raceInfo.startName); + pc->setStart(raceInfo.startName); + } + + if (raceToInfo.size() == 1) { + RaceInfo &raceInfo = raceToInfo.begin()->second; + if (raceInfo.courseId > 0) { + if (pc->getCourse() == 0) { + pCourse crs = oe.addCourse(pc->getName(), raceInfo.length, raceInfo.courseId); + crs->setStart(raceInfo.startName, false); + crs->getDI().setInt("Climb", raceInfo.climb); + pc->setCourse(crs); + crs->synchronize(); + } + } + } + else if (raceToInfo.size() > 1) { + } + + xmlList xPStarts; + xClassStart.getObjects("PersonStart", xPStarts); + map > bibPatterns; + oClass::extractBibPatterns(oe, bibPatterns); + + for (size_t k = 0; k < xPStarts.size(); k++) { + if (readPersonStart(gdi, pc, xPStarts[k], 0, teamClassConfig)) + entRead++; + else + entFail++; + } + + xmlList tEntries; + xClassStart.getObjects("TeamStart", tEntries); + for (size_t k = 0; k < tEntries.size(); k++) { + setupClassConfig(classId, tEntries[k], teamClassConfig); + } + + //setupRelayClasses(teamClassConfig); + if (pc && teamClassConfig.count(pc->getId()) && !teamClassConfig[pc->getId()].empty()) { + setupRelayClass(pc, teamClassConfig[pc->getId()]); + } + + for (size_t k = 0; k < tEntries.size(); k++) { + if (readTeamStart(gdi, pc, tEntries[k], bibPatterns, teamClassConfig)) + entRead++; + else + entFail++; + } + + pc->synchronize(); + } +} + +void IOF30Interface::readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail) { + string ver; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + + map > teamClassConfig; + + xmlobject xEvent = xo.getObject("Event"); + if (xEvent) { + readEvent(gdi, xEvent, teamClassConfig); + } + + xmlList cClass; + xo.getObjects("Class", cClass); + + + for (size_t k = 0; k < cClass.size(); k++) { + xmlobject &xClass = cClass[k]; + + pClass pc = readClass(xClass, teamClassConfig); + + if (pc) + entRead++; + else + entFail++; + + if (pc && teamClassConfig.count(pc->getId()) && !teamClassConfig[pc->getId()].empty()) { + setupRelayClass(pc, teamClassConfig[pc->getId()]); + } + + pc->synchronize(); + } +} + +void IOF30Interface::readEventList(gdioutput &gdi, xmlobject &xo) { + if (!xo) + return; + + string ver; + xo.getObjectString("iofVersion", ver); + if (!ver.empty() && ver > "3.0") + gdi.addString("", 0, "Varning, okänd XML-version X#" + ver); + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + map > teamClassConfig; + for (it=xl.begin(); it != xl.end(); ++it) { + if (it->is("Event")) { + readEvent(gdi, *it, teamClassConfig); + return; + } + } +} + +void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo, + map > &teamClassConfig) { + + string name; + xo.getObjectString("Name", name); + oe.setName(name); + + int id = xo.getObjectInt("Id"); + if (id>0) { + oe.setExtIdentifier(id); + entrySourceId = id; + } + else { + entrySourceId = 1; // Use this as a default number for "imported entries" + } + + xmlobject date = xo.getObject("StartTime"); + + if (date) { + string dateStr; + date.getObjectString("Date", dateStr); + oe.setDate(dateStr); + string timeStr; + date.getObjectString("Time", timeStr); + if (!timeStr.empty()) { + int t = convertAbsoluteTimeISO(timeStr); + if (t >= 0 && oe.getNumRunners() == 0) { + int zt = t - 3600; + if (zt < 0) + zt += 3600*24; + oe.setZeroTime(formatTimeHMS(zt)); + } + } + //oe.setZeroTime(...); + } + + xmlobject xOrg = xo.getObject("Organiser"); + oDataInterface DI = oe.getDI(); + + if (xOrg) { + string name; + xOrg.getObjectString("Name", name); + if (name.length() > 0) + DI.setString("Organizer", name); + + xmlobject address = xOrg.getObject("Address"); + + string tmp; + + if (address) { + DI.setString("CareOf", address.getObjectString("CareOf", tmp)); + DI.setString("Street", address.getObjectString("Street", tmp)); + string city, zip, state; + address.getObjectString("City", city); + address.getObjectString("ZipCode", zip); + address.getObjectString("State", state); + if (state.empty()) + DI.setString("Address", zip + " " + city); + else + DI.setString("Address", state + ", " + zip + " " + city); + } + + xmlList xContact; + xOrg.getObjects("Contact", xContact); + + string phone; + for (size_t k = 0; k < xContact.size(); k++) { + string type; + xContact[k].getObjectString("type", type); + string c; + xContact[k].getObjectString(0, c); + + if (type == "PhoneNumber" || "MobilePhoneNumber") + phone += phone.empty() ? c : ", " + c; + else if (type == "EmailAddress") + DI.setString("EMail", c); + else if (type == "WebAddress") + DI.setString("Homepage", c); + } + if (!phone.empty()) + DI.setString("Phone", phone); + } + + string account; + xo.getObjectString("Account", account); + if (!account.empty()) + DI.setString("Account", account); + + xmlList xClass; + xo.getObjects("Class", xClass); + for (size_t k = 0; k < xClass.size(); k++) + readClass(xClass[k], teamClassConfig); + + if (!feeStatistics.empty()) { + set fees; + set factors; + for (size_t i = 0; i < feeStatistics.size(); i++) { + int fee = int(100 * feeStatistics[i].fee); + int factor = int(100 * feeStatistics[i].lateFactor) - 100; + fees.insert(fee); + if (factor > 0) + factors.insert(factor); + } + int n = 0, y = 0, e = 0; + + if (fees.size() >= 3) { + y = *fees.begin(); + fees.erase(fees.begin()); + n = *fees.begin(); + fees.erase(fees.begin()); + e = *fees.rbegin(); + } + else if (fees.size() == 2) { + y = *fees.begin(); + fees.erase(fees.begin()); + e = n = *fees.begin(); + } + else if (fees.size() == 1) { + e = n = y = *fees.begin(); + } + + if (n > 0) { + DI.setInt("EliteFee", oe.interpretCurrency(double(e) * 0.01, "")); + DI.setInt("EntryFee", oe.interpretCurrency(double(n) * 0.01, "")); + DI.setInt("YouthFee", oe.interpretCurrency(double(y) * 0.01, "")); + } + + if (!factors.empty()) { + char lf[16]; + sprintf_s(lf, "%d %%", *factors.rbegin()); + DI.setString("LateEntryFactor", lf); + } + } + oe.synchronize(); +} + +void IOF30Interface::setupClassConfig(int classId, const xmlobject &xTeam, map > &teamClassConfig) { + + // Get class + xmlobject xClass = xTeam.getObject("Class"); + if (xClass) { + pClass pc = readClass(xClass, teamClassConfig); + classId = pc->getId(); + } + vector &teamClass = teamClassConfig[classId]; + + // Get team entriess + xmlList xEntries; + xTeam.getObjects("TeamEntryPerson", xEntries); + for (size_t k = 0; k < xEntries.size(); k++) { + int leg = xEntries[k].getObjectInt("Leg"); + int legorder = xEntries[k].getObjectInt("LegOrder"); + leg = max(0, leg - 1); + legorder = max(1, legorder); + if (int(teamClass.size()) <= leg) + teamClass.resize(leg + 1); + teamClass[leg].setMaxRunners(legorder); + } + + // Get team starts + xmlList xMemberStarts; + xTeam.getObjects("TeamMemberStart", xMemberStarts); + for (size_t k = 0; k < xMemberStarts.size(); k++) { + xmlList xStarts; + xMemberStarts[k].getObjects("Start", xStarts); + for (size_t j = 0; j < xStarts.size(); j++) { + int leg = xStarts[j].getObjectInt("Leg"); + int legorder = xStarts[j].getObjectInt("LegOrder"); + leg = max(0, leg - 1); + legorder = max(1, legorder); + if (int(teamClass.size()) <= leg) + teamClass.resize(leg + 1); + teamClass[leg].setMaxRunners(legorder); + } + } +} + +pTeam IOF30Interface::readTeamEntry(gdioutput &gdi, xmlobject &xTeam, + map > &bibPatterns, + const map > &teamClassConfig, + map > > &personId2TeamLeg) { + + bool newTeam; + pTeam t = getCreateTeam(gdi, xTeam, newTeam); + + if (!t) + return 0; + + // Class + map > localTeamClassConfig; + pClass pc = readClass(xTeam.getObject("Class"), localTeamClassConfig); + + if (pc && (t->getClassId() == 0 || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) ) { + t->setClassId(pc->getId(), false); + } + string bib; + xTeam.getObjectString("BibNumber", bib); + char pat[32]; + int no = oClass::extractBibPattern(bib, pat); + if (no > 0 && t->getBib().empty()) + t->setBib(bib, no, true, false); + else if (newTeam) { + pair autoBib = pc->getNextBib(bibPatterns); + if (autoBib.first > 0) { + t->setBib(autoBib.second, autoBib.first, true, false); + } + } + + oDataInterface di = t->getDI(); + if (newTeam) { + string entryTime; + xTeam.getObjectString("EntryTime", entryTime); + di.setDate("EntryDate", entryTime); + } + + double fee = 0, paid = 0, taxable = 0, percentage = 0; + string currency; + xmlList xAssigned; + xTeam.getObjects("AssignedFee", xAssigned); + for (size_t j = 0; j < xAssigned.size(); j++) { + getAssignedFee(xAssigned[j], fee, paid, taxable, percentage, currency); + } + fee += fee * percentage; // OLA / Eventor stupidity + + di.setInt("Fee", oe.interpretCurrency(fee, currency)); + di.setInt("Paid", oe.interpretCurrency(paid, currency)); + di.setInt("Taxable", oe.interpretCurrency(fee, currency)); + + xmlList xEntries; + xTeam.getObjects("TeamEntryPerson", xEntries); + + for (size_t k = 0; ksynchronize(); + return t; +} + +pTeam IOF30Interface::readTeamStart(gdioutput &gdi, pClass pc, xmlobject &xTeam, + map > &bibPatterns, + const map > &teamClassConfig) { + bool newTeam; + pTeam t = getCreateTeam(gdi, xTeam, newTeam); + + if (!t) + return 0; + + // Class + if (pc && (t->getClassId() == 0 || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) ) + t->setClassId(pc->getId(), false); + + string bib; + xTeam.getObjectString("BibNumber", bib); + char pat[32]; + int no = oClass::extractBibPattern(bib, pat); + if (no > 0 && t->getBib().empty()) + t->setBib(bib, no, true, false); + else if (newTeam){ + pair autoBib = pc->getNextBib(bibPatterns); + if (autoBib.first > 0) { + t->setBib(autoBib.second, autoBib.first, true, false); + } + } + xmlList xEntries; + xTeam.getObjects("TeamMemberStart", xEntries); + + for (size_t k = 0; ksynchronize(); + return t; +} + +pTeam IOF30Interface::getCreateTeam(gdioutput &gdi, const xmlobject &xTeam, bool &newTeam) { + newTeam = false; + string name; + xTeam.getObjectString("Name", name); + + if (name.empty()) + return 0; + + int id = xTeam.getObjectInt("Id"); + pTeam t = 0; + + if (id) + t = oe.getTeam(id); + else + t = oe.getTeamByName(name); + + if (!t) { + if (id > 0) { + oTeam tr(&oe, id); + t = oe.addTeam(tr, true); + } + else { + oTeam tr(&oe); + t = oe.addTeam(tr, true); + } + newTeam = true; + } + + if (!t) + return 0; + + t->setEntrySource(entrySourceId); + t->flagEntryTouched(true); + if (t->getName().empty() || !t->hasFlag(oAbstractRunner::FlagUpdateName)) + t->setName(name, false); + + // Club + pClub c = 0; + xmlList xOrgs; + xTeam.getObjects("Organisation", xOrgs); + if (xOrgs.empty()) + xTeam.getObjects("Organization", xOrgs); + + for (size_t k = 0; k < xOrgs.size(); k++) { + if (c == 0) + c = readOrganization(gdi, xOrgs[k], false); + else + readOrganization(gdi, xOrgs[k], false);// Just include in competition + } + + if (c) + t->setClubId(c->getId()); + + return t; +} + +int IOF30Interface::getIndexFromLegPos(int leg, int legorder, const vector &setup) { + int ix = 0; + for (int k = 0; k < leg - 1; k++) + ix += k < int(setup.size()) ? max(setup[k].maxRunners, 1) : 1; + if (legorder > 0) + ix += legorder - 1; + return ix; +} + +pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam team, + const map > &teamClassConfig, + map > > &personId2TeamLeg) { + xmlobject xPers = xo.getObject("Person"); + // Card + const int cardNo = xo.getObjectInt("ControlCard"); + + pRunner r = 0; + + if (xPers) + r = readPerson(gdi, xPers); + + if (cardNo > 0 && r == 0 && team) { + // We got no person, but a card number. Add the runner anonymously. + r = oe.addRunner(lang.tl("N.N."), team->getClubId(), team->getClassId(), cardNo, 0, false); + r->flagEntryTouched(true); + r->setEntrySource(entrySourceId); + r->synchronize(); + } + + if (r == 0) + return 0; + + // Club + pClub c = readOrganization(gdi, xo.getObject("Organisation"), false); + if (!c) + c = readOrganization(gdi, xo.getObject("Organization"), false); + + if (c) + r->setClubId(c->getId()); + + // Class + map > localTeamClassConfig; + pClass pc = readClass(xo.getObject("Class"), localTeamClassConfig); + + if (pc && (r->getClassId() == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)) ) + r->setClassId(pc->getId(), false); + + if (team) { + int leg = xo.getObjectInt("Leg"); + int legorder = xo.getObjectInt("LegOrder"); + int legindex = max(0, leg - 1); + map >::const_iterator res = teamClassConfig.find(team->getClassId()); + if (res != teamClassConfig.end()) { + legindex = getIndexFromLegPos(leg, legorder, res->second); + } + + if (personId2TeamLeg.find(r->getId()) == personId2TeamLeg.end()) { + if (team->getClassRef()) + legindex = team->getClassRef()->getLegRunner(legindex); + + // Ensure unique + team->setRunner(legindex, r, false); + if (r->getClubId() == 0) + r->setClubId(team->getClubId()); + } + personId2TeamLeg[r->getId()].push_back(make_pair(team->getId(), legindex)); + } + + // Card + if (cardNo > 0) + r->setCardNo(cardNo, false); + + oDataInterface di = r->getDI(); + + string entryTime; + xo.getObjectString("EntryTime", entryTime); + di.setDate("EntryDate", entryTime); + + double fee = 0, paid = 0, taxable = 0, percentage = 0; + string currency; + xmlList xAssigned; + xo.getObjects("AssignedFee", xAssigned); + for (size_t j = 0; j < xAssigned.size(); j++) { + getAssignedFee(xAssigned[j], fee, paid, taxable, percentage, currency); + } + fee += fee * percentage; // OLA / Eventor stupidity + + di.setInt("Fee", oe.interpretCurrency(fee, currency)); + di.setInt("Paid", oe.interpretCurrency(paid, currency)); + di.setInt("Taxable", oe.interpretCurrency(fee, currency)); + + r->synchronize(); + return r; +} + +pRunner IOF30Interface::readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo, pTeam team, + const map > &teamClassConfig) { + xmlobject xPers = xo.getObject("Person"); + pRunner r = 0; + if (xPers) + r = readPerson(gdi, xPers); + if (r == 0) + return 0; + + // Club + pClub c = readOrganization(gdi, xo.getObject("Organisation"), false); + if (!c) + c = readOrganization(gdi, xo.getObject("Organization"), false); + + if (c) + r->setClubId(c->getId()); + + xmlList starts; + xo.getObjects("Start", starts); + + for (size_t k = 0; k < starts.size(); k++) { + int race = starts[k].getObjectInt("raceNumber"); + pRunner rRace = r; + if (race > 1 && r->getNumMulti() > 0) { + pRunner rr = r->getMultiRunner(race - 1); + if (rr) + rRace = rr; + } + if (rRace) { + // Card + int cardNo = starts[k].getObjectInt("ControlCard"); + if (cardNo > 0) + rRace->setCardNo(cardNo, false); + + xmlobject startTime = starts[k].getObject("StartTime"); + + if (team) { + int leg = starts[k].getObjectInt("Leg"); + int legorder = starts[k].getObjectInt("LegOrder"); + int legindex = max(0, leg - 1); + map >::const_iterator res = teamClassConfig.find(team->getClassId()); + if (res != teamClassConfig.end()) { + legindex = getIndexFromLegPos(leg, legorder, res->second); + } + team->setRunner(legindex, rRace, false); + if (rRace->getClubId() == 0) + rRace->setClubId(team->getClubId()); + + if (startTime && pc) { + pc->setStartType(legindex, STDrawn, false); + + } + } + + string bib; + starts[k].getObjectString("BibNumber", bib); + rRace->getDI().setString("Bib", bib); + + rRace->setStartTime(parseISO8601Time(startTime), true, false); + } + } + + if (pc && (r->getClassId() == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)) ) + r->setClassId(pc->getId(), true); + + r->synchronize(); + return r; +} + + + +pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) { + + xmlobject pname = person.getObject("Name"); + + string name; + + if (pname) { + string given, family; + //name = getFirst(pname.getObjectString("Given", given), 2)+ " " +pname.getObjectString("Family", family); + name = pname.getObjectString("Family", family) + ", " + getFirst(pname.getObjectString("Given", given), 2); + } + else { + name = lang.tl("N.N."); + } + + string sid; + person.getObjectString("Id", sid); + __int64 extId = oBase::converExtIdentifierString(sid); + int pid = oBase::idFromExtId(extId); + pRunner r = 0; + + if (pid) { + r = oe.getRunner(pid, 0); + while (r) { // Check that the exact match is OK + if (extId != r->getExtIdentifier()) + break; + pid++; + r = oe.getRunner(pid, 0); + } + + if (r) { + // Check that a with this id runner does not happen to exist with a different source + if (entrySourceId>0 && r->getEntrySource() != entrySourceId) { + r = 0; + pid = 0; + } + else if (entrySourceId == 0) { + string canName = canonizeName(name.c_str()); + string canOldName = canonizeName(r->getName().c_str()); + if (canName != canOldName) { + r = 0; + pid = 0; + } + } + } + } + + if (!r) { + if ( pid > 0) { + oRunner or(&oe, pid); + r = oe.addRunner(or, true); + } + else { + oRunner or(&oe); + r = oe.addRunner(or, true); + } + } + + r->setEntrySource(entrySourceId); + r->flagEntryTouched(true); + + if (!r->hasFlag(oAbstractRunner::FlagUpdateName)) { + r->setName(name, false); + } + + r->setExtIdentifier(extId); + + oDataInterface DI=r->getDI(); + string tmp; + + PersonSex s = interpretSex(person.getObjectString("sex", tmp)); + if (s != sUnknown) + r->setSex(s); + person.getObjectString("BirthDate", tmp); + if (tmp.length()>=4) { + tmp = tmp.substr(0, 4); + r->setBirthYear(atoi(tmp.c_str())); + } + + getNationality(person.getObject("Nationality"), DI); + + return r; +} + +pClub IOF30Interface::readOrganization(gdioutput &gdi, const xmlobject &xclub, bool saveToDB) { + if (!xclub) + return 0; + string clubIdS; + xclub.getObjectString("Id", clubIdS); + __int64 extId = oBase::converExtIdentifierString(clubIdS); + int clubId = oBase::idFromExtId(extId); + string name, shortName; + xclub.getObjectString("Name", name); + xclub.getObjectString("ShortName", shortName); + + if (shortName.length() > 4 && shortName.length() < name.length()) + swap(name, shortName); + + if (name.length()==0 || !IsCharAlphaNumeric(name[0])) + return 0; + + pClub pc=0; + + if ( !saveToDB ) { + if (clubId) + pc = oe.getClubCreate(clubId, name); + + if (!pc) return false; + } + else { + pc = new oClub(&oe, clubId); + //pc->setID->Id = clubId; + } + + pc->setName(name); + + pc->setExtIdentifier(extId); + + oDataInterface DI=pc->getDI(); + + string tmp; + + int district = xclub.getObjectInt("ParentOrganisationId"); + if (district > 0) + DI.setInt("District", district); + + xmlobject address = xclub.getObject("Address"); + + if (shortName.length() <= 4) + DI.setString("ShortName", shortName); + + string str; + + if (address) { + DI.setString("CareOf", address.getObjectString("CareOf", tmp)); + DI.setString("Street", address.getObjectString("Street", tmp)); + DI.setString("City", address.getObjectString("City", tmp)); + DI.setString("ZIP", address.getObjectString("ZipCode", tmp)); + DI.setString("State", address.getObjectString("State", tmp)); + getNationality(address.getObject("Country"), DI); + } + + xmlList xContact; + xclub.getObjects("Contact", xContact); + + string phone; + for (size_t k = 0; k < xContact.size(); k++) { + string type; + xContact[k].getObjectString("type", type); + string c; + xContact[k].getObjectString(0, c); + + if (type == "PhoneNumber" || type == "MobilePhoneNumber") + phone += phone.empty() ? c : ", " + c; + else if (type == "EmailAddress") + DI.setString("EMail", c); + } + DI.setString("Phone", phone); + + getNationality(xclub.getObject("Country"), DI); + + xclub.getObjectString("type", str); + if (!str.empty()) + DI.setString("Type", str); + + if (saveToDB) { + oe.getRunnerDatabase().importClub(*pc, false); + delete pc; + } + else { + pc->synchronize(); + } + + return pc; +} + +void IOF30Interface::getNationality(const xmlobject &xCountry, oDataInterface &di) { + if (xCountry) { + string code, country; + + xCountry.getObjectString("code", code); + xCountry.getObjectString(0, country); + + if (!code.empty()) + di.setString("Nationality", code); + + if (!country.empty()) + di.setString("Country", country); + } +} + +void IOF30Interface::getAmount(const xmlobject &xAmount, double &amount, string ¤cy) { + amount = 0; // Do no clear currency. It is filled in where found (and assumed to be constant) + if (xAmount) { + string tmp; + xAmount.getObjectString(0, tmp); + amount = atof(tmp.c_str()); + xAmount.getObjectString("currency", currency); + } +} + +void IOF30Interface::getFeeAmounts(const xmlobject &xFee, double &fee, double &taxable, double &percentage, string ¤cy) { + xmlobject xAmount = xFee.getObject("Amount"); + xmlobject xPercentage = xFee.getObject("Percentage"); // Eventor / OLA stupidity + if (xPercentage) { + string tmp; + xPercentage.getObjectString(0, tmp); + percentage = atof(tmp.c_str()) * 0.01; + } + else + getAmount(xAmount, fee, currency); + getAmount(xFee.getObject("TaxableAmount"), taxable, currency); +} + +void IOF30Interface::getAssignedFee(const xmlobject &xFee, double &fee, double &paid, double &taxable, double &percentage, string ¤cy) { + currency.clear(); + if (xFee) { + getFeeAmounts(xFee.getObject("Fee"), fee, taxable, percentage, currency); + getAmount(xFee.getObject("PaidAmount"), paid, currency); + } +} + +void IOF30Interface::getFee(const xmlobject &xFee, FeeInfo &fee) { + getFeeAmounts(xFee, fee.fee, fee.taxable, fee.percentage, fee.currency); + + xFee.getObjectString("ValidFromTime", fee.fromTime); + xFee.getObjectString("ValidToTime", fee.toTime); + + xFee.getObjectString("FromDateOfBirth", fee.fromBirthDate); + xFee.getObjectString("ToDateOfBirth", fee.toBirthDate); +} + +void IOF30Interface::writeAmount(xmlparser &xml, const char *tag, int amount) const { + if (amount > 0) { + string code = oe.getDCI().getString("CurrencyCode"); + if (code.empty()) + xml.write(tag, oe.formatCurrency(amount, false)); + else + xml.write(tag, "currency", code, oe.formatCurrency(amount, false)); + } +} + +void IOF30Interface::writeAssignedFee(xmlparser &xml, const oAbstractRunner &tr, int paidForCard) const { + const oDataConstInterface dci = tr.getDCI(); + int fee = dci.getInt("Fee"); + int taxable = dci.getInt("Taxable"); + int paid = dci.getInt("Paid"); + + if (fee == 0 && taxable == 0 && paid == 0) + return; + + if (paid >= paidForCard) { + paid -= paidForCard; // Included in card service fee + } + const pClass pc = tr.getClassRef(); + if (!splitLateFee || !pc || !tr.hasLateEntryFee()) { + xml.startTag("AssignedFee"); + string type = tr.hasLateEntryFee() ? "Late" : "Normal"; + xml.startTag("Fee", "type", type); + xml.write("Name", "Entry fee"); + writeAmount(xml, "Amount", fee); + writeAmount(xml, "TaxableAmount", taxable); + xml.endTag(); + + writeAmount(xml, "PaidAmount", paid); + xml.endTag(); + } + else { + int normalFee = pc->getDCI().getInt("ClassFee"); + + int feeSplit[2] = {fee, 0}; + int paidSplit[2] = {paid, 0}; + if (normalFee > 0) { + feeSplit[0] = min(normalFee, fee); + feeSplit[1] = max(0, fee - feeSplit[0]); + + paidSplit[0] = min(paid, feeSplit[0]); + paidSplit[1] = max(0, paid - paidSplit[0]); + } + + for (int ft = 0; ft < 2; ft++) { + xml.startTag("AssignedFee"); + string type = ft == 1 ? "Late" : "Normal"; + xml.startTag("Fee", "type", type); + xml.write("Name", "Entry fee"); + writeAmount(xml, "Amount", feeSplit[ft]); + if (ft == 0) + writeAmount(xml, "TaxableAmount", taxable); + xml.endTag(); + + writeAmount(xml, "PaidAmount", paidSplit[ft]); + xml.endTag(); + } + } +} + +void IOF30Interface::writeRentalCardService(xmlparser &xml, int cardFee, bool paid) const { + xml.startTag("ServiceRequest"); { + + xml.startTag("Service", "type", "RentalCard"); { + xml.write("Name", "Card Rental"); + } + xml.endTag(); + + xml.write("RequestedQuantity", "1"); + + xml.startTag("AssignedFee"); { + xml.startTag("Fee"); { + xml.write("Name", "Card Rental Fee"); + writeAmount(xml, "Amount", cardFee); + } + xml.endTag(); + + if (paid) { + writeAmount(xml, "PaidAmount", cardFee); + } + } + xml.endTag(); + } + xml.endTag(); +} + +void IOF30Interface::getAgeLevels(const vector &fees, const vector &ix, + int &normalIx, int &redIx, string &youthLimit, string &seniorLimit) { + assert(!ix.empty()); + if (ix.size() == 1) { + normalIx = ix[0]; + redIx = ix[0]; + return; + } + else { + normalIx = redIx = ix[0]; + for (size_t k = 0; k < ix.size(); k++) { + if (fees[ix[k]] < fees[redIx]) + redIx = ix[k]; + if (fees[normalIx] < fees[ix[k]]) + normalIx = ix[k]; + + const string &to = fees[ix[k]].toBirthDate; + const string &from = fees[ix[k]].fromBirthDate; + + if (!from.empty() && (youthLimit.empty() || youthLimit > from)) + youthLimit = from; + + if (!to.empty() && (seniorLimit.empty() || seniorLimit > to)) + seniorLimit = to; + } + } +} + +int getAgeFromDate(const string &date) { + int y = getThisYear(); + SYSTEMTIME st; + convertDateYMS(date, st, false); + if (st.wYear > 1900) + return y - st.wYear; + else + return 0; +} + +void IOF30Interface::FeeInfo::add(IOF30Interface::FeeInfo &fi) { + fee += fi.fee; + fee += fee*percentage; + + taxable += fi.taxable; + + if (fi.toTime.empty() || (fi.toTime > fromTime && !fromTime.empty())) { + fi.toTime = fromTime; + if (!fi.toTime.empty()) { + SYSTEMTIME st; + convertDateYMS(fi.toTime, st, false); + __int64 sec = SystemTimeToInt64Second(st); + sec -= 3600; + fi.toTime = convertSystemDate(Int64SecondToSystemTime(sec)); + } + } + //if (fi.fromTime.empty() || (fi.fromTime < toTime && !toTime.empty())) + // fi.fromTime = toTime; +} + +pClass IOF30Interface::readClass(const xmlobject &xclass, + map > &teamClassConfig) { + if (!xclass) + return 0; + int classId = xclass.getObjectInt("Id"); + string name, shortName, longName; + xclass.getObjectString("Name", name); + xclass.getObjectString("ShortName", shortName); + + if (!shortName.empty()) { + longName = name; + name = shortName; + } + + pClass pc = 0; + + if (classId) { + pc = oe.getClass(classId); + + if (!pc) { + oClass c(&oe, classId); + pc = oe.addClass(c); + } + } + else + pc = oe.addClass(name); + + oDataInterface DI = pc->getDI(); + + if (!longName.empty()) { + pc->setName(name); + DI.setString("LongName", longName); + } + else { + if (pc->getName() != name && DI.getString("LongName") != name) + pc->setName(name); + } + xmlList legs; + xclass.getObjects("Leg", legs); + if (!legs.empty()) { + vector &legInfo = teamClassConfig[pc->getId()]; + if (legInfo.size() < legs.size()) + legInfo.resize(legs.size()); + + for (size_t k = 0; k < legs.size(); k++) { + legInfo[k].setMaxRunners(legs[k].getObjectInt("maxNumberOfCompetitors")); + legInfo[k].setMinRunners(legs[k].getObjectInt("minNumberOfCompetitors")); + } + } + + string tmp; + // Status + xclass.getObjectString("Status", tmp); + + if (tmp == "Invalidated") + DI.setString("Status", "I"); // No refund + else if (tmp == "InvalidatedNoFee") + DI.setString("Status", "IR"); // Refund + + // No timing + xclass.getObjectString("resultListMode", tmp); + if (tmp == "UnorderedNoTimes") + pc->setNoTiming(true); + + int minAge = xclass.getObjectInt("minAge"); + if (minAge > 0) + DI.setInt("LowAge", minAge); + + int highAge = xclass.getObjectInt("maxAge"); + if (highAge > 0) + DI.setInt("HighAge", highAge); + + xclass.getObjectString("sex", tmp); + if (!tmp.empty()) + DI.setString("Sex", tmp); + + xmlobject type = xclass.getObject("ClassType"); + if (type) { + DI.setString("ClassType", type.getObjectString("Id", tmp)); + } + + // XXX we only care about the existance of one race class + xmlobject raceClass = xclass.getObject("RaceClass"); + + if (raceClass) { + xmlList xFees; + raceClass.getObjects("Fee", xFees); + if (xFees.size() > 0) { + vector fees(xFees.size()); + int feeIx = 0; + int feeLateIx = 0; + int feeRedIx = 0; + int feeRedLateIx = 0; + + map > feePeriods; + for (size_t k = 0; k < xFees.size(); k++) { + getFee(xFees[k], fees[k]); + } + + for (size_t k = 0; k < fees.size(); k++) { + for (size_t j = k+1; j < fees.size(); j++) { + if (fees[k].includes(fees[j])) + fees[j].add(fees[k]); + if (fees[j].includes(fees[k])) + fees[k].add(fees[j]); + } + feePeriods[fees[k].getDateKey()].push_back(k); + } + + string youthLimit; + string seniorLimit; + + vector &earlyEntry = feePeriods.begin()->second; + getAgeLevels(fees, earlyEntry, feeIx, feeRedIx, youthLimit, seniorLimit); + const string &lastODate = fees[earlyEntry[0]].toTime; + if (!lastODate.empty()) { + oe.getDI().setDate("OrdinaryEntry", lastODate); + } + vector &lateEntry = feePeriods.rbegin()->second; + getAgeLevels(fees, lateEntry, feeLateIx, feeRedLateIx, youthLimit, seniorLimit); + + if (!youthLimit.empty()) + oe.getDI().setInt("YouthAge", getAgeFromDate(youthLimit)); + + if (!seniorLimit.empty()) + oe.getDI().setInt("SeniorAge", getAgeFromDate(seniorLimit)); + + DI.setInt("ClassFee", oe.interpretCurrency(fees[feeIx].fee, fees[feeIx].currency)); + DI.setInt("HighClassFee", oe.interpretCurrency(fees[feeLateIx].fee, fees[feeLateIx].currency)); + + DI.setInt("ClassFeeRed", oe.interpretCurrency(fees[feeRedIx].fee, fees[feeRedIx].currency)); + DI.setInt("HighClassFeeRed", oe.interpretCurrency(fees[feeRedLateIx].fee, fees[feeRedLateIx].currency)); + + FeeStatistics feeStat; + feeStat.fee = fees[feeIx].fee; + if (feeStat.fee > 0) { + feeStat.lateFactor = fees[feeLateIx].fee / feeStat.fee; + feeStatistics.push_back(feeStat); + } + } + } + pc->synchronize(); + + return pc; +} + +void IOF30Interface::setupRelayClasses(const map > &teamClassConfig) { + for (map >::const_iterator it = teamClassConfig.begin(); + it != teamClassConfig.end(); ++it) { + int classId = it->first; + const vector &legs = it->second; + if (legs.empty()) + continue; + if (classId > 0) { + pClass pc = oe.getClass(classId); + if (!pc) { + pc = oe.getClassCreate(classId, "tmp" + itos(classId)); + } + setupRelayClass(pc, legs); + } + } +} + +void IOF30Interface::setupRelayClass(pClass pc, const vector &legs) { + if (pc) { + int nStage = 0; + for (size_t k = 0; k < legs.size(); k++) { + nStage += legs[k].maxRunners; + } + if (int(pc->getNumStages())>=nStage) + return; // Do nothing + + pc->setNumStages(nStage); + pc->setStartType(0, STTime, false); + pc->setStartData(0, oe.getAbsTime(3600)); + + int ix = 0; + for (size_t k = 0; k < legs.size(); k++) { + for (int j = 0; j < legs[k].maxRunners; j++) { + if (j>0) { + if (j < legs[k].minRunners) + pc->setLegType(ix, LTParallel); + else + pc->setLegType(ix, LTExtra); + + pc->setStartType(ix, STChange, false); + } + else if (k>0) { + pc->setLegType(ix, LTNormal); + pc->setStartType(ix, STChange, false); + } + ix++; + } + } + } +} + +string IOF30Interface::getCurrentTime() const { + // Don't call this method at midnight! + return getLocalDate() + "T" + getLocalTimeOnly(); +} + +int IOF30Interface::parseISO8601Time(const xmlobject &xo) { + if (!xo) + return 0; + const char *t = xo.get(); + int tIx = -1; + int zIx = -1; + for (int k = 0; t[k] != 0; k++) { + if (t[k] == 'T' || t[k] == 't') { + if (tIx == -1) + tIx = k; + else ; + // Bad format + } + else if (t[k] == '+' || t[k] == '-' || t[k] == 'Z') { + if (zIx == -1 && tIx != -1) + zIx = k; + else ; + // Bad format + } + } + string date = t; + string time = tIx >= 0 ? date.substr(tIx+1) : date; + string zone = (tIx >= 0 && zIx > 0) ? time.substr(zIx - tIx - 1) : ""; + + if (tIx > 0) { + date = date.substr(0, tIx); + + if (zIx > 0) + time = time.substr(0, zIx - tIx - 1); + } + + return oe.getRelativeTime(date, time, zone); +} + +void IOF30Interface::getProps(vector &props) const { + props.push_back("xmlns"); + props.push_back("http://www.orienteering.org/datastandard/3.0"); + + props.push_back("xmlns:xsi"); + props.push_back("http://www.w3.org/2001/XMLSchema-instance"); + + props.push_back("iofVersion"); + props.push_back("3.0"); + + props.push_back("createTime"); + props.push_back(getCurrentTime()); + + props.push_back("creator"); + props.push_back("MeOS " + getMeosCompectVersion()); +} + +void IOF30Interface::writeResultList(xmlparser &xml, const set &classes, + int leg, bool useUTC_, + bool teamsAsIndividual_, bool unrollLoops_, + bool includeStageInfo_) { + useGMT = useUTC_; + includeStageRaceInfo = includeStageInfo_; + teamsAsIndividual = teamsAsIndividual_; + unrollLoops = unrollLoops_; + vector props; + getProps(props); + + props.push_back("status"); + props.push_back("Complete"); + + xml.startTag("ResultList", props); + + writeEvent(xml); + + vector c; + oe.getClasses(c, false); + + for (size_t k = 0; k < c.size(); k++) { +// bool indRel = c[k]->getClassType() == oClassIndividRelay; + + if (classes.empty() || classes.count(c[k]->getId())) { + /* oe.getRunners(c[k]->getId(), r, false); + vector rToUse; + rToUse.reserve(r.size()); + + for (size_t j = 0; j < r.size(); j++) { + if (leg == -1 || leg == r[j]->getLegNumber()) { + if (leg == -1 && indRel && r[j]->getLegNumber() != 0) + continue; // Skip all but leg 0 for individual relay + + if (leg == -1 && !indRel && r[j]->getTeam()) + continue; // For teams, skip presonal results, unless individual relay + + if (r[j]->getStatus() == StatusUnknown) + continue; + + rToUse.push_back(r[j]); + } + } + + vector tToUse; + + if (leg == -1) { + oe.getTeams(c[k]->getId(), t, false); + tToUse.reserve(t.size()); + + for (size_t j = 0; j < t.size(); j++) { + for (int n = 0; n < t[j]->getNumRunners(); n++) { + pRunner tr = t[j]->getRunner(n); + if (tr && tr->getStatus() != StatusUnknown) { + tToUse.push_back(t[j]); + break; + } + } + } + + } + */ + vector rToUse; + vector tToUse; + getRunnersToUse(c[k], rToUse, tToUse, leg, false); + + if (!rToUse.empty() || !tToUse.empty()) { + writeClassResult(xml, *c[k], rToUse, tToUse); + } + } + } + + + xml.endTag(); +} + +void IOF30Interface::writeClassResult(xmlparser &xml, + const oClass &c, + const vector &r, + const vector &t) { + pCourse stdCourse = haveSameCourse(r); + + xml.startTag("ClassResult"); + writeClass(xml, c); + if (stdCourse) + writeCourse(xml, *stdCourse); + + bool hasInputTime = false; + for (size_t k = 0; !hasInputTime && k < r.size(); k++) { + if (r[k]->hasInputData()) + hasInputTime = true; + } + + for (size_t k = 0; !hasInputTime && k < t.size(); k++) { + if (t[k]->hasInputData()) + hasInputTime = true; + } + + for (size_t k = 0; k < r.size(); k++) { + writePersonResult(xml, *r[k], stdCourse == 0, false, hasInputTime); + } + + for (size_t k = 0; k < t.size(); k++) { + writeTeamResult(xml, *t[k], hasInputTime); + } + + xml.endTag(); +} + +pCourse IOF30Interface::haveSameCourse(const vector &r) const { + bool sameCourse = true; + pCourse stdCourse = r.size() > 0 ? r[0]->getCourse(false) : 0; + for (size_t k = 1; sameCourse && k < r.size(); k++) { + int nr = r[k]->getNumMulti(); + for (int j = 0; j <= nr; j++) { + pRunner tr = r[k]->getMultiRunner(j); + if (tr && stdCourse != tr->getCourse(true)) { + sameCourse = false; + return 0; + } + } + } + return stdCourse; +} + +void IOF30Interface::writeClass(xmlparser &xml, const oClass &c) { + xml.startTag("Class"); + xml.write("Id", c.getExtIdentifierString()); // Need to call initClassId first + xml.write("Name", c.getName()); + + oClass::ClassStatus stat = c.getClassStatus(); + if (stat == oClass::Invalid) + xml.write("Status", "Invalidated"); + else if (stat == oClass::InvalidRefund) + xml.write("Status", "InvalidatedNoFee"); + + + xml.endTag(); +} + +void IOF30Interface::writeCourse(xmlparser &xml, const oCourse &c) { + xml.startTag("Course"); + writeCourseInfo(xml, c); + xml.endTag(); +} + +void IOF30Interface::writeCourseInfo(xmlparser &xml, const oCourse &c) { + xml.write("Id", c.getId()); + xml.write("Name", c.getName()); + int len = c.getLength(); + if (len > 0) + xml.write("Length", len); + int climb = c.getDCI().getInt("Climb"); + if (climb > 0) + xml.write("Climb", climb); +} + + +string formatStatus(RunnerStatus st) { + switch (st) { + case StatusOK: + return "OK"; + case StatusDNS: + return "DidNotStart"; + case StatusMP: + return "MissingPunch"; + case StatusDNF: + return "DidNotFinish"; + case StatusDQ: + return "Disqualified"; + case StatusMAX: + return "OverTime"; + case StatusNotCompetiting: + return "NotCompeting"; + default: + return "Inactive"; + } +} + +void IOF30Interface::writePersonResult(xmlparser &xml, const oRunner &r, + bool includeCourse, bool teamMember, bool hasInputTime) { + if (!teamMember) + xml.startTag("PersonResult"); + else + xml.startTag("TeamMemberResult"); + + writePerson(xml, r); + const pClub pc = r.getClubRef(); + + if (pc && !r.isVacant()) + writeClub(xml, *pc, false); + + if (teamMember) { + oRunner const *resultHolder = &r; + cTeam t = r.getTeam(); + pClass cls = r.getClassRef(); + + if (t && cls) { + int leg = r.getLegNumber(); + const int legOrg = leg; + while (cls->getLegType(leg) == LTIgnore && leg > 0) { + leg--; + } + if (leg < legOrg && t->getRunner(leg)) + resultHolder = t->getRunner(leg); + } + + writeResult(xml, r, *resultHolder, includeCourse, + includeStageRaceInfo && (r.getNumMulti() > 0 || r.getRaceNo() > 0), teamMember, hasInputTime); + } + else { + if (r.getNumMulti() > 0) { + for (int k = 0; k <= r.getNumMulti(); k++) { + const pRunner tr = r.getMultiRunner(k); + if (tr) + writeResult(xml, *tr, *tr, includeCourse, includeStageRaceInfo, teamMember, hasInputTime); + } + } + else + writeResult(xml, r, r, includeCourse, false, teamMember, hasInputTime); + } + + + xml.endTag(); +} + +void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const oRunner &r, + bool includeCourse, bool includeRaceNumber, + bool teamMember, bool hasInputTime) { + + vector dummy; + if (!includeRaceNumber && getStageNumber() == 0) + xml.startTag("Result"); + else { + int rn = getStageNumber(); + if (rn == 0) + rn = 1; + if (includeRaceNumber) + rn += rPerson.getRaceNo(); + xml.startTag("Result", "raceNumber", itos(rn)); + } + + if (teamMember) + writeLegOrder(xml, rPerson); + + string bib = rPerson.getBib(); + if (!bib.empty()) + xml.write("BibNumber", bib); + + if (r.getStartTime() > 0) + xml.write("StartTime", oe.getAbsDateTimeISO(r.getStartTime(), true, useGMT)); + + if (r.getFinishTime() > 0) + xml.write("FinishTime", oe.getAbsDateTimeISO(r.getFinishTimeAdjusted(), true, useGMT)); + + if (r.getRunningTime() > 0) + xml.write("Time", r.getRunningTime()); + + int after = r.getTimeAfter(); + if (after >= 0) { + if (teamMember) { + xml.write("TimeBehind", "type", "Leg", itos(after)); + + after = r.getTimeAfterCourse(); + if (after >= 0) + xml.write("TimeBehind", "type", "Course", itos(after)); + + } + else + xml.write("TimeBehind", after); + } + + if (r.getClassRef()) { + + if (r.statusOK() && r.getClassRef()->getNoTiming() == false) { + if (!teamMember && r.getPlace() > 0 && r.getPlace() < 50000) { + xml.write("Position", r.getPlace()); + } + else if (teamMember) { + //int pos = r.getTeam()->getLegPlace(r.getLegNumber(), false); + int pos = r.getPlace(); + if (pos > 0 && pos < 50000) + xml.write("Position", "type", "Leg", itos(pos)); + + pos = r.getCoursePlace(); + if (pos > 0) + xml.write("Position", "type", "Course", itos(pos)); + } + } + + xml.write("Status", formatStatus(r.getStatus())); + + if ( (r.getTeam() && r.getClassRef()->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) { + xml.startTag("OverallResult"); + int rt = r.getTotalRunningTime(); + if (rt > 0) + xml.write("Time", rt); + + bool hasTiming = r.getClassRef()->getNoTiming() == false; + RunnerStatus stat = r.getTotalStatus(); + + int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0; + + if (stat == StatusOK && hasTiming) { + int after = r.getTotalRunningTime() - r.getClassRef()->getTotalLegLeaderTime(tleg, true); + if (after >= 0) + xml.write("TimeBehind", after); + } + + if (stat == StatusOK && hasTiming) + xml.write("Position", r.getTotalPlace()); + + xml.write("Status", formatStatus(stat)); + + xml.endTag(); + } + + pCourse crs = r.getCourse(!unrollLoops); + if (crs) { + if (includeCourse) + writeCourse(xml, *crs); + + const vector &sp = r.getSplitTimes(unrollLoops); + if (r.getStatus()>0 && r.getStatus() != StatusDNS && r.getStatus() != StatusNotCompetiting) { + int nc = crs->getNumControls(); + bool hasRogaining = crs->hasRogaining(); + int firstControl = crs->useFirstAsStart() ? 1 : 0; + if (crs->useLastAsFinish()) { + nc--; + } + set< pair > rogaining; + for (int k = firstControl; k= sp.size()) + break; + if (crs->getControl(k)->isRogaining(hasRogaining)) { + if (sp[k].hasTime()) { + int time = sp[k].time - r.getStartTime(); + int control = crs->getControl(k)->getFirstNumber(); + rogaining.insert(make_pair(time, control)); + } + else if (!sp[k].isMissing()) { + int control = crs->getControl(k)->getFirstNumber(); + rogaining.insert(make_pair(-1, control)); + } + continue; + } + + if (sp[k].isMissing()) + xml.startTag("SplitTime", "status", "Missing"); + else + xml.startTag("SplitTime"); + xml.write("ControlCode", crs->getControl(k)->getFirstNumber()); + if (sp[k].hasTime()) + xml.write("Time", sp[k].time - r.getStartTime()); + xml.endTag(); + } + + for (set< pair >::iterator it = rogaining.begin(); it != rogaining.end(); ++it) { + xml.startTag("SplitTime", "status", "Additional"); + xml.write("ControlCode", it->second); + if (it->first != -1) + xml.write("Time", it->first); + xml.endTag(); + } + } + } + } + + if (rPerson.getCardNo() > 0) + xml.write("ControlCard", rPerson.getCardNo()); + + writeFees(xml, rPerson); + + xml.endTag(); +} + +void IOF30Interface::writeFees(xmlparser &xml, const oRunner &r) const { + int cardFee = r.getDCI().getInt("CardFee"); + bool paidCard = r.getDCI().getInt("Paid") >= cardFee; + + writeAssignedFee(xml, r, paidCard ? cardFee : 0); + + if (cardFee > 0) + writeRentalCardService(xml, cardFee, paidCard); +} + +void IOF30Interface::writeTeamResult(xmlparser &xml, const oTeam &t, bool hasInputTime) { + xml.startTag("TeamResult"); + + xml.write("EntryId", t.getId()); + xml.write("Name", t.getName()); + + if (t.getClubRef()) + writeClub(xml, *t.getClubRef(), false); + + string bib = t.getBib(); + if (!bib.empty()) + xml.write("BibNumber", bib); + + for (int k = 0; k < t.getNumRunners(); k++) { + if (t.getRunner(k)) + writePersonResult(xml, *t.getRunner(k), true, true, hasInputTime); + } + + writeAssignedFee(xml, t, 0); + xml.endTag(); +} + +int IOF30Interface::getStageNumber() { + if (cachedStageNumber >= 0) + return cachedStageNumber; + int sn = oe.getStageNumber(); + if (sn != 0) { + if (sn < 0) + sn = 0; + cachedStageNumber = sn; + return sn; + } + bool pre = oe.hasPrevStage(); + bool post = oe.hasNextStage(); + + if (!pre && !post) { + cachedStageNumber = 0; + } + else if (!pre && post) { + cachedStageNumber = 1; + } + else { + cachedStageNumber = 1; + // Guess from stage name + string name = oe.getName(); + if (!name.empty()) { + char d = name[name.length() -1]; + if (d>='1' && d<='9') + cachedStageNumber = d - '0'; + } + } + + return cachedStageNumber; +} + +void IOF30Interface::writeEvent(xmlparser &xml) { + xml.startTag("Event"); + xml.write("Id", oe.getExtIdentifierString()); + xml.write("Name", oe.getName()); + xml.startTag("StartTime"); + xml.write("Date", oe.getDate()); + xml.write("Time", oe.getAbsDateTimeISO(0, false, useGMT)); + xml.endTag(); + + if (getStageNumber()) { + xml.startTag("Race"); + xml.write("RaceNumber", getStageNumber()); + + xml.write("Name", oe.getName()); + + xml.startTag("StartTime"); + xml.write("Date", oe.getDate()); + xml.write("Time", oe.getAbsDateTimeISO(0, false, useGMT)); + xml.endTag(); + + xml.endTag(); + } + + xml.endTag(); +} + +void IOF30Interface::writePerson(xmlparser &xml, const oRunner &r) { + xml.startTag("Person"); + + __int64 id = r.getExtIdentifier(); + if (id != 0) + xml.write("Id", r.getExtIdentifierString()); + + xml.startTag("Name"); + xml.write("Family", r.getFamilyName()); + xml.write("Given", r.getGivenName()); + xml.endTag(); + + xml.endTag(); +} + +void IOF30Interface::writeClub(xmlparser &xml, const oClub &c, bool writeExtended) const { + if (c.isVacant() || c.getName().empty()) + return; + + if (writeExtended) { + const string &type = c.getDCI().getString("Type"); + if (type.empty()) + xml.startTag("Organisation"); + else + xml.startTag("Organisation", "type", type); + } + else { + xml.startTag("Organisation"); + } + __int64 id = c.getExtIdentifier(); + if (id != 0) + xml.write("Id", c.getExtIdentifierString()); + + xml.write("Name", c.getName()); + string sname = c.getDCI().getString("ShortName"); + if (!sname.empty()) + xml.write("ShortName", sname); + + string ctry = c.getDCI().getString("Country"); + string nat = c.getDCI().getString("Nationality"); + + if (!ctry.empty() || !nat.empty()) { + if (ctry.empty()) { + if (nat == "SWE") + ctry = "Sweden"; + else if (nat == "FR" || nat == "FRA") + ctry = "France"; + else + ctry = nat; + } + xml.write("Country", "code", nat, ctry); + } + + if (writeExtended) { + oDataConstInterface di = c.getDCI(); + const string &street = di.getString("Street"); + const string &co = di.getString("CareOf"); + const string &city = di.getString("City"); + const string &state = di.getString("State"); + const string &zip = di.getString("ZIP"); + const string &email = di.getString("EMail"); + const string &phone = di.getString("Phone"); + + if (!street.empty()) { + xml.startTag("Address"); + xml.write("Street", street); + if (!co.empty()) + xml.write("CareOf", co); + if (!zip.empty()) + xml.write("ZipCode", zip); + if (!city.empty()) + xml.write("City", city); + if (!state.empty()) + xml.write("State", state); + if (!ctry.empty()) + xml.write("Country", ctry); + xml.endTag(); + } + + if (!email.empty()) + xml.write("Contact", "type", "EmailAddress", email); + + if (!phone.empty()) + xml.write("Contact", "type", "PhoneNumber", phone); + + int dist = di.getInt("District"); + if (dist > 0) + xml.write("ParentOrganisationId", dist); + } + + xml.endTag(); +} + +void IOF30Interface::writeStartList(xmlparser &xml, const set &classes, bool useUTC_, + bool teamsAsIndividual_, bool includeStageInfo_) { + useGMT = useUTC_; + teamsAsIndividual = teamsAsIndividual_; + includeStageRaceInfo = includeStageInfo_; + vector props; + getProps(props); + + xml.startTag("StartList", props); + + writeEvent(xml); + + vector c; + oe.getClasses(c, false); + + for (size_t k = 0; k < c.size(); k++) { + + if (classes.empty() || classes.count(c[k]->getId())) { + vector rToUse; + vector tToUse; + getRunnersToUse(c[k], rToUse, tToUse, -1, true); + if (!rToUse.empty() || !tToUse.empty()) { + writeClassStartList(xml, *c[k], rToUse, tToUse); + } + } + } + xml.endTag(); +} + +void IOF30Interface::getRunnersToUse(const pClass cls, vector &rToUse, + vector &tToUse, int leg, bool includeUnknown) const { + + rToUse.clear(); + tToUse.clear(); + vector r; + vector t; + + int classId = cls->getId(); + bool indRel = cls->getClassType() == oClassIndividRelay; + + oe.getRunners(classId, 0, r, false); + rToUse.reserve(r.size()); + + for (size_t j = 0; j < r.size(); j++) { + if (leg == -1 || leg == r[j]->getLegNumber()) { + + if (!teamsAsIndividual) { + if (leg == -1 && indRel && r[j]->getLegNumber() != 0) + continue; // Skip all but leg 0 for individual relay + + if (leg == -1 && !indRel && r[j]->getTeam()) + continue; // For teams, skip presonal results, unless individual relay + + if (!includeUnknown && r[j]->getStatus() == StatusUnknown) + continue; + } + rToUse.push_back(r[j]); + } + } + + if (leg == -1 && !teamsAsIndividual) { + oe.getTeams(classId, t, false); + tToUse.reserve(t.size()); + + for (size_t j = 0; j < t.size(); j++) { + if (includeUnknown) + tToUse.push_back(t[j]); + else { + for (int n = 0; n < t[j]->getNumRunners(); n++) { + pRunner tr = t[j]->getRunner(n); + if (tr && tr->getStatus() != StatusUnknown) { + tToUse.push_back(t[j]); + break; + } + } + } + } + } +} + +void IOF30Interface::writeClassStartList(xmlparser &xml, const oClass &c, + const vector &r, + const vector &t) { + + pCourse stdCourse = haveSameCourse(r); + + xml.startTag("ClassStart"); + writeClass(xml, c); + if (stdCourse) + writeCourse(xml, *stdCourse); + + string start = c.getStart(); + if (!start.empty()) + xml.write("StartName", start); + + for (size_t k = 0; k < r.size(); k++) { + writePersonStart(xml, *r[k], stdCourse == 0, false); + } + + for (size_t k = 0; k < t.size(); k++) { + writeTeamStart(xml, *t[k]); + } + xml.endTag(); +} + +void IOF30Interface::writePersonStart(xmlparser &xml, const oRunner &r, bool includeCourse, bool teamMember) { + if (!teamMember) + xml.startTag("PersonStart"); + else + xml.startTag("TeamMemberStart"); + + writePerson(xml, r); + const pClub pc = r.getClubRef(); + + if (pc && !r.isVacant()) + writeClub(xml, *pc, false); + + if (teamMember) { + writeStart(xml, r, includeCourse, includeStageRaceInfo && (r.getNumMulti() > 0 || r.getRaceNo() > 0), teamMember); + } + else { + if (r.getNumMulti() > 0) { + for (int k = 0; k <= r.getNumMulti(); k++) { + const pRunner tr = r.getMultiRunner(k); + if (tr) + writeStart(xml, *tr, includeCourse, includeStageRaceInfo, teamMember); + } + } + else + writeStart(xml, r, includeCourse, false, teamMember); + } + + xml.endTag(); +} + +void IOF30Interface::writeTeamStart(xmlparser &xml, const oTeam &t) { + xml.startTag("TeamStart"); + + xml.write("EntryId", t.getId()); + xml.write("Name", t.getName()); + + if (t.getClubRef()) + writeClub(xml, *t.getClubRef(), false); + + string bib = t.getBib(); + if (!bib.empty()) + xml.write("BibNumber", bib); + + for (int k = 0; k < t.getNumRunners(); k++) { + if (t.getRunner(k)) + writePersonStart(xml, *t.getRunner(k), true, true); + } + + writeAssignedFee(xml, t, 0); + xml.endTag(); +} + +void IOF30Interface::writeStart(xmlparser &xml, const oRunner &r, + bool includeCourse, bool includeRaceNumber, + bool teamMember) { + if (!includeRaceNumber && getStageNumber() == 0) + xml.startTag("Start"); + else { + int rn = getStageNumber(); + if (rn == 0) + rn = 1; + if (includeStageRaceInfo) + rn += r.getRaceNo(); + + xml.startTag("Start", "raceNumber", itos(rn)); + } + if (teamMember) + writeLegOrder(xml, r); + + string bib = r.getBib(); + if (!bib.empty()) + xml.write("BibNumber", bib); + + if (r.getStartTime() > 0) + xml.write("StartTime", oe.getAbsDateTimeISO(r.getStartTime(), true, useGMT)); + + pCourse crs = r.getCourse(true); + if (crs && includeCourse) + writeCourse(xml, *crs); + + if (r.getCardNo() > 0) + xml.write("ControlCard", r.getCardNo()); + + writeFees(xml, r); + + xml.endTag(); +} + +void IOF30Interface::writeLegOrder(xmlparser &xml, const oRunner &r) const { + // Team member race result + int legNumber, legOrder; + const pClass pc = r.getClassRef(); + if (pc) { + bool par = pc->splitLegNumberParallel(r.getLegNumber(), legNumber, legOrder); + xml.write("Leg", legNumber + 1); + if (par) + xml.write("LegOrder", legOrder + 1); + } +} + +bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) { + + if (!xCompetitor) return false; + + xmlobject person = xCompetitor.getObject("Person"); + + if (!person) return false; + + string pidS; + person.getObjectString("Id", pidS); + long long pid = oBase::converExtIdentifierString(pidS); + xmlobject pname = person.getObject("Name"); + if (!pname) return false; + + int cardno=0; + string tmp; + + xmlList cards; + xCompetitor.getObjects("ControlCard", cards); + + for (size_t k= 0; kgetExtId()!=0) + rde = 0; //Other runner, same card + + if (!rde) + rde = runnerDB.addRunner(name.c_str(), pid, clubId, cardno); + } + + if (rde) { + rde->setExtId(pid); + rde->setName(name.c_str()); + rde->clubNo = clubId; + rde->birthYear = extendYear(birth); + rde->sex = sex[0]; + memcpy(rde->national, national, 3); + } + return true; +} + +void IOF30Interface::writeXMLCompetitorDB(xmlparser &xml, const RunnerDBEntry &rde) const { + string s = rde.getSex(); + + xml.startTag("Competitor"); + + if (s.empty()) + xml.startTag("Person"); + else + xml.startTag("Person", "sex", s); + + long long pid = rde.getExtId(); + if (pid > 0) { + char bf[16]; + oBase::converExtIdentifierString(pid, bf); + xml.write("Id", bf); + } + xml.startTag("Name"); + xml.write("Given", rde.getGivenName()); + xml.write("Family", rde.getFamilyName()); + xml.endTag(); + + if (rde.getBirthYear() > 1900) + xml.write("BirthDate", itos(rde.getBirthYear()) + "-01-01"); + + string nat = rde.getNationality(); + if (!nat.empty()) { + xml.write("Nationality", "code", nat.c_str()); + } + + xml.endTag(); // Person + + if (rde.cardNo > 0) { + xml.write("ControlCard", "punchingSystem", "SI", itos(rde.cardNo)); + } + + + if (rde.clubNo > 0) { + xml.startTag("Organisation"); + xml.write("Id", rde.clubNo); + xml.endTag(); + } + + xml.endTag(); // Competitor +} + +int getStartIndex(int sn); +int getFinishIndex(int sn); +string getStartName(const string &start); + +int IOF30Interface::getStartIndex(const string &startId) { + int num = getNumberSuffix(startId); + if (num == 0 && startId.length()>0) + num = int(startId[startId.length()-1])-'0'; + return ::getStartIndex(num); +} + +bool IOF30Interface::readControl(const xmlobject &xControl) { + if (!xControl) + return false; + + string idStr; + xControl.getObjectString("Id", idStr); + + if (idStr.empty()) + return false; + + int type = -1; + int code = 0; + if (idStr[0] == 'S') + type = 1; + else if (idStr[0] == 'F') + type = 2; + else { + type = 0; + code = atoi(idStr.c_str()); + if (code <= 0) + return false; + } + + xmlobject pos = xControl.getObject("MapPosition"); + + int xp = 0, yp = 0; + if (pos) { + string x,y; + pos.getObjectString("x", x); + pos.getObjectString("y", y); + xp = int(10.0 * atof(x.c_str())); + yp = int(10.0 * atof(y.c_str())); + } + + int longitude = 0, latitude = 0; + + xmlobject geopos = xControl.getObject("Position"); + + if (geopos) { + string lat,lng; + geopos.getObjectString("lat", lat); + geopos.getObjectString("lng", lng); + latitude = int(1e6 * atof(lat.c_str())); + longitude = int(1e6 * atof(lng.c_str())); + } + pControl pc = 0; + + if (type == 0) { + pc = oe.getControl(code, true); + } + else if (type == 1) { + string start = getStartName(trim(idStr)); + pc = oe.getControl(getStartIndex(idStr), true); + pc->setNumbers(""); + pc->setName(start); + pc->setStatus(oControl::StatusStart); + } + else if (type == 2) { + string finish = trim(idStr); + int num = getNumberSuffix(finish); + if (num == 0 && finish.length()>0) + num = int(finish[finish.length()-1])-'0'; + if (num > 0 && num<10) + finish = lang.tl("Mål ") + itos(num); + else + finish = lang.tl("Mål"); + pc = oe.getControl(getFinishIndex(num), true); + pc->setNumbers(""); + pc->setName(finish); + pc->setStatus(oControl::StatusFinish); + } + + if (pc) { + pc->getDI().setInt("xpos", xp); + pc->getDI().setInt("ypos", yp); + pc->getDI().setInt("longcrd", longitude); + pc->getDI().setInt("latcrd", latitude); + pc->synchronize(); + } + return true; +} + +void IOF30Interface::readCourseGroups(xmlobject xClassCourse, vector< vector > &crs) { + xmlList groups; + xClassCourse.getObjects("CourseGroup", groups); + + for (size_t k = 0; k < groups.size(); k++) { + xmlList courses; + groups[k].getObjects("Course", courses); + crs.push_back(vector()); + for (size_t j = 0; j < courses.size(); j++) { + pCourse pc = readCourse(courses[j]); + if (pc) + crs.back().push_back(pc); + } + } +} + +string IOF30Interface::constructCourseName(const string &family, const string &name) { + if (family.empty()) + return trim(name); + else + return trim(family) + ":" + trim(name); +} + +string IOF30Interface::constructCourseName(const xmlobject &xcrs) { + string name, family; + xcrs.getObjectString("Name", name); + if (name.empty()) + // CourseAssignment case + xcrs.getObjectString("CourseName", name); + + xcrs.getObjectString("CourseFamily", family); + + return constructCourseName(family, name); +} + +pCourse IOF30Interface::readCourse(const xmlobject &xcrs) { + if (!xcrs) + return 0; + + int cid = xcrs.getObjectInt("Id"); + + string name = constructCourseName(xcrs); + /*, family; + xcrs.getObjectString("Name", name); + xcrs.getObjectString("CourseFamily", family); + + if (family.empty()) + name = trim(name); + else + name = trim(family) + ":" + trim(name); +*/ + int len = xcrs.getObjectInt("Length"); + int climb = xcrs.getObjectInt("Climb"); + + xmlList xControls; + xcrs.getObjects("CourseControl", xControls); + + vector ctrlCode; + vector legLen; + string startName; + bool hasRogaining = false; + + for (size_t k = 0; k < xControls.size(); k++) { + string type; + xControls[k].getObjectString("type", type); + if (type == "Start") { + string idStr; + xControls[k].getObjectString("Control", idStr); + pControl pStart = oe.getControl(getStartIndex(idStr), false); + if (pStart) + startName = pStart->getName(); + } + else if (type == "Finish") { + legLen.push_back(xControls[k].getObjectInt("LegLength")); + } + else { + xmlList xPunchControls; + xControls[k].getObjects("Control", xPunchControls); + pControl pCtrl = 0; + if (xPunchControls.size() == 1) { + pCtrl = oe.getControl(xPunchControls[0].getInt(), true); + } + else if (xPunchControls.size()>1) { + pCtrl = oe.addControl(1000*cid + xPunchControls[0].getInt(),xPunchControls[0].getInt(), ""); + if (pCtrl) { + string cc; + for (size_t j = 0; j < xPunchControls.size(); j++) + cc += string(xPunchControls[j].get()) + " "; + + pCtrl->setNumbers(cc); + } + } + + if (pCtrl) { + legLen.push_back(xControls[k].getObjectInt("LegLength")); + ctrlCode.push_back(pCtrl); + int score = xControls[k].getObjectInt("Score"); + if (score > 0) { + pCtrl->getDI().setInt("Rogaining", score); + pCtrl->setStatus(oControl::StatusRogaining); + hasRogaining = true; + } + } + } + } + + pCourse pc = 0; + if (cid > 0) + pc = oe.getCourseCreate(cid); + else { + pc = oe.getCourse(name); + if (pc == 0) + pc = oe.addCourse(name); + } + + if (pc) { + pc->setName(name); + pc->setLength(len); + pc->importControls("", false); + for (size_t i = 0; iaddControl(ctrlCode[i]->getId()); + } + if (pc->getNumControls() + 1 == legLen.size()) + pc->setLegLengths(legLen); + pc->getDI().setInt("Climb", climb); + + pc->setStart(startName, true); + if (hasRogaining) { + int mt = oe.getMaximalTime(); + if (mt == 0) + mt = 3600; + pc->setMaximumRogainingTime(mt); + } + + pc->synchronize(); + } + return pc; +} + + +void IOF30Interface::bindClassCourse(oClass &pc, const vector< vector > &crs) { + if (crs.empty()) + return; + if (crs.size() == 1 && crs[0].size() == 0) + pc.setCourse(crs[0][0]); + else { + unsigned ns = pc.getNumStages(); + ns = max(ns, crs.size()); + pc.setNumStages(ns); + for (size_t k = 0; k < crs.size(); k++) { + pc.clearStageCourses(k); + for (size_t j = 0; j < crs[k].size(); j++) { + pc.addStageCourse(k, crs[k][j]->getId()); + } + } + } +} + + +void IOF30Interface::writeCourses(xmlparser &xml) { + vector props; + getProps(props); + xml.startTag("CourseData", props); + + writeEvent(xml); + + vector ctrl; + vector crs; + oe.getControls(ctrl, false); + + xml.startTag("RaceCourseData"); + map ctrlId2ExportId; + + // Start + xml.startTag("Control"); + xml.write("Id", "S"); + xml.endTag(); + set ids; + for (size_t k = 0; k < ctrl.size(); k++) { + if (ctrl[k]->getStatus() != oControl::StatusFinish && ctrl[k]->getStatus() != oControl::StatusStart) { + string id = writeControl(xml, *ctrl[k], ids); + ctrlId2ExportId[ctrl[k]->getId()] = id; + } + } + + // Finish + xml.startTag("Control"); + xml.write("Id", "F"); + xml.endTag(); + + oe.getCourses(crs); + for (size_t k = 0; k < crs.size(); k++) { + writeFullCourse(xml, *crs[k], ctrlId2ExportId); + } + + xml.endTag(); + + xml.endTag(); +} + +string IOF30Interface::writeControl(xmlparser &xml, const oControl &c, set &writtenId) { + int id = c.getFirstNumber(); + string ids = itos(id); + if (writtenId.count(ids) == 0) { + xml.startTag("Control"); + xml.write("Id", ids); +/* + + + + + + + */ + + xml.endTag(); + writtenId.insert(ids); + } + + return ids; + +} + +void IOF30Interface::writeFullCourse(xmlparser &xml, const oCourse &c, + const map &ctrlId2ExportId) { + + xml.startTag("Course"); + writeCourseInfo(xml, c); + + xml.startTag("CourseControl", "type", "Start"); + xml.write("Control", "S"); + xml.endTag(); + + for (int i = 0; i < c.getNumControls(); i++) { + int id = c.getControl(i)->getId(); + xml.startTag("CourseControl", "type", "Control"); + if (ctrlId2ExportId.count(id)) + xml.write("Control", ctrlId2ExportId.find(id)->second); + else + throw exception(); + xml.endTag(); + } + + xml.startTag("CourseControl", "type", "Finish"); + xml.write("Control", "F"); + xml.endTag(); + + xml.endTag(); +} + +void IOF30Interface::writeRunnerDB(const RunnerDB &db, xmlparser &xml) const { + vector props; + getProps(props); + + xml.startTag("CompetitorList", props); + + const vector &rdb = db.getRunnerDB(); + for (size_t k = 0; k < rdb.size(); k++) { + if (!rdb[k].isRemoved()) + writeXMLCompetitorDB(xml, rdb[k]); + } + + xml.endTag(); +} + +void IOF30Interface::writeClubDB(const RunnerDB &db, xmlparser &xml) const { + vector props; + getProps(props); + + xml.startTag("OrganisationList", props); + + const vector &cdb = db.getClubDB(); + for (size_t k = 0; k < cdb.size(); k++) { + if (!cdb[k].isRemoved()) + writeClub(xml, cdb[k], true); + } + + xml.endTag(); +} + diff --git a/code/iof30interface.h b/code/iof30interface.h new file mode 100644 index 0000000..359f37c --- /dev/null +++ b/code/iof30interface.h @@ -0,0 +1,290 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#pragma once +#include +#include +#include + +class oEvent; +class xmlobject; +typedef vector xmlList; +class xmlparser; +class gdioutput; +class oRunner; +class oClub; +class oTeam; +class oCourse; +class oControl; +class oClass; +class oDataInterface; +class oDataConstInterface; +class oAbstractRunner; +struct RunnerDBEntry; +class RunnerDB; + +typedef oRunner * pRunner; +typedef oClass * pClass; +typedef oClub * pClub; +typedef oTeam * pTeam; +typedef oCourse *pCourse; + +class IOF30Interface { + oEvent &oe; + + int cachedStageNumber; + int entrySourceId; + + bool splitLateFee; + bool useGMT; // Use GMT when exporting + + // Export teams as individual + bool teamsAsIndividual; + // Unroll course loops + bool unrollLoops; + // Include data on stage number + bool includeStageRaceInfo; + void operator=(const IOF30Interface &); + + struct LegInfo { + int maxRunners; + int minRunners; + LegInfo() : maxRunners(1), minRunners(1) {} + void setMinRunners(int nr) {minRunners = max(minRunners, nr); maxRunners = max(maxRunners, nr);} + void setMaxRunners(int nr) {maxRunners = max(maxRunners, nr);} + }; + + struct FeeInfo { + double fee; + double taxable; + double percentage; // Eventor / OLA stupidity + + string currency; + + string fromTime; + string toTime; + + string fromBirthDate; + string toBirthDate; + + bool includes(const FeeInfo &fo) const { + if (toBirthDate != fo.toBirthDate || fromBirthDate != fo.fromBirthDate) + return false; + if (!includeFrom(fromTime, fo.fromTime)) + return false; + if (!includeTo(toTime, fo.toTime)) + return false; + /*if (!includeFrom(fromBirthDate, fo.fromBirthDate)) + return false; + if (!includeTo(toBirthDate, fo.toBirthDate)) + return false;*/ + return true; + } + + void add(FeeInfo &fi); + + string getDateKey() const {return fromTime + " - " + toTime;} + FeeInfo() : fee(0), taxable(0), percentage(0) {} + + const bool operator<(const FeeInfo &fi) const { + return fee < fi.fee || (fee == fi.fee && taxable < fi.taxable); + } + private: + bool includeFrom(const string &a, const string &b) const { + if ( a > b || (b.empty() && !a.empty()) ) + return false; + return true; + } + + bool includeTo(const string &a, const string &b) const { + if ( (!a.empty() && a < b) || (b.empty() && !a.empty()) ) + return false; + return true; + } + }; + + struct FeeStatistics { + double fee; + double lateFactor; + }; + + vector feeStatistics; + + static void getAgeLevels(const vector &fees, const vector &ix, + int &normalIx, int &redIx, string &youthLimit, string &seniorLimit); + + void readEvent(gdioutput &gdi, const xmlobject &xo, + map > &teamClassConfig); + pRunner readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam team, + const map > &teamClassConfig, + map > > &personId2TeamLeg); + pRunner readPerson(gdioutput &gdi, const xmlobject &xo); + pClub readOrganization(gdioutput &gdi, const xmlobject &xo, bool saveToDB); + pClass readClass(const xmlobject &xo, + map > &teamClassConfig); + + pTeam readTeamEntry(gdioutput &gdi, xmlobject &xTeam, + map > &bibPatterns, + const map > &teamClassConfig, + map > > &personId2TeamLeg); + + pRunner readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo, pTeam team, + const map > &teamClassConfig); + + pTeam readTeamStart(gdioutput &gdi, pClass pc, xmlobject &xTeam, + map > &bibPatterns, + const map > &teamClassConfig); + + pTeam getCreateTeam(gdioutput &gdi, const xmlobject &xTeam, bool &newTeam); + + static int getIndexFromLegPos(int leg, int legorder, const vector &setup); + void setupClassConfig(int classId, const xmlobject &xTeam, map > &teamClassConfig); + + void setupRelayClasses(const map > &teamClassConfig); + void setupRelayClass(pClass pc, const vector &teamClassConfig); + + int parseISO8601Time(const xmlobject &xo); + string getCurrentTime() const; + + static void getNationality(const xmlobject &xCountry, oDataInterface &di); + + static void getAmount(const xmlobject &xAmount, double &amount, string ¤cy); + static void getAssignedFee(const xmlobject &xFee, double &fee, double &paid, double &taxable, double &percentage, string ¤cy); + static void getFee(const xmlobject &xFee, FeeInfo &fee); + static void getFeeAmounts(const xmlobject &xFee, double &fee, double &taxable, double &percentage, string ¤cy); + + void writeFees(xmlparser &xml, const oRunner &r) const; + + void writeAmount(xmlparser &xml, const char *tag, int amount) const; + void writeAssignedFee(xmlparser &xml, const oAbstractRunner &tr, int paidForCard) const; + void writeRentalCardService(xmlparser &xml, int cardFee, bool paid) const; + + void getProps(vector &props) const; + + void writeClassResult(xmlparser &xml, const oClass &c, const vector &r, + const vector &t); + + void writeClass(xmlparser &xml, const oClass &c); + void writeCourse(xmlparser &xml, const oCourse &c); + void writePersonResult(xmlparser &xml, const oRunner &r, bool includeCourse, + bool teamMember, bool hasInputTime); + + + void writeTeamResult(xmlparser &xml, const oTeam &t, bool hasInputTime); + + void writeResult(xmlparser &xml, const oRunner &rPerson, const oRunner &rResultCarrier, + bool includeCourse, bool includeRaceNumber, bool teamMember, bool hasInputTime); + + void writePerson(xmlparser &xml, const oRunner &r); + void writeClub(xmlparser &xml, const oClub &c, bool writeExtended) const; + + + void getRunnersToUse(const pClass cls, vector &rToUse, + vector &tToUse, int leg, bool includeUnknown) const; + + void writeClassStartList(xmlparser &xml, const oClass &c, const vector &r, + const vector &t); + + void writePersonStart(xmlparser &xml, const oRunner &r, bool includeCourse, bool teamMember); + + void writeTeamStart(xmlparser &xml, const oTeam &t); + + void writeStart(xmlparser &xml, const oRunner &r, bool includeCourse, + bool includeRaceNumber, bool teamMember); + + + pCourse haveSameCourse(const vector &r) const; + void writeLegOrder(xmlparser &xml, const oRunner &r) const; + + // Returns zero if no stage number + int getStageNumber(); + + bool readXMLCompetitorDB(const xmlobject &xCompetitor); + void writeXMLCompetitorDB(xmlparser &xml, const RunnerDBEntry &rde) const; + + int getStartIndex(const string &startId); + + bool readControl(const xmlobject &xControl); + pCourse readCourse(const xmlobject &xcrs); + + void readCourseGroups(xmlobject xClassCourse, vector< vector > &crs); + void bindClassCourse(oClass &pc, const vector< vector > &crs); + + static string constructCourseName(const xmlobject &xcrs); + static string constructCourseName(const string &family, const string &name); + + void classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignment, const map &courses, + const map > &coursesFamilies); + void classCourseAssignment(gdioutput &gdi, xmlList &xAssignment, + const map &courses, + const map > &coursesFamilies); + void personCourseAssignment(gdioutput &gdi, xmlList &xAssignment, + const map &courses); + void teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment, + const map &courses); + + void assignTeamCourse(gdioutput &gdi, oTeam &t, xmlList &xAssignment, + const map &courses); + + pCourse findCourse(gdioutput &gdi, const map &courses, + xmlobject &xPAssignment); + + string writeControl(xmlparser &xml, const oControl &c, set &writtenId); + + void writeCourseInfo(xmlparser &xml, const oCourse &c); + + void writeFullCourse(xmlparser &xml, const oCourse &c, + const map &ctrlId2ExportId); + +public: + IOF30Interface(oEvent *oe, bool forceSplitFee); + virtual ~IOF30Interface() {} + + void readEventList(gdioutput &gdi, xmlobject &xo); + + void readEntryList(gdioutput &gdi, xmlobject &xo, bool removeNonexisting, int &entRead, int &entFail, int &entRemoved); + + void readStartList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail); + + void readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail); + + void readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount); + + void readClubList(gdioutput &gdi, const xmlobject &xo, int &clubCount); + + void readCourseData(gdioutput &gdi, const xmlobject &xo, bool updateClasses, int &courseCount, int &entFail); + + void writeResultList(xmlparser &xml, const set &classes, int leg, + bool useUTC, bool teamsAsIndividual, + bool unrollLoops, bool includeStageInfo); + + void writeStartList(xmlparser &xml, const set &classes, bool useUTC, + bool teamsAsIndividual, bool includeStageInfo); + + void writeEvent(xmlparser &xml); + + void writeCourses(xmlparser &xml); + + void writeRunnerDB(const RunnerDB &db, xmlparser &xml) const; + + void writeClubDB(const RunnerDB &db, xmlparser &xml) const; +}; diff --git a/code/lib/libhpdf.lib b/code/lib/libhpdf.lib new file mode 100644 index 0000000000000000000000000000000000000000..672956c8ba9df74716b093f61f4a087609101491 GIT binary patch literal 73406 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 DpoZiS literal 0 HcmV?d00001 diff --git a/code/lib/mysqlpp.lib b/code/lib/mysqlpp.lib new file mode 100644 index 0000000000000000000000000000000000000000..f97f5e90088b751be304a3957cea9be951a32a68 GIT binary patch literal 567206 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

)Rs)+TEuQ`kEDitn=?k(--!i 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%0Dp+q2a$WpyVZ2-zA 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 O8u2>-LS^@qef@tGm-IXU literal 0 HcmV?d00001 diff --git a/code/lib/mysqlpp_vc15.lib b/code/lib/mysqlpp_vc15.lib new file mode 100644 index 0000000000000000000000000000000000000000..e32d1556db6e3538bcd8f1461434e85400f5b52c GIT binary patch literal 737200 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¥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

^r3CQd3mP7W3i>Y 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 literal 0 HcmV?d00001 diff --git a/code/lib_db/libhpdf.lib b/code/lib_db/libhpdf.lib new file mode 100644 index 0000000000000000000000000000000000000000..9a905dc96ab89ec927c14f26fc26bc6c330c6400 GIT binary patch literal 73406 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 NzXKptc2C*Y{|CAir+WYZ literal 0 HcmV?d00001 diff --git a/code/lib_db/mysqlpp_vc15.lib b/code/lib_db/mysqlpp_vc15.lib new file mode 100644 index 0000000000000000000000000000000000000000..cc3296b947235f54b2332839860728d9bb625236 GIT binary patch literal 753726 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

5*qOX`vv z!J6jFJ)Dpe)^}kkF2MJ2dLuA)mn0|*=;o>gWN=*63@ki zn>!4KVsz4#NAwbO5fsgWbBQ`#sOf*D4!0~eQ|kE8OjO`Gj!|H?NvLC(&Q1++`rTfL z`{zjuG))=7^SecBUy* zGHFuAvKDEWvR??(!tyl=U%@!nTDR9p)P#gFsOqHYuGATHjBi@_ z8|+^1YMSQoT|92cy?U>|0B^3*H;v%gn%-9L@arUj1f(`(?^5A@D|Xu3|KdxVcqspmnY?8H}oO zFX+&RIJ6|gUzMO!CyzV~metA)#A7L1YgdV^AG>o}YZv{{t5tB&Vn3j=Pw(VI*DNbH zK8>SAvx%J2#0%x5FW{QdfsiLlf2PbS7JTB=tk~V3?&`a zI%1-|?V^YUSwV%o8TbHJmJkm!H+6N(fDE|B{&#jW=7T)2o?o4mLMU7r)q<#j?_bPFPm)0}l|I&t@>bKDY|P6{9|<2u!ZO7IRFN=X&fIR*PH1Ax5Omu!c>WZRxF`^is z9&$>Ui=e7SK)q{6}H zo=yamhuUei@T-)KUcKF~HwMj4n+uSLTT1f)i+iNm4_n~>54Nu8yx1;V)TTftSoT=y z^^Dn0whvR{;2nCtwWut+aEX5-gNBLeSy3DZ=}Tc#2ro`zTVqrZ)(~s~SblH!xz*P; zA6tAo`llm*IqHYPcR_fo5q6Pk=~vI<|E;%H;vYp456>;-%>hL`l!ZxDL&^I~z2;HB zy+me6mM=Nwne|gi8)d^QX$?wquoZ6CQ3k+Lwil-{>8PfSx_l1s7(G}G(c@dZMnU{l zm3w^||8yuU0*11?y1saclarlZvwbaqbkyypeaj23ic?<#?9wXY^!?7>V5@VptzQUk zEHR&^IVdaCCZOi3rDd1kud{_t5}SzgB!`@rVj-J~A$;gU@p~HUlHB_cwc#zU>n(hL zB1W6)y*-Qv#lvxDP}iyphxX3^YDg%qfPjH=1}bWqQq%is0Hk?)I?H)B-2vqkmn%Zu zgLDqjH9*Jk+=6oo%_T60u-t)i2FVp5M{wMLaRS8!5C<^qL0Chu1z`ET-RD+cXZu*Z zailn?-~;}Gli~~Bus~&_+Tksg>z6+SpqT3u|zQT`?w<_b%YaS?GZgIC=OA zCH+AzBxE;+CPxM@#uKArKM=7GXqY?+6Q^L(1WXwJWYJF)`y`Q15clLzPYm;<5Kjp2 zWYA6o>m-m)0O$BojveE;5sn#O-sr}C@^ywnTRs@DYlX5)1jmwN)&PiZv$U9q<^zM?M+%x)(K`bxAzEFEIcwe zmqiT~IY;c2#J;X`Y?!&T_@rXV2Dpz4MA|l?d@(QWwi-EB`5F}VMbkMHJH5`$wAmw| zA^5F~5;{TUh~)vSR1n8Utc*x91Hwac%J|3JO6=-*Zf3AD-e`H3YAZBd1HUB1XBm_& z3f8z(XlQ!f-|KdZ{zro?s69jB#1BcPN%48s=#eXs zv6<-zqHBPT;kgCp6q-w54q>?i1G&^Tlh5Hk4 z2L6yLceWAC@>4Uo?(AKU%DBk=If2 zaD0`C-Ys!%ZtS0VB^BjhZS(Z$VB_TG+Nof7_)}RpGQTi?@bKJG z^so5OEdA@k(Ruo}mpOE}nnN3u5`@kIg)g$3A?}7jS6Z!)m{k-<@{6cIla1e3jbF6 z4?>1ML;yT*2LJ70@ZbC4zj0W+D(cw|w7&KwrP9ZMK7tN?f&L)k${w3?)$=g9JM1TT za_9@6{bT`+fggC$n1k_8(9iEd|Dk^nbk93V|Aqdi?45`I2Epo?^|R+Ug5{M9OXpYD zH_o0XkF&a6_#GC6!~jn#C=cSMn@UpV4l4usKhckk;D4vzzgb9XoLB5Hj*8;A-`9jSGFG z>N2?*_8WEZ5+he}r8*17!8rhUAFo~czo*(imAP2c@^oJXx=WypoX{PcH9E4h@B1T% zmHbAhM48bI$8|2@7PpJ&n95o75|$HRFFS9K#@d0GiAMo%{e8__B4}Hky(_IS=(Jn6 zxxJD%n>m)J+Ie$FD@qA|C~$e^4&d^b*_&O8j~r6+_d&ql``rQjjkWx~liXQmw!id2 zyngsuI5R#@%h_SU=A4zP2E7AqITu@?JU8A6+_?W_xRFT>re#cK{Z>(17QX;|dB7z3 zGE8x$Wk`07G^;*We+D@6z)5n%plZ@GBeQhOt98hSffo=L9<(c0HPJKM))ND>y0!ZLM&f3|Ez4cvD z-z0w#=I{yQn8T>6hrQ7(sVT~4szADzbRo&Sst45^`9k2xLvrT`3bo`jEA{#K1u(0J zj$>A7CYAY&t3)nc(Kg(LSv@TGS%Dv$6Rzxa7?PCW#8F!fw6U_za6 z(@UihkFrb9J>q(th8aCvJtNJLPch?MHMOeCN?YZyT3f#XXnTYeZMmzk?E9jko@)Se zedOqKO{<(npjWMPUjp=gk`=uQ8Mi(mj@-*Tue<2ay8<0_lTP-Kex~#G=7m28-haUp`{nTmZ zuhMAF%H8=n^$lqOxcg~S&RzM!qdDHKEsgmF^%|UnHF)&Yufb>+Vv^t^8ns#X#+)Hi z_UY5SE+`r+vNrpvc|>g`Jpg3>G1JUjOUvotVRdx(8IYjxSdOo&ZK$D+pKIRbHi?Z( zjVcUsaa%_Z;O}x~+3xB}MeUnzfZhH$CVi~W6;8;kLSiTT0cd)XqS3FS)X6wuQ_&sW zo!79UiMG5LXuiie&C>SHtT*Rp)xNJsgWmj%h+5QH6+OicHb7v5L9gB%^zY86*#~B8 z^sN}l=`~zDvh(_gn%CEW*N-oFjhOWCfef;_c zRnzG-ruTTuZ`)?qvK6)O^8l>elZut&pBZTl)~vgwVup^d9|(72Hro-F|E?kvkbjGCGs^N~G`{v0Q2LopDb0b) z26=vlQ`&J)Lrw@r$VD*7^D`aOnggfj)Mx58NXfI@Q7`&e9PC1MlztPao^?buZpCdU z8HTq;6=ziDAQQ7J8AZI!UIgyWIifr1)aO{8Dr2THrxP&x08%HizIu9;`mUh{i_ z@&$L4qk5MdQ%BHjb80zw8PIvqA)Uin%uOSmY%HiLe+5u}$PwjWzbaaAS4b&<*f-_G z=1_YE(X;Bqj%FhnpxI@5PA${dfW{+?MjFzFs;&*FfjfZvb$d{6w!>bPln~_V)ow!F z1-$B{)pr%xx;bB6JsIC0v{#%FXjgj#LZJOG#7bga(2FEu&SC|m70?rD}-oSE8#YTM}Zf!gP$p_Xsc2Fv)SC`QB;?A^ZA2no9Zlh*p5vhKPAh=b>JfNNj1Nq)<}!6KGi8& zpZuKCSC zF0c>@pNs3o$$CC4XgnXUgS9zctc^v~5u$bZ8G4y@<3Wwr_Ag0!G#~IK)gZNh+QRQqeHsS8lSb z*i9amts&U0wwR=xveJEsg%l;OJsr3fn&?gnj8nb1&2aad4b<{CmmOo6`&A?UL@~GQ zb2sdk9fBK-gf_elOJ{axUH2$3FReRjbJ8^9hn0u^ORLMPv)1?gL#(unM8#(U6)!VW zkywJv9MI^CBY^vwjQe=K*$THrA=DUand#8*0QE9zrJ=)#{xY3lyJ@I!pbt#;bDPkx zym%pOkxh|dNiy%wC^b@&OJqNHQcM& zcK2GvbVqnO!H*qO`Rp1K=RZr2-N}A2dFMV`j~hyBSDW!C)mwJmsyUmHw0&NTy$-G0Vj~G13f8w7lV<`n;=8Mx(;$Wv7)@Vm``+g0j0~=3*P*Aya*q`CBX2+rk#h0X` z!+!5-ZZ^mV_oajeh1*mq4w*HUNglpTiyO=W&O4=Of0LOGlRf|Cgbpx7*5LLZD^7#+ zI6HpBx$zYS{Q0lKR~oR(>mWIUGjrjfCRX-jki@St&>@*Enemz|&Hj51$l~iLR{mi;G2qVC)@#e_i}6iuy>`l;1BW!ZK~Du* zzClZiBEdAf+-r3469Dt;HJByFXU1uYhkPT!35jL+7=|$Ju4KYG^Koi;j`FeIFq8^M zXOY1&`=+5ZfEFaSinaZ2y2*X>P&#bo!IU-f#t6Gym(i(3!jd+ma|vZLeT$I-H*#R| zaDMAB{1f$Xn(h|gHjMH%q-WvgboL%Elke%CU?Zy0WQu`^poCR_0Pjo7WvVS{hv2aK457f6DZebxrtKWN5%$`*H2Xk9w}p9kyx zLj?Cmuioz0RS81Qy)&kIxIav&X>{69cCJ6@HKA?^mF~z-=h7U=ymJh8)LVwpp4_U6H{ zbwxIvTV#D_Wo}lgwwA^bjb~y7DE;wFl)AhlMQ#5iEx80#{X}M}+}xW?+37zi&=kot z6<($;W5?olGi+^DZR@U^d>cQNiXsS)9I+-G=S~-YKl|;ObTjj?@3XsTuE|K zH|L*Cf&boxu)ViS3cTX$DtMrSwTi@+tXk1z=lvX^YS3)o1{E!Nf91`y%kx>PSqNp*@U0z_+DPK+f4}XdAm9=Ojt(Po%HcCQ}SvKd6vMZ~&vmOC8e||Zl zcDnl?+VXf_({13fz~f&LcwF@3ve#>-&PVTvxIM;xPLlX!)zcMChf-7<|5w?3ENW9J zj*`q;q%y}sVxks7_2u8mXryPFo7(uBNkPd@wV_t~uce@xyrqZ_4?}%<1-Y5!z);ux zU1_N0L(*`jThwZIFdI|NuwQ4hxy#KCCp*tj%jDgRk1lJ5S!y#=y!btYUQI0%h0tZ* z@ut|odn4?M>K6*+S@*9gR{a|hZe8681p(P-&y=)udqcS*zZp>=*I00ZnHiZ9W)v5B zUxZop^4#qVBJ5J~rUG&16*utvw;A5V%V`DT>?^Iwmqi)wze6x{nW1!E)v5w@ z<~bYu=)WstmR~ryz|R~7lBA(JBJU^o4X;xb1Z3yEA(HU{LV@-rrW5=cpE-&o{9Xb- zmm;M=o_X~R68}MpJNe#DfjBeQO<9;9BADejV+yoc=X+3-g@s-ZeVAYs-z_=7Y04V; z{TOE+d&{6l{~*RJzMDCdG}Nr0EA;GJEw_<6pm|hjV?!d?teJ~`+-(qSO zWao&xSQ5OVgxb!^5O!9sR%V&8CC=j<%;WFW^H8sF?7#x{8VJnH={ZfM*-rw$_un%L zr!c}qcRY4^z)&rF(vsndhPgxCdnG zUn07vI!^9(FB@X!|61_7YBtp}OSh)?#8W}K|4ra_k)hz$My^DU`9;0*rC`PXd&K$i zWh)p|W@f9YVu(%t2b-H+=7Lk5Q!(TNe8eTaZcfr!<{lFz=Q2pnf4Zbre&#rW9H?)q zF9b^e%O$1o0zpcx%}(n)3!RBv?EM)F%zC$av~?WC^@eI$@yp+%6T`dU4D+^naxE-y2P2yfOYVHY-V?Vu8z~QX6~^1 zK2Zjqer(!!>f}6}*X+M@z)`O>;~hH&e%)!2Qq}1)vd@OKt+zf~4X-##Y=s==su?$I zcKxpDf_x3ctDGD4%B_)|_9%odYVfZD+Wp*UR|=uJ@tY)CS?{l=S|T%KewwU8^HG_Z z4ox%_RiwXPM28~3&`d_=^*+LkSSbtY`9R0VMRe$L4I^SSA&RVAiOdIy8dT%+{^_Yv zZiTG0m|he=AfiRifppCgQ&!0Xhg0E(6Pny5RNM1G5e=%G%!nIq=+H#PQOAG>M|4Q( zB@qc45zV|~Or148ekc`6Mr5Z!vujb6(@$VDB=SWgRw#+cygv-9@eo3TDs$9KL}pHy zG6o(hQz2)%MYK4R4d!T(^cSl4_psE|D3>QYXEZW`H2WtKS`7KE!&sA5T1=Y#;pwSS zvc@GXk07*Y^KM=9CA!>65`!v9KQb*XPPk&K)%i&YO1Ny`VJyikxuzP%k4i;}k|EjY z(Ci?jWj~qHk<3w!*r6mMtE`$%n@=G$$l1yf0j{)~={?G)4xvHGgv={pswVwugaR>p zI^uyF{3eNfbc{d$^TlxHetHTz9C3p==_Q?os+v9~rb5i_cDy1-H20?((C}D7gE`we zqQ})PIigvcV?fd4GEwAal}wh=J(M0pE_lQrH`JKwvwQ}jMrXJy3COHR4Z8gC1ivan z+~^p}Oan_NmG%wlHTHyIG&tdcNs}LlC=l}1UCV*SLPoEyo)}ReKy#Z#ePy3S zDc}PvX7rh5fI0Ie89?^llL>ZxM!Q>S)bIh_>YtL15+^cg^0PcOqC=5o@0J?|{qVHm zR5;;8Wu7Sr(f8Vh6?u9p8tl@~@AEim=Kubzd*BaL%a~t)&`IQ)M?Zu=jAoN=`OM+e zJBY}eth8qk3eaaUQ#&SX-73X?IcL~ z>}ZrZ*?p#)ctxN~S?7=N$O$E;ii2|*DAAYK%PLK#ii7iMDUwU zg@FS{G4_Lsby!?ErhnX(nFFSq@Ut-uhlW{{uoQ8yHPPrJGexGlcF!RcMZ5EI4P=s; zEgdK~9oBcN%TVU7u~Y8_gI>J}{im0!B(VVh7sglS;9=b6a(xh1XXRq5BT&npEQ?lG z9kj}G-BP>J+;u}Sb2W$*zZfWfo;!+NQ5zj+BDHS@YM<|nT96^JOcj$UTESc+Qt%lr ztXLm(dLU--nuSPOLaefChRT9ks$L1RK9=9C)%LB6U9!L~?&2zbF3hK@nh){j%vRBM zh5s(*y+9-Edvd~ zmssZ~#62@Nk23L){2FJ0n@g!^4Ev3GH=G20%cW+ROqW!YhD{>an|`P z5aYQc-`OloC;vK`#d#r~0@vT9HK?(jDhVcMJ_}6MPtMuXmvq%;rqGldb)HZtT6EFc z5yy2bnn`wL)zGGV;0qaPNwOw0HOxeptV)y*ykVwB68C&Lvzd_=d(N0LVlEPD)LZJD zQUPa{*{EQTv@&O4W$q>T@nR2;FVql0NH^)-)tRZQL_sR?d_Y}5E@A2x-TDjS9l5x& zBpFFgslS{z^(%Q&e_!6zAJ3Ee7v@dT=S}@;p47i2Z|Yx=C-p(z z)St?e`j_TS{h2(eujfs@e5KERTFtW{n0VH9;HDqC%9qN+VIRkHcxas@jh zQ)R8&4Oxoak*P|WE19{)j4jFUassTa>m$>ZFheq1fkzE=^+u;l7I~+1^+%^m7O%{7 z&1>>QPCyNs0i$aQD_%opoK+Oe_BL>crB+G%>*=t+_Q<*{b=vK)F=%$$oZVJ~D5WiK zQ%v>-!JS7;R^wwwotkeFtg4q$iRot5WKlUwiPNZO$E^r&G8SyjWzD-6)QRUd#Vf_D ztmhh)o0jH^c>HpLQyKBMwQo(C2A_rTE-Uf6%uh9C=zcb)VMRehjpoRnw5<1I$~gEO z19nJ{g7yoxvSyn5D=_xs6Po)g4cOhx-6VUj!q`tJ=I%B(+Enf7b1@Akb&*vgAz5{u zi5IUXbmY$qjfI9@ZGRr7VRfQ3d_Jb()I@3c0!+i{+-X>-Ff&8+nZ5?Bzc0izoIiE| ztiPg5g!lp=nXWDMAGm}QjV&rgOUF%SyWX_ZzX-4FM()yOqT!1%4V$^sU^@9;gK4;= zpn+9Pw|$pms?Yr;82e?bTZZ|;Xx7uAVyMskr7o$puX$Zzhlr@RP<`$%b4h73K_>G~ zG}X8Ma+kD%QfjuFgJ!+ee0kUlTFw3do{}VfK02KOwG{IAB?gV_w|v-947|Fr~vWm5RRhTxx@6#lOz z_~$2u|LX|;g-PN6dV*i|)Rbug`9O6lf3G9>59K-kN`*Zz5>K86?7wd)-4AMZ2Z!O& zXs6vD1pU1${YJ0Z9Y713_MqNuhrQ}Wxk}n548$rq*lvccttxs^I$vEq8T<4OEmrv= z7+z+cRVplqAkzFIp!xM_Xa>KVPzmQEN~E5v9yqYHcyWHtNNm>Arn0~u*Ne1%HqiQw zsc7YWW{Jmsnz(m9b20gF-$3W0De`Q+=281U>6~~P@bQ~s+={}^GU}`=Xvzrw<`}cC zl(URJv$UK1xo?c|%LS9I@tRiqTVlMb^2FA-O&_sjA&~7-=AaS8uJblAV2IquWtqvPr))L5*A< zQeKd(a$wr=Z=%=@C4Ob}ndQOcTYodfuPvl&kDVQ^3QhZ6N$gy~S{Zd#zMJ;ncQedP z${gAg2Mv*{@1b~QGsk+a%q)<&{CGIezL(+@ORw5uG{wrkkHhGCH<@(#_j7o~vZl7P zJ*WUP+R~ZF{1C;TI6#^AE>*=CQORfB z?Is=n!#eu32VPd}rU=$sbl6iIby?{!>7E~PY|EWvV;=?6PKiARmKSdVLN&knGg z&cmOIvFmQJ4k$3q|EFULRQE|2*qO?c?5(GQoc&CUefY9xmNt{;;%6hwiCd+MIkRB6 zG-s4^_j44p>Rzcpoqg8KttjC}^{9V7fm^mYT~J_>__tFE47WH137L01E2bgwU>11r z3zP!wJ#*By*8E4Q|v+ z>sKgl^SwjCfXuu%d6eG4s4(0;T+m>;|NJVY0k15srxi5Y+nxAMuOJ|+6jbKe6%V4 zFk53aCGjFC7@v99R3ZnI$oVe?iFucb^A{mqz0>0)27VB5;-V@GB(fncF+;_>D$GhN zRGH^CuZfu*0IB+QGPiyoO7R7~8)z>enL;Zzoq~j0*FZ5`DQPXM2AW@BMyDuGHQ@QX z3!V=kI2;Q&<2mS?W_u7`?bTZ-%-kQ;+ka~QLk9$tF-eRv(>%|NJW-0S1I@pYpxI%$JlzB` z?}JKoDHUh%6)=O}9Lo%{Z1c?P6NRqD*?lFq_!g z(IY&$C}U=-7c}vR&j#K5+l=a+u)fvqY=z7QDeT(X%6bi5MzEESSz~8Auh%Yt*0%Iz z&PQeH#2t1U*7A4QS|Va+i-nABoG~n9=3QAiq`oD873j*}B`bLgt)ZjKajmuyEZ!RM z_w5_?7P)OVce_ww8&xZeJ5yLos%d`jcRfE;ZgJf6tEkuSC9r-U!1G($spFd+tfHm) zw7M!kbjW-%S6Hfrs5f2;)czi&Hf&rAI@{aez_6rvapjVHXl15%PEGI2fZh)#=ncYK zjn-bjc>^6^HoSI1x%#HF4U~U~P~NJ8%c#G%z1_SO^x=txHPNf9w)~zys^<4CI9EPQ zsP43&qX;_>r`_vy0lNGw=W(o9-jL>_6gF|6Uxs!3eY%dj-Fh#w^QP0+v`TC6kE$(D z3k6$`NQDK7#Fct7tkfUSl>#SBZ?A#WF|k6Yeb+hhH7}?&-77#p|6zjfHirrLJ=SZ> zvzxtod#ke>)Ef%H zqVXNfNTe^}?#w*Dg$1?0^E*M`{+VKaMQ{(I1ZZQJ7s$1Tgb(Z{7Cr0ko6|&ee+6Xv z&lPJ9QN(eD70p~##V=_izXVeg0QS61QpOI}T~(`z{6{vW1y zIRrzg)Z=k?5{ERS30&T44H+J0hn2P%^y+w30oi~ ze?#c(L7r2w#rL5%r81|siLZi;{ViU*<0u6z??krjGN|<;)gl)n4safJFU6G_xXztVoXBhk9*3YH=va>1V-e{$sS7 zMHrc0xuQJRF)U?fU2lrB{u5ry6OfU-RUg!miQz1oj8ar7u*t=d|2d!e;pTngn%{!v z7V*`v7yl(Ozv84OCpA>`g$2UgVB&}W(dTm+?DBOYe~WZ*^g;6f6d{M+b zJ@1?qo~y72XX1JK4zTArvhp8{E0CELpFg(mqG~vead?EqR?nGc_K_TBhE_6N?8tUz3-f9p&Ku#3{!ejc z#R1I@Xw%ZTcIJvvBWby_dgx87{a?jus}JitcD3g;6`+3}^zna-t3A$x+r&>*Sjw5T zYU0QLOokuB6n(Dzm_MREuREao|CjLtC1x=Xe(`bw)#wHJb@O^zQs$X&U#9i@Xt92} z%h$eHzsiC-Px5m>KmQ+FzwUOk2Sw^#+02XZ^ap%>!79tugY2vjo+T%)MA@ZrUVT%1 zK4_DVC1+DulgOG(y&PFBy~+`FPT04CY%)kCsLeEs2afg_#rJkkw}?Yrsmc9st-K& zG2JKY{a~-X*AKUXM!j2aH1Vq}S95^fBDWyUuBGPGT518b)C`^j>Eq-y2^W$>aIegO zZZnoBjgy|}&$9ZkSn?=xB~lQimZD4Gt3p>2DlbrBL3|*PS&lRvwO$NzbU(HRP5fZj zE_XOsbJ3f|a7uriNUbYD$8R`NC2ePyf5U62`;*!9xwO2gxA^z#Yp4ZH)sZ)Y9(w>@ z$5SDG5sU1sDNU}V{_xRs$Xs;{A@Qu5b6)eZ`Vy@A1Iemyqt_!-Tx$t*r$t}EIcP0| z+O=4oaHhHx55ntoI@~TEzp+|PNXh20+W@BhTFyt!-NXp!F6_AnleOH1(&ojk%Vi1e zePrr4k!@JLk0-0w>kR6HB1;(_g&@y7_RBb{31g{8=V#Tc_gGlHPr$2prhYBN4^JK5 zmEoRwXI|HAx&8m!yAJq9j;eorp_kAhp&oDq2qE!Gatk3R`|OLI;#@Cj8`)ml%E^*X zlCLBI0)d3ydkG0O^xk{#y+f#>_uk9*W_D+_^LBQuw=-*rv+no(!nN=A|H{01@69Wk z2|Py!+~$K@dbvBu-EGgr-YKuF6j7e~W#=%Qn_K&mEQfw#FUIR)NjjRjbGPv&Sv%lm z(7W7bWeqYpWKGreF5gx`U(fXTMJRjprBAkRa=8ix37s0n>Ux)Nr;vG&-fR_%!EaGK*5g^%QYVXu3YBQ6quH*gA0ky1iOe6=^ysHIMH?m3fAcI7< zzB)-B)01REAH&uRQU<1ybOzP2&kMoc9veuqQt}gaU1x5|daI-ME*+w_ZF5VfwxI4> zzXW7^*MM5vE$iG~xv zCZ8*8sWlyDjv?pBCgyu*fEmg?N3+Cyp8#_m#=Apa#1fxJMsS&-O+IhP05el^bIj_^ zQf!0seFMzFNbl?zP4@^BW(+XY$7O+9#cDF@e8PnNxF)Ghw+<0*B=mYofSWe+Jm(|37i!}r5^9ml~s$nS#!s84LG~Lv{0(DS4@l7 zI9{%v!b+>7S~hF$fePF`OC7vTntG|4S#u{S_`Z696ILmzUzi^fE6n9LzWtz44~kN@ zL;HMb)|Q}r0#;&KUo?RVL&%z_!|rhG+q|IX(dyZWv)r&bcyA@LOcHx;p`WH(w~SwU_WeNP);cxszAN$2Fj< z=+o8J6OVM;q((UYJr$2-f(&#BI%dsnisqz_MsZqGpEzjpN!4uX+T>$~JaBjOb}Wjs zi+DRI%*lHBtz;0+-8jQsnwx{%I*b~F!ETKr6zEprm*rZu7)X)t_;k-e#+ZEm2gOx~ zaO42T<~WY6%U=C(3&IGjaYXex>( zGr}Aj%}3T!-R9HNt)reCGrm<5_Scp`GtRJ%7pf5Pa?=zXR_Avv1jJ`%ff%uvY&A3- zJ}V2n*ny;Tct~9>eJyZ!$~s~;I58*~RSZrH{zN&IQ8JWJPmWcKEUCQu#cmnsK06D# z%hhtTT&k2W_Udk>46RUOKm}4ay7V-5a|@@U(J0TGIzz(NZ`c6Mx;Cu6=7!p89d-6M z)V7Q;XM00!w~jj78)}DjyjkB+JF`HHOa|HRX>O=pS>Vm|hT3f%@&CpRwI>U@v$>%P z>etmv;hxzxhi3OZ_btHZe^yT~zr$xPokX*5V&z#>HIxetJ2V;IFbcBteD64cb z$iofj*j)B1vyE0R39_uP7Ov5B`C)SB*dG^*6Nb024#|ZHNOmfbVBu2F{D27m5KsDm zC#3+%Hm|WB>0Y3G|x#q--2vt5#pAeADpFO~zS@wNaRBFR2 zqm->poSr3|+$x*mEU5ME5b$#@f-`fgoFN_aSuZcn00GQ{Eb1C zW{1)ycWQUxZ2xaSazgxkyk4)>ix#pK;Zh%DAx{B>WglU~bDM{kJm2u}pStDhT&-n@ z*mPT-C^zKRpl~PQFA|>o7xq_)<=x~G$Or6+H{s7g$+J_6*en-{qlmA6?y z=%0@u^)HYo>bU9H-pRp>@Qm*E45A;r0V^~>6?fZ|$|;=s9Go^H(4 z%S%nDe+q_j6?frSDHbL{RGWubvw>4F19XcDWRd{6IU}4EpSI z(H@RK&)cL#rLJU8Ete2Oz6bQR9+iZ}peM6s4yJZ5VG7KLfESHScp=RGF5Z;P>?d{t zgFg{&;Px`4H2jF7p^z;47I}P6M>bSW!Vc_aeyJ1aUr*4m}XJ2ihP!JygJxInxVA9)l4V`9RXe) z@)4{U3`2sK{T)9_E+XNPd7`U~KgyNOL5qhx8h;7vKiz6ZDsV)Gme1c`nkk>;c0@O34)8QxDM~h3*$gz&&s9yok1MWV_DqeHm z>gv*-9K{MnauLf2)pMKSRV;pdsInattU~s&0K9q%{{D{gVip*5Ja}ppLq^{Zmq#KV z3;_?G7X5x=HdbwXsj>(kuMv(@0msvQ9K26E>7Is)pjL@1jNChCT?9e&=O?X)A5LK? z4_Sf1TyOch%lT47@ieifJSm?2$W7LlnwzO;)a6!eH{;;jlVCS6l)lCJa|qNLq^|s9H9vE zy?HLk;JNvxy zc=2p{^->cmlR-AmW#*1Wb zSj(8{)GT;Hvi-PZiCc~)PjEe|{+cXnFsqw$LN^mfpvLUwt{K2{-NBIUcl7G4w3 z;IENi!x?j(iXJ(ZP*ZF7;;1I92|K9v;;sWb_>w3udRB0~uFvnKj90VJ>}VXJKsbq> z1gKu0qv@Y}Sp=swkwO@(>}t-Cj+bXa2dn;5bu}B(p?l|gMMy_t0xGT$2&zW<1`+*eLqVjHSwW>$ieq%Ev3>rzNt)bQy+M2be%( z*l0(k%f;e+q_$)XPC|FUe&EY%IEFfG%;{#IFQ3r4ehm10uVoZ?i%ZQlKKB|9cr1ZR zzHt&fD%Ju2x+tH`JSuaXIq_I7M|~Fo&eunA2F5sSfr4K*OXaEuIe}CiRp!VwFQIQ} z6FD~R`hKPuWV-#(?1Xz`yO`~D^{5n`PLpPu-_ZS2`QgKB9%5A5FCThcc1O2pX+a@*3|fk9&g)t)-xlfLZP zTn&`I!w#iFFKlG-jU}5)*q;6ip!c0EdTsl0{B7fZy)$0@^6?em+`HQ19L4IWonH+CP)5`h0>kq;^XB*%pP36bod!Nz@{ zMSB(HkyrWgaxrBF{pF*th(Ws2NA#cVkqMeMCu|3Q6i~CH@!TkjI_OTP4k)-T_xk^wN$8+ky2tX29L^P-EQbFNa*;#94Vr-%OyusXZ6Jhjs{B2 z?j6|!_q3V3l`c{^(b&qeWoJQrFGH_?m6B z2rOL>)IJjH@cz1GtO#lfzN%xna{%i%>|#Yw$z0XUMgFE$qzEXTr1x; zC=p0HC)Jsf?SS!nmM|iSDfp<)IBWxq-?xJiL8Nn0eG9Q|WKkvS(W5`^sx!1hx^YzP{iZ{qqu*jV)SGc#-m8kuY2(m=>20ol)ukRf1n zo{6ghA)5eXzc4|DfRQ;SE(nC{G{E&s16&9eonPWwK)5you3x3cgJ-i9cggt<6R0$%)yqhR~gHI=MT5xwm3KX<3qg{+DSR-P>lULD;j$eflcmD&uS zy5&wu%d-sgxdXy!kbTvs0(F1Rj5@GoX$d5sa3?Q@E65Zc01E$-C57%3jBE^l7}{># zgsHz~Muj^S%^@QaQb8pamE%a5WQCAs7(|4N*1V07$lkxv!CH#E8h|#-~G5&Cw6Y}mh0{{Oh<5%2@BjX?d zKAOO9B8WBEk@=~^^RE^0aE4mNhLfM4)g@ zp#@9{(K0)QH;^%DPvH*0)QB(sw0a8vZ$&((75QLu(ViG>n4%%W;_ z*xrq_n)&fJTnUYsqb6`H9uIgo66V?Dm9F2A#}QOC)F!{M|xeg*0Ow7OO+}>el9r2c;$`E?FNE`k+1F@+~t$9#f4J{1%R? z>~qWm>RV-mTA|V@aEsKdjGI+2ADtm?tl)Gl5st5ndk%2l8sY9D-PUY;yG;hDE$Fpo z&f#q{Kx{{+)tQM|(2d(=gxOr5)p_wUV7`5bxl+p9T&J)g$=tp}HppXYZPR+(F&oSZ z#ipZ9zGLo`9crxFDKtdwH?bT2&NA-oOf?;~qs}5+2&j*-kJ?AibL{q%4bQjx=G~$YIdjyGM~) z?27ffYWzm^R?ioDx~KD8L&-fdp@e6YVI#L~O7dZ$ifm1)kVCyEqh#J|x~&?4wLJ+Y z7|zyWhhgWLaRyvB4Q;(jdS)prJ`S-({g{P!7DrPjaxWDH)@(yun2O_NfkNF2x13xPnI2>^hST^31%=88Lx=lW3~I?z;jP+URVyOdeJDboS{uM%_XU z^r~E)t0ndAbCY9WwM^xsJH7W~6qINE!y0*^54glT-|^T3G6!>NZ@&VktO7CjQYSawk6{e9|O>5srCI^M_KU`wgjwlmaCFUxE!-i8fZ(~mGPeqZiS znE3NU(3uDJbjGhN7Q;}wV#NW|8H4N5SYz@->P+w=Xv_&cjR`eo4+L4|YPnf1RmvB8 zb-y6qIPgMcg=D`i*RQ_Yeh&BYgCyx0Tx8*S@uPluL3Z$a%DL!cQYAkOkhC|f4-f20 z!8x_x&!!xncm#9KT;oI_CueGY27Ei|2WV3VBV=NYnCT8<)@QNetphctY^m-&0yr zap9Rn`L;MR?&6^mWX%{51zZTjiGblDGKTnLL+tZp|3fne;8gzghFe{(R5Bc|ym8cc zg0XJ4*hU={Z9GCM;E`plo3>Eo_~0EeV@5+eFnUg;>WYrbBP&p`BBSH*$Xw13ilZd^ z(z9S=M;X3--eGs9wz#y$-@bxff)%gPV7XO;6mPu1gsM|I>$i!^tPI8{!T3&`fr1(8 z*L5@h#*Vttx{VcY9`-Rp(TH2B`;#*ot`be(mXY0svw0oLNPV95O&1{&A6XYc6#e;0 zY?YZ)7|Iv&{e!u10+qkuOyml5y>a7=H~zFE!!l0j>H~E8r4-*_kZDwC_wA3iioXLI`{QJe? zPVgh9OnERMp8e6+Pk^sahF@nNE=^aw*2m9Me4I>qf*;P8$vgA%T z?Ci5yT0lP2I-NPYr!)S78vb9t9k!=4;5O;ziEd#!vsgOh2L4iD@xu8(fz{;|kLF%L zKEWol?P*&Dk_HrmtobO!)Zfz0WY~r{Z4l%r98~f>t*L|Ej*tdk^73?Jre21?1Ag5s zm8%{s5$BW9BCFnGlaXLpQocAj(Q@vrU>DAv?A^1z$Q|uthw)(2EYe_2{e}&jMp-S} z3ZTh%h?7v^^k_i6lYkm#xrXKe46VFkOdZgG&y*QeIkh*%<~Qs@R9Sn=vJsyN6+&Jz z%d_s5aI0CWP-C)2=%Um;97C<{xpl6l4aK@E^9XHFJg6fsuo=dC83H~fQ+GST^DPP! z>6SOxgyiKe}m$o9C2?Lke|B}a=SAn6W)^<56{ye;a!kj z%fs_mLcVG|yg-X&!XP&BU1zhmY$qY2W&3no7IRmZY7MiTTy9bhy2-Xqmk+y;V}vIi zn5Hz>@S6Vp){6XF_g&w(41;QGbh()lm+|tVKSN$&aA5c}R^955a(Y@8rGpQ_< z>K+WWU`rMxu%m2EDI1L(Ygi|rC>@4{76wQ(ln%hC_4r6>3$L653BEMTwU+}7KrBkO zLo)_`{v}hdd*8T-f0@yoa6*l(xh~q@$G=`%a;Ho1u3~fw6^x?ZdyXbbt01J-qBINg z9ZK-9H-Tm?a@fV8} zcMwAo%|{0I7)XFZFn*4IMpt2+3!AK%IekGSIib3+O}SrI4RUQpoaSdwuGirw@@wm!7yhW$K;?)HOOz9U?A; z>_p{=Ox+WJx@M=TL&T9K*Ds1pWZE7Nv@Lg-Hbfd-ZvE;h8IJ?n4s@0_L>gUc!ljU< z_E@0oU`HuKgr$&~I!1g9PwZyUkP*_?jT)=tQ7JRNd{RHuK>C(?i^i+ zEV{JR-Uxf;x};-NA)->qO6`L@3aGlYQ&b_M=#o-<9+v}65A6_5h@=#9Qu`Z^1ezY! z8JZADWGNNYUdAJUqK9{cB18~fMg_HRaT!o_Stlq$1koj=_9z|>^gN;i^dNFl$Vcr* zJPhc0034I(CmY}7u(r9jQ2R+}0`3|%s6PvH`v<LgTjeHbtO5F!DA!H zUG}_%)66{cZCaBvD4Y(2fNh|EoR6S3qxkZk3^LTZ7p}(#SeiBM&{N}=9^JeB6F7$D z`n;F)(1f44sQM6&v_;Z59;ETa*4Gv5PEEh;IBL6g9(?&p{+AmImY%rq7!WF#pm)u0 zRzqC646r^KW3~CnmC=L>C*jSX`C(7VlAgB44N#>MHo_w53;{JyWz_6n_Uea|P7t)A z_^-#Y2XiV8C$IKyn}FkKK8{+`bN9oOtz21a^n@!t|HsNUsWc3WfCKUJETG}(IvUia zta@e=0hrv!e>pyBi8x&OopOfI_S=pnx$BE22`}-!cZ~~ zbUVkNCBE(#_Npo}wv4pu=;3b_@o0E5p74nfapQr&jb{ryyaNQ+sz4RI>3g}R)8IMb zx0`idof5B-s6?Yp7w>bV^Iv^QU_g0bK|a(pi64yd~lHAiNpPF-4l zwV`iBlwkQSU%_Z8D0_fy3!Xexwezimez92W;vk3W$CqmxvPB18qtyN)FNbAqx*Xf)3pvy1ZXERs! zDlj}N+CJyo2E(jKE?gZVbN6qcYge_)U5JsTvU+{bpIx>RzRhLCTrs%~(Fz~)VH1SR z$8$kTU(_}qqmCNro*XL$y5;+HfzJg41rxgvE%VtPw&1L^N!^MnPxd)-dG+hX*Fop6 zmSklyp}}W9sEmmi@)?>E5WM(3rJ0Qs;I_2Dx3_8!GS&(hu zJHZCN)c<~O_=`XMMQI3*q^M5)-o-TGWj#%3f+q**xa2G0$k7Dd{=}C@G~q~(=tOc^ zwv6uv%lryUT+r!LSH*Kf>KCP3f^E1q!V9aR6gzEeBAQdb!~6yG?3L~DmJm-_XDZ>_ z*~W6}_+T$+=&Rb~qP=LzK9}ub>wF}qu6Ft===-Z9l3L?&TwWBO$hXh8flIH+f=jxq zsLP``C#SB>VB2tB>+@=5#+0Z&u_AindRJUILW->+W2jM zSnYqj9%z4aSJMtfPVq4@Z`WZJJ2 z$QAJ#Q>yOd9JTIz5V-fQZs%TXX}Fa=q>j2~;vC?}yM2x{y!rw2C}s~`k11%JpaY6U}54OIa8U0Q|rPyB3!Vd-C_b1SsB`eI&i*Bmhhpi$t z?s(B;fIcE2&C(!I&!baNXMk7_>qoOgok>@Vzc zra6Njw}^HO10~-aj-$@0oC|#Yghix~va*0x9SgA@xldZgiosIPp02a>QygopQsEOT zchpPOMro#5u2m!bLFTuy&Kvo(k3c>B7_a7_>r_H5T?6Fw8TRFdSAn`McXm3d?#Z2k zb7+)JN1-Q~2AwbS**0m2r)jBL~(ERF0Uvtu!^Xdn9NCCf7s`J8k))# zZEyt4XNZQ$Bjl4$f-ZhRd|e*(83+l=aR7mInMtEFO*Je`>>y+lfb5GV$Ph59&V@;K zgzGfG^(6yb2o_n7!jgZ4Yct^ba(Y|{7L{8=;^_yW8V6KgNsS7DBJ(ONr$MO30M%F1 zqC%j^oD$_u2oswy{I!&r5F|REL}?7dGzyr$o(>a&MCOus=0S)?0MR#6Awq!YJQ9vK zLR17q-%NuD0U~oqB=!)VjezG{DexdTbp8mZ6yZ4)@O+z&2f-n8N25R21!!FF(2U2| z6*r3h+Tv1Wy!BhbC!w*($_=cmf&Y#`RAD=D6?;;xAkgiY_^v?U@54xTNGGD^FCCM{Hvb?ErkFEHJzF}D?T0cVch;LLvHrJBtFW^~w+Z-q zgsZ%`q+Y2Ghn+1_@v5+whcm`y-Sxq#z{Bs!oJ)}9nP4M-L`3L=6Tr5N?lH8Ojw6nv zTnXm_wjXnB3otQZp9_%%#u4IQ6ua*`#jo8$Fc{{8(G{+8=!jT6Q@fg@&UF?ILN?>LTT zDbdfdoP4CpP?yX4y^kFhzbanj0e7Iuxnc&B7Im*Ke`p)mDsA=A)Q$YnE>=@dPV?&a zC#y&iQ1aQD*LD8asiT zf3t=XflR?mk?@mcz5`JH-4;p&lFmty1e7tdJ-q+0gb_hZ!AFr8lre4tjQ_NQ5kaJL zQT_J66%hW*3PJ=h1rOCVi(3HUzil8y0I3`t76AnE5zhvE|FM7%!6Wl840aK|DZuw% zb9@LMnS0`LLFm|Y)pa*ybpp*cyt5=P2!W&XPFyJn9m`qWz!V(Q3hAz);Vi3VqkrtFD8*=;kVEXf1ylYW@mCucxhdNOrv!|&}nO&ubRYHJ+LhTq$F zm^MTj-ExG_7qZ;ghTl7MmNrBhU24geW+M2LWyUuA-l>z6A;Rbq6Hbmy z7u)cA=MK_^$VwqE5p>FQT>*3*(>b~jS#)WMfK{f7ZTLO5V^krcQpid;mNHdr!|z=> zMHM27E-AI=aXHX**ACHyNJ=3mwZFkO{NAlIG$E46QqpYry?aL}LIlxeq}jxFk4{j8 z2%<|!?NP7|zxV6_J&2qX@=^N{Y_r_@)u#uMLzj-)dte)W@3rdGAYxL;M(s1O?&y23 zHZ_PCx@6Rz!X-e>MG^~K*#-8j}AlzT^j1!ei^8Ez^YM!h_EV) zob5R}YHd zUS8@h+`6dxPY8e7rdy-feoH==x>zKHixbuhCGqNGTRNljS`i z0wYviaRSJ@5Jli`3J(Or=Vcgglg{^vkITAtH|Wpm=ife9T3Yj4fY}8WAF5108R|%j z%~KkP@Y>-0nvYPifi)MFMaX)w4)kI$f|b1_o89eQx(hnk`pZVr*x;v=Q|EHZAp4;R zKdtq?B>^W}Cmr%(hP+vtu6U|t@1|ZKa#pP(KUsr(blh|rmMQWfk;X(f0-KZaV2*sD zUOU+CTnXroGrlLBezomluSlnGL@-|z?g@FJsF~B>y6E_A&wm+dyNfN?q}yY4G;==C z^pHfF)E$T|4~*>!8riiXSh6RshE1v|u7m_LE?1l|^(=Lq8PVY3_Gi^NGrAIz z3^)@m*FchD_4J!qTcIUZ== z9Qis5M8@NvrqZoDyQeXYSgtn8^Hpya!d-~kYjbnV^GsF{l=2{RVo;F*O}P4>jE2Ty#G%VcQ@Mp91KmV1kR{dKNx=U2Bv7km1FsyRIVhpfFiojJXy zGm#bTzPAROr`EjA=(=gn;5yStp4_k#{w$lx4VoDPXSRuImFmU&#FZi2={;~`oMjU! za!aZAiEhTgltr8fCfSDRW*VJs4<~|2=cYQZ!)6R@v4#?XOu1GVP0=B6WX_3; z1aXe#M9wk9hM>{;Caw>Jjm;Q1*9;qiM&_EhG!Qa2W8gd^WC$3YXX2_r$k>d5^G%Q; zU}TPo3j*O{GX^d&z=dGZ`6aFegp17>aMR;Lu&CV9MMW2;Muk9;d8L~%P)dsmfg*D% z!Sb^i1JfxnAxLySCD?oRjy97H6M{tMQi7Eq0YtN@5FtQh9t|c~(0)MVwTH;Y6o!Nw zW&lvkwT;4f219}k$^nY`_D~q+|MOwuS&lH~AltjZ5F98~mOXc-wz$@-a@aGgwb~Iw zsX6`PSj$pleZJ+E)GFmhv$!ofHxDKyYB6| z%CH|?fZ5OC?wH8S^XRzw+iB@f#Ak0+}je_#1Sj)_srvj~sX0xMX_1b2)lU{#e^PC)2X5n=R{reRuD7 z#YW5O>i4UcE$ctUM77XtXujncUhIZW%jf z$8@r_(@Bls<*OT=(}{-b8ah+k!{G&8>L_>^5q3t4nQs;XPmHC6gZ0u>0^^NdRPg1-Bs zJ+hBj9$u83uTt_86Nx2J{R#VTBr-{&ZZCME^#0&uwinzfcvZN$bzwNL7{QmcG`1F^ zGYd@RjFd`Rl4}$UwYDvZM&`~#x*aV`9j?2+qK;@3!7GZnJtZ9Tk(B&)$SMnoB!{0> z9iwG6SGKk%ZYyaBZfNH+aX&=??KEwoKl=nF5!I-v;X`92+=SNKkt-S-+rxHkDV}}h zMry5TO)600Iw?f7-NzEbl!q552u9h%9?NXyBWrok7uRQ`=v+97D};}|URWP3k${hg zS~&^%h?RBi?Tbuf=Ux>J)pyT?uXZb+eC3n{QAJwjsutyS&0(3Dx~Q!KDH;=QZ8QnU zu6Z6ikr1(>;dX=@Y>2eSh}b|9!KQG_+}J$#Di#gaHAUvqK!bQ2n>yO(1?z2{6(Q0R zL00m$V?n|V{(CVD;u0$;yBJ*B3iFh$eP!Ef_sX`#P9M~0hcq_W*OM7?Dp4lZqhZbI z02{)M!NzE7vqv6{Od>6fO?4P>Ut@AfvATLS9_P~Y6w&Ow3yh}cM<-pg>clC51*3vq z09_`o%Ic!DZYN}AG}4^Nt14{t+_`725=BM&#gR~qo}wg~P&4uYIMYYq2%G+Q%IQiy=?Wmv$t*%`3ju!WhI#l&VbC=e4G&ZXHQc_{m zJ8GvT{SeV;HsA(tbqvScrM6GnhTjS8>fhX@(J+G!lc}^&VO(vTyVPzaHrnw`Ei9>( zG|2N5wst5Dhiq$$b77e3_+8!bU7{P#Ri(o-_tMr5=gQFz=PE@V5>!_g9ZF4ygzsGV z)jbpqsUaAE-du0AB$Xuntg$Ecur7JLhjq*sJ*LAAWQ!; z%)dP?{Tpch%8@pb)g z4=c;s!|HAI`ZxS@%bbcmEc>6IN8R}q`hWDm_P@0w{5mb=YxJ6KdrY*<&W&^@o4;c? zJPYza&B`@uBK&m*5dTe+W>b!x9h}hd`EBl8Go|dV2Xwlmq#oASVJAA<2DkG|?JB)K z-R*SU?s#YW(Cv=}+z!3FUN&jG(7DS^j0K#rgfn7E8oDH1Y-b$f#QWbemg{2lnl!v~ zdu^6~ypcVViz0ib?)p;a8B@NQGip}(&73i@%COxzqirs2TZ4^bMa(QU+GH~jH`A^p zvOVzLG5vq}V&FF`W-JaeBXidK{xd6P-7mq8NSTi8XkX~K{87#h(VWb@*^9@Gojr^7 zhw4~etT5|OrU6TsN-FofwO zx=n@Uz;JuFAtJ4HZISLnv^4HSGWPn+juKLDx1%uiEMs&VX6{lms@Opo4P$l?L^A45 z%+C0%+c3_6yW22k?B0C{r@QYqkTd%*VMe%HosK?lPxD9S=Z_uBUg+rjk&f=q$t+Fl zX^ma;Md{DlEbCC_&vJPU+Q3*Cwy!K}GoD|&7cORI6HX0fShY(kKAr8=H0Ja{n{o{> z$;vLwi?L$s1_FC#@N2ZJj24?X9>}#S=Q!!rxIr866jCm~Q+iZ$L~~tBq%qtcYY4L< z)DUh7EtxPhwxlh5!r`XH9-iC6Lh1>JmqkL+*7nxMSl;xa@%eeCWfxV|9G<(--ncp8 z@bP*1d86RRsJwB9=e9*#LoA`TMhn<#W{)To>xhyH#({es^-Yn`wD6Le)&=2~6AmBQ z7#deUx_*4!$neN<;nDSn56vA>9GF~CTUt|EQaE8~M@OU~53Slca#{6s%2k{axT3VU zyr3*lJv6r`O!$!BF?g!2v>frIVZ!X<@WRux7VA`QEhNbc|%qjQIc0QM(yhtG=S4zDT79p2K~ z)H=5{ceoi=M#F8b(bxo9TXS0sQ4RgNnh!?lV`%nHCQ)5Ht$p?k zR+w8Cwa;ESHZQ;6-x71C)gBF5d3m$>&k{fFDKXdxS#1sVU!y5?(YR^y`FTpk`h>EpY4$v!(}ZAuYhbo= z=)(1|SZmG7!Tek4WZ2qPcSc8;h1jed6(>&8nuf@7V|=o5l$H98X6y1Wsh-D9Mw!aj-x{Ce_FQM}X|Z%FmRTS1 zn<$_C z=^$B}{^MitBx^vDd=*Dw&gZv~qT9}qFB{t}?Pj}8k`5YKNW^Zi6hy=lovP=FZhr_8 z@K6fT)Rroxq1;t!?%l5BG=wm!ksBt#_Jg@2ZFBE*Awwex$sx|qb*i)EAbzW$a_~AX zK8yqp2SD_#TEg5uS5FqQw! z(4{{vn^O6IGWPI<-LZ!SMheQJ3x^c`KQoAu|4bhz#Q#)#I1f2V{@6Gpf7+C>hlDlu zuoaX&Yy)KvqoC|zJNO@$?~HHcYgx;k*1dE6-6G^9`C|CfzscBbuKfQ%$t`d1^{6`*9h z63hoL1|{1|K*{zpP_n%oOqK0?=(5YMh*E9ype|&qILg0~-}P=p%aN^?fl_4a+I@oi zUDt+LwptO?Ken6Gb@Xxe=tU$>xR}9@>N}KQdt|A`h4u(i1of%vb=^MJ?sfgWthzUK zVK@a$j73yJNdOs+cJ_t&t4}qyNRoj(VGWf}*w$a=!+Nk14_q4#cB2}i^Ku!^<7liOW*Q3k9 z({|dZCUFCayyGS~fl%TOF1ZPEYAb0(tRZQE315q5U{Ft}P__&#E4iX@3TmkG&I`K=g7ppFEh%X@v@$h9(GXE2}ANUG*F!(BXB={Flb$J6k0sJdi z1Fi#=@mpXs_&0DNxE?$YdMq(uK(#wq@?aBN;{gV$s4 zoVhrO6xCpHQjLTa=*nD(%TB<=qE)I6F+4WTH5X2#WSv3wo)dqiGm;DK+PL?Top}BM zD0{I96azj2r8^&k(w)tqbO$-di@+_Q?8N6_DflHQd$AR)1-}AkgWJH=Tg@! z6-V{IpWh2z>0Hv&LjMlC<7%Dkj!)|(lz+e0Ni>eu$!tlPuC~qAj+O9x#KkF~%w5-p zOm;!eRYE6{r-bN{?26~aZ|R^q#TOmwp2$)%V4QArknx?-!M#A~;1EzcxDO~D+z*rv z9tcVY4+2%ugF)%wP*6HJ44e%f3Q7kL14H1EpqO$r*a{v4UJMQgRet)X_%&cY_)~Bs zcpEqxWQ=5u0q+6Fg3_Dgz*JqF3|;--_WD3s%j2=@rHvkIr+b0@YFS&jckK zxe4%3VUGu8gH8aI^(0X8F90R~BJgOi7#syo24z;Kg5nu_5}o9rcx0C(2VLv;A-^B+ zOPx!&aSq^KCpm;u9)6S@lvo#Tm*rry&h+_Hed(%P;+=Rk(V>@8XJuaoW`X5k4p<3l zyjKOP9@Su~j@CezbBix~neJSRH)ru1pEA!<9EGXk*Eo(dk)KamEdhf^g;l zluG*h7Gc`7J!uB>I$5R%8N4-MzwRjSRNa|Qy;PnVU|(=1NHwfe!CY__cog_8a11yb zJP|w%6mL%lRTsu1UzWWA8)J;4Jf#OjE zC?18uT(A)okLH5n(L7K*ih$zLd{8`E0DfH^`Zn=W``oX?BYRn#M7nZ5HR_H@9}#y) zdelnY#3RNChDT?B;!zaL1=~UKCyK?_V9-T$q z#G|u8>Cri$c=T;B7mS1A(K1jxIu{g=mV@Had7yZ7J}CRrhH>A|>XUPa>1S%IN@rD+ z2dV;7I8kAa$1qT}Z>Cwkn^UKimYHZjCR&js-mK%xT2`GEKpwKCE3fl>D?IY{tkH$hg?}uGc`E5s-n!4z`dL4+@)0ZO$DPfwv)_q?v|C5 zCGzR(5UT@K(*spr_WfLP(bPa$ftN&omt0blNMe9PEUqXkC@J@9ob8ZHD>&j(Qc-Rl z=#(SJO+=?%#6%~eTlIm?{Xlh5L1lnJd7qqHZHZOadJ@is`T*2S>y+9+)v3Xf>R<^6 zYYIwB1I6&Y>Qw6xLfm5F6_%72bE~GdIyf0GXJ@Jc)fKf>MFCSL1?pk>0u@!1mj{Y! z2*>`tok+U>epR5jgo8UKz@binp8f!ZfhpuuF{8Y+qM*3Apr*hpOmBZMbSo*)(N0=@ z{DG3vDyk@}MAge{s#!s@OP1je?6826`$8V+gxtd)(wDa{sLQiVf6&@$rB{F^6c<%g zp31D(&N<5;sG0-~V-ZJn4JZBVF#Y^tqOTdzce;fIqC^PW7p@oytI!t!BfVaM}KFlrA}xThknWD3e-kr6;w6ouu~k2O=q7 z5I3Dc{vefA6*Uz_6{SU`1=ZCh#dOy;HwOCynFcQ%>(AZ0jSfz)36_kqhC8A6@`t8z zmP{@Q6nEyKs|b7hgWEaV4Z>@HZZU@VLl(=xs2DDP_wnBqE4Zm#rxsueF%ic&#oN~( zjwVxsS{9d7S5{P)sJR!^)Sxm<0`1CWSX8dCx~9rH+=;(`Qv6c*ge^7-TwYVcp*Yj< z#g{!4RVf$Lkf5ts2l%6x)Rs>xr@bY#MaD)A`#^s%yVrH(*uZ zWa{b#JYu^6;Y?X&jg{wcB+nm^rdeH5E&T{ORrhM-axmW?-WULBR8>W(m*U8z5S`S` zwHKCa?MC^-8>t3n)>M|#LzR_Oml;(WNMWU5!=zvosiLabYXzhI(JN~UOG~P!VqrYX z<+i#p{%}&#(t=Zy?UuT=pOOpHOdfr%p4SoMs9%eyqxD_|qn;zI!%xg{X$pN}7 zj)PVdN(PKnil(Zas!LLUG|LU3(N8c?8knBwXBD7_7eLhyn)a&%)HHNIJ^6lhdC6qD z$0@MGzTeZk&jD6CDp*AOEur7z2&-X~Qt6cl6)3DILT4*$E6WPX3#J6j0BBz)wccL1 zLQKi@l8UNoFQ-1|*ru!ZECKhas-W zyvptCg`6A+P++%d?&r}9rTz?kD{D=3Y_Q$wJWM`)9otj|zi5}$uK6|QTmjr6k_j-m zv|x%6ZLp@ou{ow3HxQ5|w314x#kAn$+R{=>jau|HLsxH7UCq$EoB@haR^97i?v)2- z1ge6JUc|#7?WLLmN}m-Z-2~wogw8?S9D3TRNImHhCet6*aD38^-pkypsj8)B_V~!2 zX&AAYVKOEF;h`<+W|d=a6D2THy>IDcEZP)xO!mkzSc93YsI4)>H3jZt0@s!srH3g6 zg%wpbM!ve6VV4ZKkW3+SJ~L!^h&vnzj7B6(IzFa1GMWeg^&qyax56+p^@k~_t(jV( z$&lfV0`y1@0Poec&}K@!ApMhrIQcN)sHZS+Hw z9O&+oGl=+UDr}WrSEJtNCzOgtL?1jQFb(r5t5FsxD`Y$^Q>WXsrNr%Gy7L-3P!mGq zc7=eii4fI+8X0ZdCg?64PP*%^G}waz^+O5;!xN$ChS2>|Ga}GU7@xRVQa+tk5oWIe zuZS=^ao_e%W-3Rc7c16~LYg(bpvqXnk|I;_dmvKoii8a)D>zwKqYPJn&TZD7vH93A zlb=UUv&k^RTS!sp9yXcjMO8^*ErpZ7bR*rqQNu9L^tz(;v}r|}gVW;8(8bhNH+wl5 zFx{Y)Rs|-rgj8N+&pUL#xBtFZtPCf~iZW9ywHgK9!zQ~-_ezkNOb=@QYm9&*Wu@Gl zTvaf|q$-tplmO`#eTO)pX!MoNqS8LxzK`49@)pd~j3Xf1m66lJI{xI=Xmef6e(jg{ zxB&+~GIEG#l~$Bb(T}buBj*_?vAVehZEZY$W}aZE;W;-)WmXeZ{PD4kjO|q({&Rv#P7HKM*&E+9frq<)Gnt`WbUoDYwpgPx1|S)x3klM@ z6_*A})RE-p=a0mGW|%cGUhFW}tcq1snuRyz^DqgfoK6()t0`2FF`&$6AtTdZpnQ5s z6{DRjZpNq@9h(euM$WS&ka`?W_1EB*{OpmlDeJ*RTNL8Cm0--2^?727A1NE+897sl zTItW+p8eAVrKe)-EJiIvtDzIhFd9!z&Wf(#-c>4oX+hN#nU9*l6wK)%gp|>#3b!@Y z@sv(cYjkQuw7jD^9F2sE!;QSis@=4bB?Kz1>`L$UB#HegbY(Q0XgcEhA0T#m97*EQ zED{|Fl-HIq>dMHONee733epm!!@uG#1)t2o*l3X};L4&}BVdKmQnm)f&Pq02Sw@b| z2_;ufY*6cgY0i)eBb$-aKz6ncB^sR5-qecMQ|wL~Wx;l@(JpL_G_*CEM*C)0K~0s^ zy6wg-6Z3LvIHbhx8;Ppm>i=kY_ES>Em~>5*{){DT&@MLmqT-(4b=syBs=VC_#Kbnr zw6HGN#M=msrfK++(ke!o0;!)@fq3q!rY_3cYrMMCpRuZC0%?(1O{cQDR+Bp#f%1qG zmF8~Dn$&Ueq*v_gAUeJLV3Qcl2@P+r3ICh^u`L(L9ui`7^bS&^Q0nmb8V%R zf}c;E(n?<>HS!ol^R%j_WWkaO{H9h~=c-G}DoNcnIVJ;*K8TYTUNBk8$SHPW6qN=F%4;iwQ>rTX%Q9h6pfnL*?2%q{ zl(x3aH9g9SZoE{hrhci=z3ETX*t<3oF@ls{Dn(=0P5&lMa14KqZ1O=|YZBmUTM-N> zY2iUxcC$TOtjCv9xhY$Gu_I)kh?Tw+VJfptp6@p7{SLv*BXK(AZ@(i&?3FI1p6QSU z(ZE+Mq|VHgrZddRF!NQZw2WgF!vkl z(%qk-F^A4jHNQ~y`lQ@GA7qUAaNnPvu!O@I`G$U8pLM-YPa8Ak(hJ@`vFH|^AZj!8 zuMY27+j>B3{VADazxe1E?+r6&gh{6%d*hS`GQNNEndSRlbVGDVlV#3UWT#y{F#Y8# zFaF)_TQ@ePUHpS}C@*Jf2%p{m^p8sF7A%RieXC+ZU1$>=GW4y-_g{I|V=o-=-7#Bd z{$;=O)^H}-(0|x+*)Qe~dG-3Mu4{Pmly}~n#(6bE|LZ4tbDq2TxN+xJ_INq-nQ6m$ zCqWOT|8&uxpJ}klk9@v%^27`8J!l>28~RT-9Mu1YUw-_v&rdjQOzBUya`@+VL*LZ? z;cwTpefrhvAAj)aK?fYU+OjqndcOr{_51zbj=K7y4Oc$>@r$eA!;x%&W~W_te*RBy zSa?2a)(By|D@%w8=m}A^O zZeG7&@b~+bjXLFw5v$&Ms6S_%dMW*jwq&ONDeKi?Q)eD^=U(4g8eoWL=<7b5@TcQO zPrhQ`!+&)5OZWY*9R3*kV-xyU?(x*+Z=5pjuctos?r&Fc{?E|Ab>hhOdtO~S?}fj; z**M_357^u-0O?j|kYrpZN zZ|KA4-ue2PthG7kWS_k4#No#;K|l9U`kVWHQkpUFrV}d1F8k%S9%r!+eukmH@b26QBEa&)16%y}sWAPyK`TW$3FnfAnH&amk|Q zera!?^jWVE<|10zJpN;v}8;#H3v}fAV zKXSI;(4V?>#J(Fg-raiXOBs!SUUJ<=&U+gASr0WY{^hFEw!Zv>RR=!v`_rH28CMP& zWv3O+dO7suX-_t7DW5fX`IzTvFYSi@zG~1wW?zhTeZ{sQH3V zBV~;PKWn&T&Irua-wgfR{jQo&@{8|Zed^!(UHMqflcY10g9X`XPd#z)UPphl{E5Yv z4?K0J-G z@1$SW*8gqY1CPB{a9Go`mUWY%_dE3Ntv^`$#`;e$`r!fFu6_SN+LxifwqIUo+^b*C z?0@mmOW%I=t1CETNE^#ed*s-0w>*AO$(Fab1vg#(+sDr3tc{@`nfI^SvEg+!3)WsS z;L}Z~-AVd}zWl`{_hk(n{`vac8{V3C@)Zj?b8YAshR6MM$mPq6Ezc`z!b} zK*U5_h9z4q>jC)TlS`R z-*0;2jJzLz^3Ju7TGlE|zP#*)x(f%sRoRGc z>X|C^{M^#JdW=5sj)N=PujxN`beUznZs^}T`R&S2{!ta4aOBeX{ZEX(jpJZB3jgHq zpS=8<(MSFLXO~{|Y1Q-_-(u=u=!f+<`oT<;RA;tn7k&`tJME z!3W;_>uIHjUGhWp*3f^^w&AzQS|NOdT%bH>z<=j!d z*SLq!TSFgt^!*1f`0W7&`=4|C*5|MN<^Hq_L%%E1k~VI_8MhAo-GEmQn>nwDc4z2w zhQEH-X^|x#{-y5)U%mS5ir;e<6rINIJy5=G!htte-*xkApFENGd@%!dLm%1m)!BU- z54(PI`t|o*ee3)i=z|SC`||zD_Wb8>@)thx{gHc}IQV1B`pnP|8Fk=~R$ZDi=InLP z+&yOIS?f7tI!Ni)*WLa^zc+uKUiW!)?eh1pzl`!5`gead;<=@t9kJr=2Y+|N^?iO( zMY}Wf$StAgYPVhXm!E$eT$?lH*}Eveq5tW>((?zrkoEJwEbRCExb;WZV>bpX{WIrs z#wUB;%Y6_1{!izA@y8f;$@bl9@ zJ?_ynZ#(f6&WjuRGmm8b{mkqC`pU=Od9L#0BcI+1|7m;KY2SHykAe5S|KrP!dFJg$ zp1OQ-A?X`>ePsQuUtGz!!q9Jc@6RX2_Y7>!`#5sR$+ds~r#X*q z&7$4wy%!DLywoP~vJAbdYMvFEFq_win0Lr%9M;a;G@Lj7a&&6N zTY`2cdi%oA?nG}1#}+NvRaZM;`(+%D%InyYs^b*p^cC{IH}xVdSU zV>h=i-i_ETq3Dvf*e+*|-tgkAU5@TBe$*}}5NU4S<+zl+EgWs!<@gOvbK7@0a(i1i zgwf!wS^t(acsu)U32|=24s2&P>f5w5ytu8dW!LrJ#|tex^Ie302V40l2P<5=oKk&V zJKr$a^-7^#9qqf(G-OeBr~JISFw(H=R)ylXH;1CTUVl2YmUb!CPWRtrIeOPE0kPFD z@3Op6@P>v3J2Yn9jv>N}L%U&1Lwwz1*G(zP(tX{#EqN#! z=Kt4h@S*O8?A?@>-LdxF81pqZw=ZFVf44L~8lKxdvv(k^2KF|(PoSIn)442Urn7LD z6OhH+jSkWoyN%rC{1?QUV{BaSR+DWH)$K+fwP^S9R~NS%b1u7w-1RA6Yn|P}Z>PO! z2XU8W(>{+4V0%Knz2uoM?qGDaBkkW|0lQ6rE^D_8KJUkFW(dE_EJA$U$L+TC?RC4} zQ_$+$c4utY+7#ZcaaN=?6x%`RyRExEL|4~R*R-TP(muPrwIdqhvZa-`*76F@T{j1e zcz3G@N1!ahbT89x>@nuFoo_wva{SoB){Y(YzTI-QeUbgumb^$yQ+Hiz_lYcNpS^oV z5jM2!pc>sUv7=={%c32uLv>q$kV?PHGH4Dh-sQNos@-Xn^*b?q?zZMlyoEcq>#Yav z-z}SDFQJXuW%j8z)Om~DNuaKsZzk??0xk8U^LIHi(y!}??fL?8TWgz^AjyANO@8jM zaD7|u2|%PRSJz{5kIp^a5TJ`-U$om7tDLcQqn`PbN_%f~49_=xYmdnmAn~0>+^k~m{ zv==>ECA(B?vXR?0jxWnv<@hqKdnugmW?8>=e3Z|lz39>M$%-vAQaQ`e3{lo9_=!Zwh^`J*v?a^NMXm5J7_dME%9xa3Ho%9@Erga%UZTs}GUUPg|);h9JXis~z=RDeakM^!dJByt&y|t!~^@QWgvYvK)nbvFyth>m~ z@nu@)dbA5X+Rr`Otsd<@kM@8^TkFxD@@VTk+Io)`XP->(`RHRk?f9~+=Nw4f=MtyzAUTQ@nu?j z65OWk?f5dSX&$Y@qqTXom`96ywDUaLRUYjcj}|8bwrs@%#|IA_U#3;YE#1wsPH}wb zi${xkv~xV#xgPB*k9Lhm%Q!%fqbj!=$CqWzbbOiCiyrM2k2Z|p9AO|vo8!x}Vvdg( z9_PAdd=}=T9de?yU5bf>H!j~eWNqMG=+@f67Qw}V&6O9IZ9V1U+D%m#2R2r& zEXzK{++Y6Kpyg-xwPJ@aKYODUJ9xgevUYRT%D|>de1u8GD2zmx>s>)y&({$~2}&(k^%SXtZG+>D!e z=_cNwwP}jDVeHDE#GGYUh?Gs0(3{q}qIOGC_3ZlXzc!$E7m}Y|ir7uIA9+-d%q7yW2XBarqq^>K17|O?hQt{fa`0qZ|_(H^53E>}%?;pa}2cgTv` z^~=v*Z_2yglz08kl(*KDxAfvb_KLtpG*)JJ`6E5i^^Getx-0yCGZ6Tw4wbG2WlNe*G_sCdVzjjTihOXGO z+4$^mjh=5GX0i6&Bk$?TSwuu zQyGKLPGu%OCWYLs$7iR~gwHO^LVR{AaeQ_v-^FLA@_l@ED)-}K%1A1Y;ImVC8lRoY z%lPb6*5R{L`6oU*mCg9lYNfcS8O7u99@`+IH^eB$D)F>-SJ3Xzz z$u$Afi4kNGeDtVbr$-Ni!ANskFlat#6`suL)PhN)#<`)p`mUCfP`&RHPHr0d>i1Mm zT{VR#@!4HF;btCZY7Mywre@#W7noBEHp5r2lxLcpGNnA6>Xd-5jhFHj*MOdzo0RXC ztBR*(RozLWAlbZ0eKggHKO@RVHdBJ8Je%u;tPaN%uCg_vW#dUB$GRzZdUVyvG3CAD zK5Ei~t`0r*i7hABMn0MAW@Jul_?`)qx6`{(yCU*J(5}fysEahlj+tSN7(F)E@0>5X zjv0HbpPHNNe$jR8s8J*BJNlw)AM5IezbL&7Gk%DpsD9fh((m~3cI0H&#TQ+t(mi}c zxC!d`a4bt$lk`Q``u281aQ@H;I=Q%&y*jU`Eea{>M~bu>OV$;w}y7flX$1ouBB z+=1$%aT+TSZj#?Ni_V)Ut#b*}Q(YELtu)u_`b)CMIAKgc{-_@C?0>+QWOw%4u!m6n zQ~q7whE06ddUw7Id&M_jhE04>_M0!me)DBmK1H3|?KfrpUxwx5uy!;2w|)}V`ULAY z%r%3ctgGK0Y{qf6HT{qqwfsh=yf0jF2xjIo$Cw#77gm}^@YC&2Yco+W@9z;k)zM%0 z-i4m;yRCE=^HbVx8JTg!bE1i1923l zH#j`G4$h~o&DTUtMf_J>K>$agPHy)^rL+Mypz zJ(NH7jB9p%D5#$AFz_hwaPU|VT6_}796eqF9t}2t$AFFCaPSN;4?GJT0cxT$5?lo` z3yI$djs|ZB$AI^Pq#a)a9tXY#jsxESnd`*=0ZsrlKR6ytr~J%h;^Gx~b>hFvpPq!5 zOVyz{(2hyrzv4))8W4=|@!t$5cc4D{teSKo#*dMi$8*0fDgDL#{JM0Z>H_UMpz>YO zMO`EVIjsQ5rPk$#(1xefMRAlava?3|>JqZY=-sykeL6&y(Mvp>k0MK}lz#_5#>ma> z%+#~YS8YUbzAQIBM@tiOhm)mgQPMl)=sA^3Jdj+_7vq>T8y@KU7lWbb`xh#=zJKuv zILw5y|A_FP1|~m8;^27h=O`KQGL1`fIa7q82N}owit%g^%$$%+ZYVK1iW@ z=Q~7!%8)Ai@zhV{(swCTtcjp(!`|rhV5?t_cEfGAG>A?$x6dV+&hIwUJJY&⋙T~ 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

mG2D&${8XF=cK2x_o*;-#@3ZZ88lD?3&9sI|uW~ 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

LdEQ81=y!vDaK5ugyW{2PoUvupgGLhphu`iP*rV z?xBG#GE(Y?Hf@seVb?`N*RXM^S(qqSvEr)A-l+(cXH!N2BAx0jI zFO;HzK&;JXoclZ)jAiJF*le!x)p);`o6K%cM|@MUounmzy`*kQ9>x$ZmdDsu^h;5m zl0|58Z~kLEL6yWsDben{55IE8Z5*=iq7Kd{7S zky4PmI$Q0-d(TY?uJl_|DqrcBrWCI9J5vfb!7EczUg;;MRKDT|rdaoh9+x8S!VgO+ zo)bPRrDb=aSEX3Sc`r)oeCItVrQsKSPfF8W_&F(6_lX{pV!bAQNJ{0M@EIvx{)JzW zQamp7h7{{?nSM0h_r{ccacmjR;^P}!Ig9@j=r=x$@RU%U!7l)xdR{u};AVyM4+ zYcFs8W<2{pP~HjrtwiAX3hX7Yu1?W|0s84&(aBN|)DRrmmbdc9W3?E-Jt zO5Tz$(CU7f;8j`4SNcg=RVLm|FL-ViueaifM1?!|zY1~jbPJw^_y!SP zIBRXh+evt`Bc8zno3yd2kCa*o4L)0H<#UR7w1+tJ%%0$qc;^>SLJLyoHMURi^>{Rl z&)2p_<9Ip~FEgs|Qj8508iPgwLSg&NR|mY7Wyt(A#wMO$7GD#UXU$TkO~ytFt$sZg zMfwO;+l{>xI$yayLXnZNp+cA8>yYYg@`iX~gDKP4QlY`KNJ`dtYy}SnQI^Jz3SQp5 zjx>hX;mJ&S5?0m6*ixb41jOgLJR+%!v8Rep7!Sdkr|UdImS^m%&`IB3Ed-NU;7jGYx4g*H7bbvCxvl;h(dcw=h?ZywmyGBWZt z_Ez)2d$uS-k56M~1*e|8a~mg+pRu_@tIEK;rudkSj~B}uWUAe>wQUwUJRff(OA{)t7;I#1QXi>HfIVPZ!Zo-FfOEGQY}CqeeCdq163qKQ0+wZ>ypC*ZJ}C zHew@Qx%KSEHGaJEr;>Pu)B02M{P>1=d~Jje52|m_sF&9k;$sPXL5cTn@X8?{bZv0) zD0HJ~>-<7m#VeDL_k}?vZN07(4W7%!+k>rZTlq${>htR-q*IMBWxj1fx}?ij#|_V)5byER;c|!Zbl6R3G zmr@Tj<5O0VX|dcF`)OfSQhYJ8)jT@tbrbvZWa~K+%uoe!4`a9s^2YsI(a*rkCV%T(P*TiSy@2iCSkJVf!jiJuV`;Apyjjjcv*9T`D2xz zcIArth`dhCDL*ChD8NUb%0)hu1Y6>sHBwSM~7n zrkanY$hvN~U3$cg4LH`%OqbE971T;30@9xni9-WQ-ayynVEV6KN z>@6HhPGx+7G>g?kI?`a|R4y?1EPCBnA;0M`D1U=v0pU!k+iy`0>;jm`%Zz3y=-Pz|@z|lv2m%LC0UNF#V;UUCv@|!MX|tx}k;3er+qt9E0aG@9a=G zM4XT{9&K>p?<8IEuCvgs#wfE>7tjtrE=AAU;Lsk8TQ4CktY-M|xI9sA#>pg)2G86# zV0oIzBx2##aI?}XrSFDMJz@jvBJrg1!>epwh>Y={Y-}yuxp+F>VAnYTOG678jY-Sh zEPkxzf=}8o#nPBrs2)vJ{Tj45Q+f4pw|kEch-tmAwsdBwa=j91menz)G`6G0(pX+x zXPGda&`h;7Fh+QH+b0UqvuPG@8d}(v=@#FT#@#X*%ri7gSrZV?YEhZK4O#kBxXI1Z z`A^4{nn-B&b;eB9u-5RHX=$3>H0Q=FCL07wqpr-Dm{JfiYxLHpmst9A zxV|1sr21rhJ;Q-ombDfy3qPsHEDJMzt;GvH%_0HGq1KXNp^?A7v_xP)3U8!x^B#d=Vzoi~mw{vp|q_GuzoSk#@ zEx6?UyVi%3hpn^jJ&A}4ac1qjQ|>5S8vaZ+-jtQ)lbSL_Ruvkr!*qD>TZj9!9jPqB zbNVnkG)dzSVnHvdSj}V$L+3#=xkh83R2e?uRy)WHpMb_e@l#p!2cCtudOAhp-~g(? zv*s7{;CfKIjUsi8ulDdNUp9_F16*~ev>Mk+E>fmYDBCgB%O{4#)PI@}jzK3prfZn+ zXh9Gtp4`wBk2V@#B;@7Mb)ceVl-Y|nHNhZ@EIHR7S2*%)3akE9U>LzE2mkv;{cMJcNqd7+9PvFB67Bdw8ieK_T^oHwyo z)84z455=n680gROY4fT0>p>;Vx`f{<;9Jjbep&WGJO8c2JJuLn8_Zmd->n%uuB`M4 zzGgZbQSlb|nMkV`N+r`tm7XMN73-MHbi)Sew<@M(geYDC{;tO~r+H5iym4C<4PGBY zeUeGDKB<;Ge1}}&Yxo=9Yb5N&a;Fkz!mN5cO(P78mPpL=8$*OeR9tC>UhsNKvl2^5Hmcq%IQ{pZaoL8UA6yExMv-x{nJYxK_%lX?pY_H3|g0KWc zqkqrgZ%#YmWHPM#W-eh33czx&^FaLVNG6tw*zlJbQT{LpKKf;8;RM+d@_56*3+;B|FYEZx9NjNR0ZH*oc zCOAEz>UO(^-or>6nh0k(MfA;tH#A9EEt2M*g=%+%zY+N4yaslJ{>~ca*}zD*(3cN8!+^jhOEgpRln0}1cO7M*|A+|#QTzneY zvV~&~&jt>Z$QDf}YK(*YS+qGr?LBw3$}%{?hSmxE}juTF-HZ zAnOCa1w88GaRZ-H496hivR*2IWy4+QW8U4zwI%}ySyZnvnvFEzn&n6jzF+L_&MsN9 zWU1=(iLlTDj2HIbrQpGN=@VdT&MI*|THJr?lM3g|$9!{FtT|c_Q8c&-k(jJq%(zBB z#*6T9x#O@~T;aIcChWc&n|u*kH7+i~FWkBT@AG+ai_6h2%$dy?@!=@u=d9ZTvmeD? zx1Bso;FMh6#5~%2-~9;g>G$m^-z!j$Irxhprf23+ejnK0-@beqbm3)Bo(&L6DvgDd zPc98vgg_g#9l#i9$i`9)SZ{zz+YrJufa3?_05stO8t6Wj7isLog0;4j(0i1Zuq84t zbQ^RV$lTIFhrutgUR6WcKIpE%{Plp|vRsLWaBYqAqN1Z$seT|!jJtJK_y$0GL^)jz zIwaH%C*;fT8GZL~ zNqqHdKEAlu>C9L3`8&tS^mlQQf$@fDX}CTWk7l?7n~aDK7U5z1VHUWc!KhZYt1y2i zjW8+Vu14nNh5TXou+hh;Y{b~Gg8VwFsAOJQm=~LbZmWO2HK`Eag!xjUK&oF0__oA# z+^?!Ik6Fe_TLQ(nv|2YzIUg>|I&pcmZ3`CCD3sQ_>OvfL?!ETc6yj10*}7u0m3*ca z;_11-?P!V{`A#c=r^TNDulr9n8O63wFU(IlW&P`@B77s(KeC=h_e=gzVSb*D5LwPB zgsXOGSb!H0_Q1Hj{}lz~os_iya#{h*PL^Py|^+Py+O%sA^uFj}#J z!u1@MnOOgE{9=B_z7ZyVcp7S~VGl|T%?b0sM#z>mPI>4&*q^#c9tjpi!wsIF{d)3b zabCntqLNX>h>{qou2)XcpY3^LaSK=Pt%X1##%lLm$>b|9Hn7eUPQ-$BSfE zHvb|-oCn^-UgLIL-POUH1UZ*1L!Fl6@AvR&%y)o%6GnYH?#(AgZ}_H*ybc0gHa<{E zA67mqbhN4+juhuIJQad)24b-s^x9-UgRIlPCIx`℘cMl*b56ves6@gS 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�O1as6}FQSiQ*kewG;<4D5SCa!GUdHYhU5pfY3xL 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%0A#f6#d;AL}Uwq zK5@a&1IX(w?AQ87_Vjc0Fa7v)l=(a!T2H&rz87cIThQuHPKB4~{D?bb$vRo1Z{m%euAn#fqC@w>9h%I`UG#1jy{c>N<|;}EWy1j&QAQz0*CNmUtSjh;=X=-;OAFszT%iFCpRIa;-)qrq;Qhj1JdnJWe$k6NNx5<psFMqNVCCPY<25n~fam7T;Qj?gl>IUGYPcYd}q zPDwY}5{^nU$qtUDTeiorjyho?ALBb*Y5P&tc8@Y7!!T~3X+M=GaZdOs=7a&e{bK9Q zSfA6pA~3gUIo)o7yDY|;HVd2!t-5M`J_Z|fv>|6RIpw{%>wH|*n+T%D%GB8aOns^D ziv6`1JpR)RbLMEw;w9MQ(={Pl%wna$1Wop?1eeL`Jg5S90EP%CYk!7!AoOAk3rbE)6o0CKuS@C9Ax!o()oC+5coC)6y;Eu8WxG;p;nnm`s)Sd^CFuoD%vE~r>pZx zs!mtOP1dHX@=L8tSH(}INtg9ZqD5E6>SPtVD!)Vpy3At=<++kqf!2Zyozu!tN(4HH z@fwU)PM{SThMKTBK|49uVX7AXIHmc+t!vWe3m4Gv!yB3({ugVu#r9n1=#5OU(<^HV zOp8+1X`}@!I>^qNqLHulssgS2{Ohf}tHJwzs`ly_>ecVp{(v(72hRX1VfH0AA>7s7 z)5kBl?z87VSl9}}uEQ4f9TL`?ZIOmBlnSc;F!t;e4=Y=C^k<4?uH~}l%M$-8@n_Qy z8$!g%p@!`5M6E|0d%T0Km3NJTdV@8c>7pOS7W5e*d3`3R}-1Aht$Rx%uWLVUssy3d_ zu+dwp>vjQQFydzNxRBx204DdAmVoY?MTAu=0Q0?wVZQT+7J0C^{eJsm!t0x0WKi|# zB`PdBmYL3NRgK}x8IStA%fCYMHb7PHO2Vj(l25gr0KX+$RtS`oVg~g5_Ff{1Iann=~QtO0M&gvL`?<`WuCVU|zgliB2Bd4GjHKFMcB#`rY_-e8xJ_VnZ zXrT|nhueKI3fS0SZ9w0f_xxu;f1?U_k^*rxNu^LP4(>o5*{=}#vVQppGBx+pxKB;& zKXr}NI`tvfoR*;1UupE$;~V`r1HJ#M&C}qT{+}|xK*JWCXXh+1=NTDj7v|Dr+J1#H z$>S7V-ojmo!L2)R=%>|ylD^bBoQ0!z_Gj zH7?-*OUn_$G=RJdo(E3Ag9ARN1@#)qTJs@z9OX6HB{D7e7NZa= zV*otLa^*~f`)ep-l=VxFqB*k^)&7Ri20)oan$QFQ_t(69XJiS#VbN=j-~hg*`l7xo zXH8+|k?lx`hoHuV4w{gMZgs{hON@9ij4=cw8-Z{e)ULzahM7l{Nk%(fD|;6!l3K2K z%uH${9f~%Y-nzlcQm{cZxZ8C1q+N%(O-!dK`g`JNDpKm3d0ZLHRnF^LJX!VTTVE(idcS{v0YSAE^TmZ6e)hpF!8ua&2edD z;T$zCjXroYEOpqa1NFvpTwXm#ePi_!<^lbUmD~-ZejUvB1AW~C@;#RMevIEP8C@M_ z4-p40^g!dntYzOr=J$Z|(IxuMjC+1th&#vj8scXA-Jc$ckRfp41vMeo=$`JO*jv)4{S+Uj%@ywiB-*We@&VQto8+4a0#fs zW?fwi2D#1y@3UrHE(}h=Ao1iptnstcWwNdjMpm(eXlMh^Yy?l3cV7$9*V80cyU%Hm zDAV7U*~icMR`!nU^5{@vdmPp0h7iWx6oL(u65I z0j^}lTj+1KKGJ&%8o#&<&qFIMYlqzy%0`b-W!+~soEDV@mS|3yZB8_$OqiOdCC|E= z2I~}MwRtCSIm%Cv)#Zxu6QQc@T)$j_G?dlXLROn^q4*85Ucd0;l=2Ar*6fECCtFXO z4+EjAz^uFLlHsX+leN{R5AT+!r8c*OFeus7B&S)5ChFS)cf8ABv(4v;d8m`o2G9j; zC2P5*F1jQ!k>Z)nCdWIpq7iA*>H}9m!H$vb<7XYKcet92fgt^9*~ai-=v1FoU<1=& zWTq4EwZNx%-N{m0-!nXtV0zEYl`ec`cu(-bD;ghX#VuhN`c&ikw;2ZRuA5o|v;3oW zyexrOYss(RN|R2(%^d`@hbsYnFy=Lqec-3V4jpM{igYaTTh<*mFEkDA?j8<9|3DM9 z5KupdqJ<4_7#uZGs@=FlVA9kLbWmMRx5zErAu#Yz$DZE)G3dZxUM_gufP4kW^G9d= zl#x%QX`=p$hU{pi7S{cOdKe{-M9X9^Ktod0ds7Y>VAc)?IS#NQ7#MWc4*U)qYY#3x zW;CwIGvBc3)W-LH5jiB$V*qo2z+k+URjG$%E&BzR z)1$mi*ZD&J3%t5fF7yg*A@>CaP7k!|^f?+9Zor|FhWSkSU=pt1a8*Rc;A_K6bBRb4k&rDrs)6RLQH|Wzj1bt5?pDAQA46ae{ zsd+!FhpgLLr_F1wI5E~~#-aya9Y%iacO!%AWNbO6+?3FD(wKgy$v4V|1CR}D*Q>f+ z)a#(-L2KAHA!^E|9Z9#j&q!kf41)5G1K3CSF2wR7oPf!}4L(&haDz-8Xn2oxIEnWj z>H3|4oa^9VeSI*(ucumZ+9_qQPB`Ca#4^i?t0=Fk!*OtPxDK*kjXj)Ycya3LBlUGv zErAyG-T-H4-gxXDVX}*ciCgQ|^PpR`wIC4>*2}R2fIPrk!6v*~Y18F_XD8JelS%bW zHNmRzdNCt!>fT}wjByaMp%I~SBSRohym2A}a0cUs*WsHbfwK*`lYdYBr&+2qSesB?ZA7JM*%;9ENKc3l);e*%ggCsXs;d^0&n9nayR;!9{p_KY zg3BFY1!up5h6=9CyEcRZ4d4|u7rSYq&A*y>m{MObPblwUMgYGwxoymUIsTPbQ4h4RX z)r7GzrQtytR#RbMl%XuHJ)4mi=gZFr9Qitxj2c4!8CjM?nV2AljkXWwZ`PsLCc)Dh zDMY>)U1*dwMOxOIb?_yUR&)!%ESfUuXYx&6zS_*0I!+s@CmeqcB{CwUd$=>jsBA zySr>C`kwE+joj}>dm-aZv}Z%;1{&Gl1AOk|zKJ!Qq0bokK`k*n- z$~hABgv!~{x;5=J$*p?9(iu#DZEfE*GCBr5H|@JR%T|c~MM+n^roBlUYNHxGW2i0E z+c`WqGT1Zf-`G1c*3sv0mBjwCyi{^Gin6`3jy z=H65#`#VPZVJXgEeDk&b;(@`w!EJ;7;!PEJHW&Mg8@urAg{KAv$Sca>-i-N-*2n`* zbqGbOTkul75t?3Ws^LO9VJ%&at0N{(=4*(UBvGzpn*uEjI3a6gs!&xm-1Yq^G*pA) z*S8j1f70#s7xxUU8G@F+-jQz9xO0uR5i9U1u&l{(p$In05p1G~9l-xlD;z%& zJ>iS)_gQ1PkNoBA*|W!ff+FKVUo3bg9y$|!tSc6ph=NAZeVeV(rHDFQxfu|_Z*FUeW2J(m z%|{7~K9LulI6IaVee&$_7D=So<&7&T8-YGg7Ex(E`NZt>dNr2beGE1r@ssT@A=& z1DM-wM9>5(o)LkV>S~n=jaXZ?C_nmj)FU36i0;j_#%6;GY=3Q0ESKJNL}UaqQO44$ zqFC^x#4TDHIvER{j)zaL4HxXn7Gj)^hfafpc`Yh+M(Cv7FU+SZGb0F;i5T-b4SI&o zWHkHc1@hpDHTz=lg!3}Or(@wfWVbYUIumRWJ=_yFmbf3ObBc07X2 zqx;aq#0{Ql(!5~fR-w#zxFFV?306Qa$I$Hs$%;pErz7m-8S&r=yX(>Wy8nIeVgHlA zb(4Lj;JjFH;&7055mB89B>k?Wa{dVappAJZMP{;$kV|y`gf*5Q-G9a!opm^P8jU@B zJew2*;Xz99qtE8Y0^vj-c>h?wuna~YT00@55B)UZ8hscLU`4_Gjp=v{uM%J#u2RDb zX=~e><4sNI%n4IZ8D5g?^ClTa*a&))^atZe|Hhk(Vg>Yq&Zjdrkm^gpOQDm}4=2|) zFB+*NVQP!w;gjzU=G~Q92*!ywXGR}SL$X*?CJ~!`3@|ax!-<1c zq}lOXqWkl#w`b#T<{cWe0gM*iBO)nu<}ePNNDm5=wx;-oCUAr^ply+KE_>X~%#xtp zQ#D}{B~K3rCzz{Stp16m7_q8rYlP^pR1HK~_npJG-EV66J0`--fw3)P&3SUb5)V!F5z+h-FC^Kx_M=vAs=am#6O(+&(QpP5jF#!FZP>4_T;mIYot4}inLlMJCD zQ7Akdy?`<>|4uH|CQCOT0qIzi+CbEgqFyytWTqb$|yfojYuU$tF z==56PnhN@ykHSi7Ls ze;He-digI2#T>tky%xe`Re<$s{=qcJAZaUwq3Rgbo6>&^P5;Rxi**wgn4qHFgKB}v zk-@zLH?bOz+dqc1_8TpQN>fS;L%vbd~@ODt==-Oc3ZuBI` zw^hJ{(cn%Lhw}<36#pXrt`Ofd z_zQ*0fUQMiVQ&}L*pP1v?LKs1>XXK9%$5ZP=4G?0@0ATyn|8@zi4YvaR{HuLwR> z`{g#Q2EH=EyTyim8$Q*x|AtSMdoI5BQ{}e7w@Au(9=^*Y?eF2kOH7pZC-_tum-tNV z4e+VDtb-5l$${4lpTau;U!K4|3g0#G&9@$cPo;Rm_B{z40Q7+s4e8y65P>koLCyZIqI&+on90sI%-Q*iIZ zQzdG|9WYE4X)euzhf?XHLsBUseX}0r98S72X-{;mu@u{ zzJVxmuKBSJ3-PcXrag6*SUtCHg3G$WhRHblmj-HcV1hyUW?Svrmuvkqe5B26>(kno zYdxW3XIoEdA1*D*&O9ER-^5XFRvCKYj{BldrN^5xTWr~jr3qxq8EZdw8?pqW*f|54 zu2&7`>x}2iAiEHuS3Ts5YIs7T|q=#j)Em4wewq@55Qv zINSIDTn?HC;j+CShs%mmNT?2{Pjxtbxx)Sm_D7AEYZX9@D%gDO%e5-0k+h_@>%Lnv zF@2HEDto$dl2lrHFPKU}O1fxS1c&SRA)%F#b}PM}Ur85FqKaAxOvjUvR#SyRnGC0m zK(cd2+R0uI0s{9h#H%^|vW+QS16ut1HUN7!n*yL#SBX3t8b$gj~BM z0kV8Kd%>O0s+G6dkP=!oD(W8q0C&w;pVJUM*TJ{!!y5vGqRuWH_Ett32Q4Yp)$-u& ziXLwIKz=hH{H2e-Y{}c54_PxKjXXhW{;Kr-(aHHh;sU1@1(|$&k`KVr9=h3mb^HV!Gq-*uB98*B*kiD-qwhtSo`Cqp0{yrp0R2SR1S zC&7LS!kpWXj}e3E7Iz1cDJQT2y309v&VXMk$hy zTtL=-t$Zb-505KXS;mWR5Gt43A-PrR3adAMm1X5@w5=0ZhvlM-_M3`r+XrpPBg|iX zoysR#h?Q3>33ipCZV^`E+Ah-UG8yR>s*5*JnSFZH?SCn15YL!IYmRp~eW!<}T=jK+LGRD~`o80*6{R;5`VK{9OO__wK``Y=1R|GG3?-Pg=Ng%QGLTIp6bl zHzX2g8Pkr(;a`@pHewp$@YNeNeXC!Zsv*_@a|@Vbk{=dE`FdeQ?c_bE5!NqiRYcQ4 zTgQ4N%!zgk5AO%&A)bprh6g0}qz-Kx9L17ucH#d=+nd1GRaN`rJ42h0q-|1CXrYu# z2~g-jI#SA%>9!4IYKGEc;gTk48)%x4fkG9$SU_sT2R?lId?-8>^*vGX{lJHcS_G^E z0^;z{hl(>$#1^ZT2ipJlyY^mZy5}Yl_}@>{wa?mX?P2Y;*WPEJbJpUH=y()o!$h$H z9!)cB5v)ZYtQ$8(+z;IiEz}?Ta1AaN1(4oez?1$I;FW;)0d5C;7_blUn}9n2 zp8!Oe>Hh&70(=f|81Mza5kPtoz8df-$bTo`(SWEkO|956BpU^ z^H<1=>L+=qpPvAvr+52Y~f)KBW~^UycuL*F9$nq5Dw zesAFhzPOAkP1DhXcm~|ib0@&xcC_BtUmlFa32-XlB(!lFU@>4R;BkN$d(qc&!1Hm9S60%{aoUwMbkH0N z2;DL>0iiQy7U0c*n7irs0iFQ(e!w|^{|^c`bAW8m=K(2u*hi85{{y7#9{{WZd=QXp#+Lv&_r46+5BL>8t`T1cybf?L;7x#! z0CG$o1^gGl#{lmIguPAg1>6Vt4B)o_X$v9S^oxMs1Edv!Jx-UPt!R6?9PkH#6vPh! z*|#47VjVI+2ISm>-A=>4n`Z!Fx6MxhZvgyXKdvAsR_CK)uIKw=Kh~Qz5a;3^sYba zu6H9|j$s~X zd3_LnoAI|WV*AKL8uno?J19T9C+SMb2r4oH@h#|hqI9rEWGxy zc?mEDcUd$I++}fB&uKG){B4~$ETqnI<4>LCa!QRn6>0wXB{Q!%?)=@1j`8|(xxzys zP2|(Uio&-pJn+v!O@MJ*N zUjfK6vHudgej4CzTtjEYuAdG_8J+Jt{J_vQa3FZY#etyQz1yqcDq9Vr3-E^@S8Kgdvo~>EV^^U?S4p0(zylZwx7^x$ zG|MjkvoBG5upDw?|IPxO26#3gWRH7dlZGteIUM&sfae0TDX_<~*Et`s1=ql(Hv*!m zY4)iGFb#-9iuC6JR|DP;h_OsR0=O3N3BU^hDN{ZaiH;K=7IKV&Sz%0Mer*Eeo)xQ0nsg~ZjDfiv@DjjI zz%IbefJ1;tr#V-<0pAPQ19%tU7QjydZUg*(fL8+U1>6q!J-|M|p91ax{0(3~;LCsm zfCXsVRe;9=4g#JAh`QunWf-sy*U+7G1K=*e4#2kqZUIDF(mMdJ1H}C;zV0;X>jC!w zei86JfY{@iQ9$mO(B?GuWad^t?6u%!+oXRD2wRl?1K=Hie+B#iAf}4Jnw8E6yb}=j zQ3k7S8uvx!qkzi+(f4!};N5^&^Y~~k-46J1z{>zX0Z5&@2QaF~%TZ4$WRQ*bjddqW=1N1i);C8WpQJv=`aO=h7nzpN_(jROSj47+bgwqa$-&~$$-d_GVI+eKZY zEsw z;Ew=L0sJxGnSeh5q@1C*8DsYn$|=NOwy_&QUUaP>59PtOJQNzcEw~-qCPT+EV}7wi z$D!fSd253m8nNq?gZ@}A$L47KK_BJ!8}x~7`7PiyK(r}+Cg6*JRe<{e*8+l9)>p_a z4cmb?{;gd&2>4E1zXEt8;GY0*13UzXIb{9<_%Xo00zwbWVL*(dc@^+cz}EnO2lzT5 zsA?SidKPX{~-a1LM*;KhKrXH0hkP5~SOgkH*-;Wo|HJNMT~5Bs@jmT7#$`mm?Jjrt@b}${4S(T%5@`P< zGsbuC8Sw>L1`@go!zZZf3hV@+o)E5Z*ftmOj$I^2#97#Jjw>z}-t-`g^ChOWWQmcd zwM5*FaV%IlzSi_Tj?H#e!)-t)gk4>0_3CzPd2M&b2&zX}v(%{1vf~{qVitr7PS(}8 zi&~H=AXHT^+GNquZbe1t1ORwvb|8 za!!8AB5 z#0fu&hE9jE9iCIRECg$ZUx@W8;G%KRvXKI7g-_9zY?r6dhP5zv?2sE2!!M<&@G=_; zLc+y>IiWBlwAm~aD}-MqBK{^@;n9+|ixC5fIbS_jZF&M-|dkH)5^VsC- zYWN$jgUjWDvLAs9$8^ngNq8c(?u8T`i5|rjpVS!vq*ysKf)S+H8{%T4NU=A}%oaw9 z=92m0P*RjSv1135(#A)^Nl~B39E~WY?Tn2o#g&LmS;I)hnKgc`Fo$Ay zv-_mbD7HcYf1$0_@U+>0+a{Z>L2M=43*fD}@gcl5H$I4WscX9LQeB&(L2RY24ll4b z6_tGr`&`#bG@7k4*@)lVxRNK}lby=R4r^FjVL%vg&J*G_jIAxm4+YK{!F&y2EBP7W zz-et*VaUn5B12x@sqZXLL*7bx!O-Dc4oRT#ZhZp!N0I#$UcLN8snylpbq1e zPy^lyAp?q^=1R~gw~`STQC$14p>Az+q9Mh#UUfFFQq|zM!W9TIt_rHbZzW#?AWNWe zm6L|Q6^dY}ac!8!z7>LuSmP>9je;vw5|!1DHcs2h!3%nqr@H(NIIMvokKml-#A8{@ z@Cwci6!Wm4A+IS37nz>lo#cl4w)Qr;-yq2t&cU??tWhkb8qRI$3ACZUw%sgtHDHNC zo_K>}4RARMpA2w^1j@!1xQvHKd~wg+v<4whZKJS4fhD;C(R`8(tKpSq4H|@XPuS=d zzqzAbrahY%?c!h8(2nr;8HXf{=Sj zN{w08Q?z8!!z4RObkxbD;-iixmxBHnp&!R%DkCT)TdhM`&Z@uQkOf22f`|8u+` z7s50euASzFM7rMD_|?r#O>i&;zauh~%-7XU@`Ewk*&!0>dM5;#LEE)4y6_2^nk`f$ z4!M*_*FPZ&1W*?uPD@s(i(Y1h-c)YGgEmX7i=7b1hHgLIQR*retvgVtHd7ZqA&tgw z=R9FEb@daXNC0=L3~6*l6Pk=5?kZtj)`Uvk+WKMKd1J-GbY-)J#Yb}Iy%K44aTD5@ zXztoTUF(D{Bci*?Ll-)~v_M35ns`>J>zWXSgSsn;E^S&{pcJi2*ES)65ekKN=MINe z>H6l%sco*KMlW=^x~@rX_UP`aLE{H_*J|TKysOB^3-Z3eHE&{p-nDh(hkEC>g+duO z*t@FRIMLqKaAXVkP7}}ivIc$E36cm#Lzex8AN8G^9Tt*3^1D`(HTJuji<5)Za5BRU zVydMXn}dy5i))kOI!^mu5hiZFs2+4cacvZCVqr|JF9y?CF8kdPhidX81#fsPY9Et`Xi5AbjDCcvCMxrjL;$({% zuld>H#%q4I*zua5Eq=V_XNw`P`Pt&gYksy^@|s^2v@C&m@|vG5ro857iz~1B*<#CU zeqC(+HF7i0k;xWgUiq`dnb-VmvF3TF$ha6d;@Q|nFL{es$gv=C!B`kPY!V6y!j0*np%&D%C+W<>o~E*xW3x3=*Pvlcf{aJ-FX$$c2PV&i^mk$8wE zoZk5x?}5k_iTusY713h^|E6^(N!Iw^+~JTQJ^;Ap#)kmskq&u7LBO@GktpDbjsybN zB0{mil{OL#T*Z?S51i`6c4P|(uH{97g7YlxA{lu4T6SNM$*ehm!g5?R%4n2O+C=7$ z6)BWbCr#F9q0|u)#D)vyEi5ym@j_|4bELi4>#S+0!TCjPvPF(8>YAIH5sMJ19s#IHM}Ju_BFf3bT}$Xro$nX24Mu zS2W}(X9o)#BkU+ye*zM`ZJcbApwoPYnv}z9;&XgFAES~;jw+akC^O1~r!A7j6Aoq} zc#LN8l@g!&9aubSCzm52sm*GXr zf#wtmyBVJbERY87!q-T!Ns{rD78UyE^O%lk2C#TDM!Y`4A$uuMbHUl+v66`P9IVc4 zWArW2NJIaQtM_@L5N;*bHp?bT*xWf`Kh8OF(Qj*J4cA820Mw&eV4L zknl1$;;|erP^=6MOj%*st2n+2X;iWauP5Mebp2Av=VQ}s0hXyF94&g-PPO9==t4Q0 z8p{*5H+T|#3m#bt<f;&C#prM!ZZK@NEsxq=NVqjcI3Ev{XLgY5*Z z3loZU)=s7%yPn(0@YGQF7`;vm`mnT`->Y8T-`i~mi$~xZxRVk;8Rbi#5WI`Sdk*;d z&KIZ2fHcVC-vawlShmWwzKzoyr`GQDP+G=F5TTyAL6MSqOe-^&XTH)mK4%36&5@~0 z-C$)c5{s6NE(i=EfEC--e~CClR(IWO(o2XHzV@l8*bEQ2$1%IZ(E^8|8*;w&x2IgRM+6Jjt%{L zqy|PdZ}06IpI{csSR<>?1cLkV;$-Pf7^QHFknhM~|k)y7A{?#;3+$-q6^9h=q+Qc|^cYQ|>AF zrpNb^G-d-RMD&(C+~mnp#O<+*c|jsJbfjJ!?-a@kjDmFumUVR+3k|B(00NC5;0Qk+ zE-cHQi*oV4DZl^5UV!gNR@DCQtY;s)>DPsSnezERo`Be#rcLm9m%i_n>swAOn0j@~ zi%0J)zuTD42>z_=s}KG3cdwrR=~?&x@yWS&6_oMFl>oa@s0R+C?1b*`|$+eHY`mK*V_WNgETzTf- z-Y4G`0{`q|8-D(`p@(-SUu}5oKW<)v7mD$XFYxCaesbY=xBmXOU#nbLuW;=6Z@>BP*x}`|oEdW;Jtz0}(|5hAecIj|u6k}6?lJ|x@`|~i>2CVh z4<+_}6eE^2(Pmset*f}%|NAn0$_Lh|>1*YI6eoODxx1wC^ci^Mpttd(RY+dW581DHk>ow%)nz?1w zrtWy}{?187*Mw@N7j+#z7o-|hbZ+n6x?_Uv4wf*|w+Xu8V)ef1PX8l16KsVB+lGIA zx~X{s{ct6)Bf~@8Z=e7xh#kWdWL;e84Z`BeMU{&dS1wrwxM>7)XOjeyLO~Vnm5GX; z%>#+^0D1=!yk3@=pSVmAz!PCFhU~>k<{+jr%oy$~8_MV-{?kbFJ@W#wluQ-# zU3|e6iH8o0<2S}k6`8fL1}6%~9WGUDKIBq((G%+gbBoP|E>&bM_i)`F?zTzBB&3vQ zU8>kT=Tb#x173w^E_|H1RFQcOsgs0bL4i#bn@X1|GXLh`?(%Ry^l)^nNZuk-a+G`% zi2iPHDb(RoMdm>d_mGF1S!BO3FEHIMRcyAoRFV0qhx@sQd(p$a?BV{;!!iEm$*4P6a1VL7y&mpy z5BHRZd)C7}=iy%RaEukiRu!4oJsftN4p;6{#b&05yB~9If%J&qj4)Mf@?EM3?pG9d zqlX(P=T|J8p%1xKvDxcVMP~L4n_FxWE>&cHh}0tCNE~BR#iqigAT$m2o3>QscKvyb@-#iCEVj zxYZiBkA3h4*}ECH7^z5c;S5inC9cdfjE%8WjB9*U)ZgV|>PsNl)t@zg5oYk8YyTf>sxs!>prmJsp2X;V-PG`Q~`if@d}%crcfyqrc*TgJo04 zIkV!GZ-5k(iIh1+8W55xlv%a|Nw4#jbGPV5saxg`@rWrl9ZP1Y z{OolUnA2Pxj71r2-zm7JdsY6$%V4rOgFKMIe8M#4Yv;J~#`8@w3mxAg$A|b=)3FW7 zQcs?#bo7fIy^as-iLWEyEOk6|H5%*}*Kf)@yG$mV6^@tj-pH%9fmllB|i8;dzdaV?2O1>KI=TDUa=^ZdKtg&VE*t9_7_IKBlD%=!y1&dR>RVIK56f z{?(2@sIQy@lv{k=lg(Pk%eZ@#8|xkbJ#|#&K{vjXM|}O0Oapnr*GPymg8HoWXKzD+ zX?FZAj$hla^=7YovT1d^ZH`yN-0A4oJ9?Eb>x$>Wd;E@PV+@bBEoy7t=6E(a zo~f8GSUaSSFm0~6%+aPCt@fXK!*R8U+8@6clgWP+BSe| ztZnYVdO&XD7!#7~9``I*(_CKP=2X|nV5+b48qKGyv8KEH?OizN=)_M3(E1-}HUrFdWXqI3F&^U}%Ho<0PgZ!EVr?pI1l!3!f1ic61J8LjLYQXS zu3uN;nshq=DV3d$4xu81PRrFYS$?qGU5=jdlUc6PpNeb#(dGo{5$#FZaXq1JhvZmNH#}HbvJ#>JN2B%7u;MPuKLD96$3&$DiiCJ5n~w(Drgq!#;8hg;&bWGw&e} z)h2fh-H(9&oyszw2T93WszITJwi~9ye98IUi zgLMr^i|xJ0$2}U0*EZY}z~dIovk#w&;FbPA0(kaC?a5~Xc(z&bpY`#wZ~FwUDWd_< zQ13s_e2nvbK3!=7Im-WE4zF_lB(4XL&oZo@<(m6RgEAg)wCp>}&^G_KkC!%l8rS4! zf7ymFIsPyEbfvUa+J=W5Ufb}WxF&C~4PSF*d_7Wzw&7tPFKxIN*W{N?GTQKn7IegFYKjG7ro{Suo!&45g zZMX~9h|5T<0(BfZ`2KD~R(bmMb zna_*X>xV)3#$!XfUCuJ`uI}Hs^0J&m1m)*FnfCgkAB$*?EAw}e{`?--(f&M78uaG{ zM_XhjO`j_oNL%I7IevOh?kfjZyM4lb@Zd2kUYuAxvZHIbw;wTuxkuoMlQAuL;)PcR zdhn#o?H&GL@q@ir^K}o#8Mga@mjzEA?k&z8*|DRuucvz}kK@)q( z6FgoIoNdef{vT2A0sLLuzd7N*9 zB<^z-n%d@$rgn~34Prp!>?)W0fj^@kq1QUJSsa~qKPtI0vWs-u0^0`M9`3Nei3>2qQ4ixjC*(4TrE-R z9Llm0vgDkl%yiF0d1;z5(lq<5Y4%am>;u!M#@nyYkFc>uHnm*jzS-of9%FUK;oqxOso@oX;hjF$_ddgt7yx`$qC(O=HtPYZ&0DT4C2vmMv z&tn8=H+Nb70^{8G2JS^G&9?rXj)wc6m2~7kXy-I}s^ArUOQ4K8vYa~ZTQ-O9r%P`%wM|nWBDzPE?EAtC|~D~w$bOs7c`EyJ%;x*Cj;s<`x-14MoZ+wF;bau z?O=L|+XHe8oik>cLmbz9nOAmB(e4(Sf&L-PPufkKFXX-rW$3Tee~CI{jic`IHEZhL z%@AU+ZFu*<>oaAl_smw05X%ZU%Ik8%v~NclDS+e3cKb5QGn*ZKm!oH03D8haazqYx z{K)U~<(MswZ)<>0^$TyL98^2V^EI|j>$Q5EXRdJkS9<(97kr!D=km@lIkJw-LRn*l ze&W16H7o5Mc8MP^#2+mXRfI2)Wtv2AGHW5-QWyxILpT zi)V3uU5lh0Lp%J2_<8dqdF0eKIzDCV3brwl7wQ|Iv851iOc`U^qFJGSN6M6bYg_oN z4@GtgI{7H_zD~8=|>39;sWh!bZz$1J^)|1|t1Qr`NM1-U_*{#6;rIr|kcH^4%A&{eWym&!cd}I;KBKyN$jvZ} zliH4JSXQc&uf!tSiay`5k81{dw)9>Tn2XnwwrktfxRvhi+IFRkx60r?^N8-GCke&@_a^5|9EB`sLz|DigzrY{o(m=u%4hiygX$J=*tt~dhnft-!IK`Y@s}! z1qbUxrq?eo&u8@drDN0Dxl_hP^~ICDWcc$+!$kR_K`2r{ft#s5~B7UEDjojmK8#v$l=r6Ct`5J$CYG zGU^N*!D{<0O&uZ?4fbEF{Zv7qJ{=G4qjBgU;W$*j+-m}7LqP;+9bQ5YL};BGcV90Y zt#uI|D1-Yg9&*sFwYGtKDi;>eYZv!R5{j)$_DC{rJ}!klmVHlvd#3Q7E7v>>UTxnu zq#PGI%C^V|bUed-uV^Q;#@%cri8Bo7Y%*f;fgWa)ipf6P-?N0OJ}=+Bm^ zu8xEz=)BL#PMsY2`M&Qy)}h{wZ2kC1-tnm?Bf-;6pTn!?BEiRb>2q}IyU5lXb<$_s zuC9xOCg75f?NXmblBa&H#2ugIRfk2AA9Tj&>Q`SylAqy=&z7Mci-blz<@lcX*ame` z6v+29VF{iG;C@k_2Yeg)kB2jXuWxY+cJZkYxvII<{f!wIIp>VZL$@4=VOfcyn(jsdyrR{%6`8mBNdau@xrr5v8NMx zuQu{r4If(#^mcFe&wlv*;FI`!1vkMj9~HKF;xQ}gNY2SiZJ*G<`=a`hP2SDRhB) z10_ly)P@RO)Nh=tQ*EixMBK(vmTE^OKf`65ZI9Ygp~-X@Cv8!CYRifD7RUP3z6xE8 zr#RB6treOKFLAa_YG?g&0^Z$R-__0vP1r@8v{`Mf))Oc}^3~Q#e$+Xft3&OrE5rGQ zvu#v6D|y*H!%1CgbA{H9LlayrHZ;&l4c%?HIUny7&ek`cOE}7QV(#ECM%Z&CwfqC*tlN=6>fJu{``80| zHwIkf>^nmt6!)Io=hI;h_xX3=#iLc;K0g$^LFPv!a)aP9!Zx`18;sh(cE?6+aJ1P1 zHjpnItikH(*r6IMO(al*v^5%~f#t_WXmIVy8lb`Dm)HOo@XBR(3@adieA+7a0Y9|z z54s`Io3#KABY?8r#Qj>|&^3MB{mVH12zCA#e{aX$|NY*3Z|Wn%dc9(w<2+swALH#x z(H~Jt1=IK;7I96C?QY47!2<`-iAsf z_|tiM=BN?sA~F4(%(8~`bNSgK`q_D@WrxG|F>ma+d^(QGA0K7U>buhT5%!25JG!1N zf4tawEGJ7`JsH38gX-CO#tW&(dd3T?y|J(f3S_&is} zgrny<`s~5;tSqCU^Vp7wgv}$}ghJ-Ic8nJ>kL6`X%d>49KUSWli$=<0nPZ2+vwX9? zsFDcH)4CC1dia3@zhNnuae}jDFJYc@`ITTS@cZm$Ndv<4Sc{$|Q*Ff`z|S>$Ih-wg z)7!&|dqcR*ZK-#me()eFDfen)dGlqzvU>7$@{V=n>++(0d|6(mS6(ZdSf9MEoLHB< zE-%v~uPraTKVF+ZmN#CuGsY9I%+*Xcytcfk6JC}vh67$HtJHZ~u5W{1!rHY6qy#_4 zcnnru1HYNgs}bx8E_u;Uu606Mb6%yjKWNf$6Jv%!|- z2c)yt;dpZv7l-O1W|22*l44cW%_modMiezE3F zx7SPb`e=K-Os_TU8hK~fJb6Ec*T?W0Mn!3lwfSOym_L)(;#bx7aTc%D(Wz_Oam2N> zw`v*3^SZ4XCaSfy+KtU@;%Y5|<(|N6KHrC%aj3KREPD>|4J~abO=NhYy%wL$KatTGVf-XNE`}e={RiUrNjVb=-sk3OeC$4} zSDBIfEdHoyL_ZiG-r7qLK|KAt5M!^;^k0Yk)pu@&|8ct@A#7h=L#jTS3++G~Ij(<0 z8QiOU1cmCmWxOYij-P!6)ExY9VEu~30k9DO-2BEkP9RQz?ejRaI{sspSKYJ`XV(QY z^y~tMFK13u?Bl=7vgtz7)^dyc1l+0`OYLR&lia{KbC zO~J{3t+NF<13}EiwpzS!11e`nh;s<)E_5C=)gc<_IU}yuNzqOZq2s8p#jBCL&|}bT zWZ~Yr2Yr>$^|l$Fo(eA54(KTBmGckYOT(F?>{aru%vmJf)L8HDR2+gfi85ix0NzXU z1v`BYnBSwoRor%bYS)U7lH?ol&$)Nw%ow2|*_TK@j5S{1VAy%MXJ@{R-iQamm`4bO zQr*!G&+Q0`qHBo_^O8tYpl z?mVPjlf!uoFDdwfFy4FTihU`J=C#}J#E;6v%T89dqfW<)!ZbF^=}2)nueJJOzyBrS zyf$o;5eija78LnR3FmXCfo;O-W|cwKu$`{%NWL3Cc>pNoXN~IV_#^q^Dc=ph@Rx?$ z*Fv}blx0~MZ~NtB6&EO!JQ2LD%RQ@Hg}I>b#1%rv)i!&6%|kX>vA!*)FLc`C<1wLX zJX_(%H?q3yu9q&6KKOBs?0n7Bcu05?nsZa_VX>W?>O@{`pu6_lKxgxun`cb5-#z^b zYk~XjN!|sczZ|UjJGS@iknf`OJ1%}BrM@@xS;i=6;X9hM*?V7?-_Oa%ix@lINAR0d zyzA@jBQEit^|`6YsJr!;(QqKo`>_v5Q^4IhVycKuB}6N97et=)R>$uPOc;*WlYRgbQO ze$WT`Hu%)kJxc5zQ$ABM2S4e}olvY}u>~1{j=k}W#yQscHyNCRd+>k8lDER^V`hkZYbP3dHxG6W zUK@x-LA~QUp}B6oo@46_P)Jw`wG9!xwGnS(obBGo-A^!5Mgo8LuQ28cuP?NTp#aQo z%sf1!FAFXjdYOHWhFvDkuFq0teO;3|NE@wZ|8r4)#6~Z%qK{&2-??{TP!ihcvtXn3 zerImnepx@-gP#)B+4?v-dtYQWdotjAB6cgyTfVjwA~ea#l`Yc3PnCF)>p@D^+H`FAv6Ep*%i#DxBe{-A*6zqu}8+W4+HdUT{1FK6Pgi zxIyvuN`8JgBA?Y~zepF2PxT-YicjZlfZhh;6ME=_qsO^#YX<_a+xyGk=P5qeHoM1V z{m*;(vb|xerM%M9l+WVzeFD8lI|K5;ymmz1#CF%d92tg+a$J-!=6X*TTKaeP40hlf z{T6q-&cV*(czA0L3?UUent*(r3#G;OlqD7kWHP z^ykPz>WOqsTvaiYAfwhM841ZMNqi=HCVPFxnWB%HC79=G&u`*9kdQ&fJ2Mz-4$*FX z*^@~-pVOt}z{BY~Y`WkOc9#LLoL*R5V{=^x;^+ttK8}P=R`b=>=z*0PY`NgM%vHD7 zuGRG!_FV9_&GI6y$Psp2aM0@NHpgG!a2-wl`?-Y<$J-?C!|;lS%)2F4A2_vHj;9cc zP`NDy9rt0qxpp5`iF9xu_5sLnXV=hhKm3m9K8pS(Q@umtpA#Qh$~X7wOHF0phjLQ# z`H{_k0X!_1`?up<9ctI+vAoDRj{imVkZ1o|V(GjCAMblY-UGXPJbrw)BnA0tyXaHE z<$322v1`1um)b`9uY@xW(cIKPCjz|mAhb?u2SV&@=|}nOSHA0`)^#-Mg6z5m;L}CR z8N)UsE*pK7>N8(Ab%RknJv|KMNf1w+lOcR<2g;*Ps4Y&)9P=Z-xq0OwR3{i2jyB>3 z*a-IPcdlPL{(*bwc1?D~erBn~`q zuAM}L@-{r@Xb?Jfhr#u1yK{^k47R4Rer?L~w63pq?Z}PfC)fIUg^@fwld7-98GP+U zTDJ6E`jC=w4#~>m<$Yj_=eR?n7Qec+xe@nyjnz%i6}wgkWs(Z#BlLPZ4rjP&a>q1o zZc+!lGI>IkYQ%911dq2=Ro@bUek7~gFHE(s?P$6vB|@UCO}@w%cl&Mj^uv{H@dyBa z5!KnAi?m`MaVqfJt47R?G2<4>v>J;7vkY}{|Jj7HxSrly?e9OwvRwlhKecfMw3QKi zuAVwrzS>9nAxrT~XYlIY^{g0P=V3x@k@`BLU0Mi!t|@x9ccSo$uK>hWvvC2n-1s)x z8#!(F80$ca{bQZKKpnyL@qM_qajSUtVEvVGEZ}`>q_6K<@lVBPtZ#!n^_Pzo2#W_? z{@KuqGu<_>&Ko;+dkI51`ErC#%98FxYt z`FiLa?jPhnMCC)D&RBQl>t^<2{fy?NQSVPRKdVSUzyjFpG5aJG?sokM+SKw{w~XC)Ty=-=MIwLh`&;-&c8 zurRT(xf_4iB2kAxT#8-ZNtkW

q6ka4ObDuEv^Lz%_lSw6PA=uW4Io{?GL{v2e@4ssY5a>mBMri@R32(6W-= z(m&YN)jwb}dUtF`>@jeog!bCR!cNSMYj^daP&up{>>21E97a+7eFMXg)7&>WDlTr@ z+&57~=kWHvEnOOXEK(B2daB7k26}FKp|4lqk7Iu&^*5+J7rStP7rAhN^*g$@k97BB zh69Y0pS=)%7OSO<^t~ZA`!x0qvEpQHa2T9;$Ne}r_KOy6vj4o`daoQ@@A9%v0Z+|? zb8!>&ebXgy@YV*0b#*@0Ek_ zftTptl7NZsAG{XhvUt&wMJoZL_z}3}8|dj8?&(hS?C2&7<2UkN!CLBsDB`MwyLU+N zc{GANB9hPG$N&s}v^+eIhUO0qp*%XPvFxaKum=wG;GMWTfs^g6!`l+w{V*y!`iD{9 zFiOWiSw38OgZ=$|iQ)dlz{t?HMAtUlcc6)g=-Dy)((aeacVAa%MhbU->&Oea(7DlM z;hyB{qm8fcez<#29r9 z@!QZcbH(4l()v7;yB{rKsrNd9k%FarU$_ewQqBf5ya?s&!yPAn;2EuHZyCL?WnGB< z@DbaxZD8A%JRqcK#Y!{00nDRi=X8`_T{xO7-IIK2f1zOZbi6d0d}&Ye@Mz;z~7d)AeJy~XuIiWf@qkCyG}IE>tVs0G4oES=wYcu!*~ zxbiv<@96;J0rYrJ@&JUg^l1?0tt~vdh2`y8TezpCgyT2urjPyo$PrME{`S&ul$giy z6aAP;{TK#Gi5Z>@!kp_kjyK6TI#s#hTGfz_*LUxNhLoaYsLE@@B)x>B)EEr;LP%&| zjU93du6^BTOADmn^{a#uAXkNOmF#JJezc=>_lr4uIu1>{@gRFA<3BPpAT|*Onf}Op zv|*JQnFhLjRd&?AEJ6`=IYf0ilto>xD55$*VUElI2lW>s+kM>uGdzt#?l>@iUHKMdxi}Q_WhnMw*j^u9myZEJOZK$nXAwOHR|bniYzJ%ib%)Gw5v!ec z#+`X`!at-u4+i6jPv_9@UGt90m(RXXX<9@09kTQni96Sh{c zQGnOU71f7@oNY!fWf{4+MhiIOMN{V8+OYNrQt0%9%)0Vh){^DFr=#$e@*JTo-2Fn% zD5ls?$!Mn=iriOS2YQaq3%?+w-p&60bI3V6XC#{?eLy(a`O%jAbJoop;mjFbI}hA> zMSB{lXnxB|)>`w8!8xa9-qmwBxG&_8s^gHIPZW6LVT@qu{{JCsTbA9Bv78;J{I?+z*@^Wvb(UCj> z%)570(&E}VUV@6$G)lv27KAh;uznRi2;+6+g>PAzhBRc@<}0U>0YbBl=0u@9N0a4h^~+%?=a)ezuws?u6=L-(9IYw$D&oA^ zeckKkow@su9c?ThEz85uCCh23aDkO{@F8YjcdBjKsPQ=STdp|bO=P>O@1IWE5g5$E zeKl3o{iS;`Hjl`>)&K1Hpve%m3`rrj4ctF;6v6_z{llm1knO&v3QN$3c)?klZ-%R- z{S{)pWQBu;fPUxiX*@uilsxpF!dp=PVYSGIptXCb(g#G(4~+ce){d7T4cQm8%!cij zi?tOPpu7w7Avq_?-H-a~?ra$?SnZcknOJSueTcDQPflhBt^9+%n~gp!q0t~u!WST< zx2GBv6Z`$=B6!SS$fLpxA4O4JGtZ1Pf`0e4^SF?bWnPG3_q8Ck85MrUHY(&5n8eQB zy3H3C43+^YtWE5>5N4}z-@9%kEq=i6OW$JC5PRXi8{VrI99AikG*#V1U$N5GaUvV{ zaJQY9H|^zekOA2?tdg91=Vyqtim6+?oXOMqBQ&Dv><=*@-oFWj*#2`f=`?q-m;mlOp|@7)^3{&P zJYY0LkGb2}S7QsOlq)%nq)`i)iq*H>FO_=6$5TAmm(o2Qv?{V;orN;AI)59=&9fDm z8JTGZ;_19mG*c$*p>@1#2o=1)PI^-+JE6ll({4HuhL`f>CJfulLc70$ zEUQcA=c2<9KWfTx7O9eTWC&2~5$A%~BW#KaN7q&Eff~V-4VU5noZ%JtKX>?w7d`;~ zKv#S*-pvfoPOMYha^8mP{a3K{AeTD6YOK;XLdapg--rwk!YPJ=K`i zFl;uLilUxfHB9O`$O!uaOTUebyqdzJu}1`jY!=a`#u8yEJ^raZD66A%Kh|JOGTdoR zk-lt$SM>cS>^}xPncXgUf!(w{YeCy_mWh`_--iF^;ji3K4Hrr35BMLiwE?#tlZe5b z%grcK46|KsxP#<8FE_Vh-dm1uAZ6)}$Ei8b>n58Ek+P+1!~A40_HvVlH!&>7hmpd$ z0O;;P%C_K>I9i===?dr=pB$w~%@VqVmug1Ja-=+5KT>!j0p-2Z!##*pLP~iasnaBP zR-wUX8l;)AivizJQM;Mx+YD*7}f+{O-H+V@+FpIiz=s1kiar~e*CNJkQCPTkP-8@RF zXd{vfNnTDOiPr<;XxfQ{T7l;N-VgyU7V&t;A-N#r<@}Gky7{6Z-XP#t(Y9vg*-Mu% zVOnSuLvP+;%yQ~RkmjsqlyV4jR#g;p_O=LS<>G6?m}SctGH%u^UpAM?+^+>Orpn7e=(fMxJ8p8;lX2t)bV zpVsvqT;7LS?{ob~NdRqoew~3i;9*!!%K5+D>&l_#862t`b9tdHInUAbUs;9O&$=v4 zK9v1F%upXQ4VVL%V-~}b>FM@4%qxqTh5S^iw{IYoa&OAGEB79xyYjxiao6%@tx{Sq zB6vAM-m0%!$@e5AiI)SamU&n5x;?M$iE!28B}~$rt)J|&`PMxyOWL~2y0*1==gu}z zsC~bq3a*}QSzRe+x(?abPxMM2G=j>#|I3v1D9n`e7tEw}5q##-vsWYnzs1W|E?u^C z*~+ue3LueOTv@qd1t^yVu;I zC@KY=ZzML?md-a%%;9qMyD$4ROjVi6 zy^A&v>CBN#=tagaZA$kB4Fw6FhAK_@iZQ?VmL=yjPMDUg1s`1Ak%TJVo zF4A9aF)sqm1&@=8K9JGAQuH@qpom|NznehwWk;8-ytT-96f`AIkc(;`U*3tppAVW# z9bLBaW+P)OXm&rz(z2Jwp?Cl^lb;eYgCUIV?2h_cb}^?1}*7a?wLsFQbA<|b&y58{tzufyb&0hl-aRHnUeVAEEK z#Dh0*v3AgvH#>AR{(nF8U7`Q%bYAP}iDm@$=a-zUAC99R@Qb=-k{-thRYHpt4i^FiLu9scpdv%y6Ki+V`MlC#9Y+0br*I)XO~TNMV}7TRCAfT zo@@qyXa0JZ&(|1oC18%>&GH6^CSV`9kh3Wb_~Y-y9Fu0hP6kW>Rsd2~rvjb>cm`lA z;C#RoAnr)hl)*y4s9b4v?D+cF??aE6D{8ku`#Nwa44HJ{`ALoP&P0?GEBsuhd#3IYCu|? z8bEG7YXN5f;#4@zZDbN~2_US4$gCc)3fB#Qs{tDU8v&aDIZVxf>~9NTRE9SIPu!f_xR-J!2xmG@t04blz zfG`WD0Fbw!g@B6yj{>BQl>oBMQvjoKcqjAm$MX4$>dw1?i`q5vP!5#wmqT(G9PGE# zk447(;#8*$vyJ4#7z(~BjrX;)2#52JeetMSy1jo(Z@Ba0wt~vlOrfa2a3& z;0i$Y=PbaejAjAPUr?WTYruLbqe1*Fh{%XMq?v)gj|FAqEtANI`vugg3WF@mpjvYx zWTEuuRb`+I)=BxW-U^4utxB5LrGRWpS&ZFS2YfmHC^!D1^W}rUMf*n{>f}ZE`$DjP z5=@hZgC)lN0{!z=E1fPJu>LJu_{kwr=&h_lJGU`_5LWl%GCnHhj%N@gB7|3P!SU1| z+eI00Y&hQheFc4HTfYW)BH-5n+3vkDvRDH=TTXudqO!OOxTq}1!}6=~cYjb8!#xQ5 z@(;=)wwHM424x5P$vUI`{ITojPXIaAKLuo){`U>^a|nFV^)=YfF9!SR#_X-==|uYZ zSJ%(~bNzhH_4DBKpryh1Y8by4PX`E+W}hv z!Jobq@ST7-*f428_Fy;QF2EZBZwI^y@WX&N1AZRx-GE;Ld=Fp_+VEaL+z**s0im1b zeSlSf{{)CVzqt*t4e)lrO99^xi2bVhXF#;g+yQt4;0FNz74TmGKLz+T4e(*W zI{_aD{0QJL0pV>j{YOB&GndBPH+KVKUugav5PKwZ4flc9`KWZ_W|Aq_yxeP1O7ii>dyUue@4H9x^fk+Df4XW1BW}RkK~~~UWvc| z3hE=*2d9s^_JSn%i_^zUT?*WXYzT0(Ug}P8pZys6#I}4Jkad0sked8mz~cZRZ`niQ zEk?Nyc?yv2{ytz-7Tgz%B@60Mbni$W)_*(x9tg_9&aAgW8r(YQKEcgbPByMy{P~lO zHY!b&`>}15SMc8VIrN+D{VgE-`a3|%>-T_^*Yki&0AB!H1^5ym?`{78*a`SDAmMTg4EJFOCV^k?>iGMo4Z3ych#vga|yrvD7EhyrlQ=)Tl%^#0ic>QjBY4m8uUfZJ? zswm}sx1%9on<;NL_YVB=SBw2O`;i2k3b-1OwrvgIX@F}17Xvl`o(I?nxEinpuo-Y2 zU3C;w*lS@xC!ucfGI%AZYy9^&w2mNpURJG5Z7fLk8Y$F znbn@uNlPBmaPEB6%fWdLKF#6&cI-7ab39aj11L{_tb_6^#vj|jU!$>mh9*FcA7qlA z3D^QS7jPZm0zj+>=@o$OfK`BySsFC(Fk$ufVnDWi17K7ht>`$*VEOz-*W?>vI~PXe zK_1Q{!n;E9@NS4$WXuohImMKCETD*7PBW7;QN)rcVsR9~hS_O$17?zUzDX%^mbn8_Wcdf8)Pv`+iC}&|p8jmby-9J|0f*_i z1|K*K@f-2XC4uu*w;%NO!uiR2AO3WH+Uv>YScs4L#aL7M)A@{jL+JVwk!!Ba{PF8% z^8d|UYx(xtKbpmPh5WR9%xU>4{}Fe+%9VE$rBZm6{{!-9y>g86zDS*)VG&g$N0cqd+0p|k_04@f+3UDRhAYct3?vv#F03#%J ze<$GOz@wh@6@b?Qa`biqUJr<~yYzbj-vRhB!0Q0N2>4FGUjyC%_y@pu0say2CP3QB zn*m<~yajL)i%;wD@ z;I{yA_Ghr~PxI5a?*QUl%X}B`bigM7an@s=1Y8dI6d=|D^EBY4fIkL&2jH`SKLdJfsKb0=9v{^dl$|mi7tXtYctM!qkP$Zsiq2I}1lAM6Oh=vR4B=Rpli?2G7?%Ji}zhbVN>9oa>4M4aUv z=eXkHK28s^IHz`6OO|+$T1&*;9>;=}hdl1hc2&czMkrikU2FB~c0(bsJ7WZpq^wzL z)MwxEjx{#6q&6kw)Q{u9lEPm7w69s>P-^?*Ls6evj2(o#^XT`s;HPDm4MhH+gge`Ivhn?lma%`xVY{4J` z6|Tmyed%+uuwJx_1q7lEP`b=P)y#462H=@hBr(ZrP`vkjYA7W(*`xD4@N3J)_QJ0< zjpv7-bIQ-Tz=n&tpI50UMU-wOW~r;g z3t~@2WnaTF2ecB6+^kGCx;;0p?<`NlJ4<;j^n6p>+$c0 zZFA^-pLFog+77Mp>eXNiDpd{iELtXUW%K-*EZ1R(7cDqK0}F ziq_`lc1%$?LT-=+f&?1pSqK<_qrSR9VjYOvAC;y?d=@H+KrBA=god`2<5a=f<6PEJ zT@C_=H8A86pOc(;ENdBF@wtIw9u_p@H6>#_<15J+&hfPdtWhiluCpj*ggvQkH;Y{j zSfY?8-V*8c3hs7oC~8nPwjg8zB0`9JdhGPM`(UH6LV+c@AqlTj4Xe@3H3*)Ab&p=e zQVa{x+|e#eGKu5;tPcKXr6KF8+ZCfVkA-d|Zad7}PbX+Vj`J+kF+?w~xi zcpY8AAt@Z3dXC1cYucI{I@;lzx3yk0kTelz*y3GL3gJ{HLB!j&xHgqWb0|p=aZ!B< zMhM@U6qJ>tdA0>17ps&Sv#ghN$)cB4c9iI-qgBO6ovkhfJ)K_vBaV?}R{aI%l^B{9 z+$}aV)WC@rBgcw=cHD2ZGAzp}D4J9ljW{aZkRTr)oK~rdVp=Zq>uM+Y@M;Ioc9wu0 zB7v@VLQsP_(xgU7e9dWNbm0>+r9ed?B3=K4DA`n}bV9^w$qIGR%dF6w%5C_1$P(*f zC&cwO3O#BKP@e86b(M?O9U#@d=)xzY9c?U6!Yft+^ zD+FnDMH3qF&skqry&k(@ddd@(A(bv`LZ#E&C*zG3$#iA2g|R_8;eA@(E0ICxwC?~ln#2&T5%Ip*MNJw1&;2xAf0R$n%e2qwYd%J zbTb?!wqs~L{XRZOjq%3%)S6^)0PT=$TiCkUK}uOv;E7&lL=)D3+^p$@J|Re059fhR z%@;TMD#U#X%bODV9N&P6cb zM#`sDOT9cu+1A$3u>l+5_2R%3omS(rB1FX8}Cuaw_bvK-<^b~7VZ2n>||D4$TC0_oyvH45A{PSY- zmwEZ;$L25h@-K+ZU*Y9f#pa*o*cSG z&9C$F*Tm-ABfujVd3;;3v5np$@i`^$9*N6Q9AbL#kb^is77R6m(IT+jci!&99`$)U zzs z1in}Cl)CD?T^iMiRhC61?tCn3dDC6K3w6)4wAC{3LI2|{?6)W^$35#?H4Qa5zo<>N$dN@|b5k>7ams!Zq1)PV zS4y>JDVfo9wer|_x|$gqP*=;$jHt_99c#-TQ&;6SR#aV1VU`jTSy!vh46du|kMIgxDqP6ClACe$WXCoPZgggewh;&++kmj7lOosvr*z5|jrqEhS6Y5I9M*c=Ey9 zOxc@|E#J?pZ*0L0qa#u0 zaI;b_}*e>#BJ3;G0`@1?Zs>32v9(Ze*T8_}kC{cQW*R`pbXM+Q8w#s+K1JZ;%jzWKL_rMld zi^8&%uDxxX)Z8i9vqEXhS<$|@VUUt}C@YhZC&JPjKBol+&5_wj1z=?@5_y@8uAs^PHJFe^Y-4Z@d;+3 zTs~q%xsh04*n||yb5vwu572~9@5Ng@Tf&FhY>D@TTILOdr}M5)Mu3}DkZ3SM%8;=` zsgErT;e7%SoLfN!3rsDViC@?vxN68KvW$?DQ;qXbs5LI4Lwxlr{8|>Cj&~$wjH!@f z8O03D19OgRQONLdi&~p(@b!WtxR>~ z8aoN8l}A%Y-H3BVde$=YF*ROsNXa7rcAAn-AxhLo^a#rV!F_( zv7saN@NiAhauwycx+PW?$7w7ys7M0{up=I?X-u-`qTECHTbaXM6~7^^sQuqr&pvk3 zuM7V&<@0|$0kLQ0yYbSTyi4Er%JnU$7EHam<;A0SmfwwUY=r)->#Gm_^mnhG|LIxx z|MAJWci|HQzDr)3bI%92wBDcpho61*%X0T?Vq0h)eCR`()aK(EZ-e1&3X2*4L|?e(8D{EuQojP zA2%=g2@208{+z>4F8uD+-~aY&l?w}&-SKvaYg7i`DWD}jW^zY^WSkJfOk4e zb7sta^qkz=Pv7;f_Gx=>xazrOFo%L)dBxn%bT|F$hZ6g~apn`3J^)knC-xU(Z@N}( zf~Wnh2yrAn&^6=%9TW8L97W+_MVI8k@O{h`^3((PXG1yT<=l0&M zJ0{rdUt%`giOU25JQ4O{$X={O z?sL z&)gz@_33cedbpcB+#U~iw}<o?DoNpx!ljDLLmqCghogNvQ#fvOsbX`7 zOBI>ldbk%n9PZ_WquAuTRFOgW0Qu^Dl+dy>MY@S#-)nQvo2L+mX+AtVna8Qq$@Jpkvc~> z9(1W<^N>pwner(%x7f^dDb$P9xx(=wmnt@Qx>S)_Jk{nFo8>MA4iDGj;hvp_6tJyGPiiR_jl0TEPvwRFQc*QjLOpr%ORMkZKUzZ7x-0K7!Om zg8O%uDl(r#>O#T&mrE6yuOn42xJO(Ha|Wrkg8QLM6`5ZmwMKBib*Uor3R0^D_ZOEc zGI__~`%b|XxD<2^sXD>Ubg3e9H&T>FvH65c6`A`y-2EPIuZMfo!#(BUe(2$z^KifM za0fixArFVUJy&nOOJU4CT)Br!c(@7=SLxxFdAKSMSLfkcJY2hnyWGQdd$<7)H|*ik z9_~gD_aP5=r-y@K#k0;ykb4?-Jos~W7>tl+lT}rS>cdEExScXZY1)RI(yPFd___!R@#=11JC!&u{he^jN3hF~W^qesXe>}>;y;JEh@I3FG%r=0JQRi$M zT^TphBEih5Q%H@ zF}z_c#orUyPjEa$H!udC{veI$QPbHsp3UIqvt@f{SI@To?cH!?hsf!ZW`H%fJkY;< zz3YwWcc(nz2?AI*9G~Hq6@VwC+jca;I zISPMaJEq|ZWOI_^ zo$GixUrDd?m2DW?ck#(M_bo7fIy^as-iLWEyEOk8e6CLaq?GNRhT_%&w z3dhTcn&j2`SXZ|C&UQSj9FNL^^ps;f-z0Oc<2%psaf}DhMjhh|9A3*)`&k8ioc*jO zJ@m51@i8rBKu@$E)ayF@#p!j@@vnCLL4D;Mpxol?o@~}SUPe2m+*tPj=&7UH{)>=D zdBoR0$uy7`e2s)CBdE_>fA%&Mm}bY%h}Xe!*Lt(pJ=wH6-ZsapdKuqVJY;wD>m9wy zmvzPS;Oh~`voVH8+ZMGoZ*x4G9M4qD7pxspN0>I(T;^y~jy5=c9JlPUn`}BA?`FrV z{b66S^{3nM^f;cN%*YdNU!K|O=(jm~>O1Ftp4)?5LA=Qc1?oQu_3M1=clgWP+BSe|tZnX5$$*?LFcL4esrn$Vn&8e=D!Bk)8HJVRZ zV@-GY+q+U-IE5eR+{(zN>=XK(dzF;WI{3^twEhR0EpcwMWlEp8W)Gq)uG#yr5a~G3 zMzEdy^Y>Y3JMf%mBZO(D?fP{ku1U88kW$&{=&o^eTCSGK@`L5>a`bPH(4UHH{?XEf;L6hLFx~6M#_ba;!oG~n;bv$NXMV%y*pAi%h3LD zPs2WP424(9%`@*I59BuLc>h1zz67w&s>=V%(k8T_O}apV0*|(=rJ)<86okAaFHIm@ zvvk40Ynr^Yfox>yrbwWm(}_BQFm8-H$f)2lh>D5`ND&nr6b2O$5usQ_ilAkt(*N&w z?mgf3zV{NT|G?|{zH`n!_ug~&``vqvpZ^-*!u%hw{PaA`{At_OF^IAmhMU?Svb;A~ zUdF>Y0>f!Md}r7X zmKXK#QyczKkFR(>D5{5_S-hs4epO-A}6lc*Y;Q0dBQ$~!R{N*l- zFOW$<0E4_i=h)Ml*r!MTS0CRe7g_KB8S%b~-#Tm{o?!FDykln%CaH!T=7l`8hE(cI z=HA8R*YF;Z#+GmzIXC%>mEQ{acS1hB-3N~k==qdnbOxsjHQr=p=1H!V|Nz@KJW(e5jaq!$!6)STOLV5F^P_OLykIL3LU%> z(D7Q<4^$a5uY3kPI33&H-(%{~vv|iHOBmkn8yQ$V*grC0@V^JXD1fhMhY{tT3Y@&! z)ZTH0)-~4iVy6kaGnKGaY~uI>!p?HysHv!ch`OR5hXuCdW^4tDnsb`S3`>0|v_;55@U!G89W_^^?C0Q~xQT2Pa|^CM}k z*`q<3tWR%34s}@vU9!zmXJ-DGTTFfFGj*iT%(Ff-kNV6!@cESJ{;MTXZsy;3K}@h@)lTLo$Ha8d0`$r{ygUh%RePT zw!cr~Oryy19vQ*Qe0y?po#~dB6AgNYJ$X=M5N4p=gT_bOqka?Bp)F^H2E-B_pD&Wnu^ zc6XgOi?;i0-_14c9An&1=$yaLH7+>Z_n5P-9lgE0$H2b;hetI$-%q38d)pQn-=KWactdlZ(o&7AUS*UQwi5?*sf1h>_ z45pX!8Ft*tb}nP{$S_ZXNZ-kmW5?t78OYW4K})8hhd@2fb4~=FZ7)VRYMxoXd|qn% zU9;xe(hkFlZW-k}ee43|ow_M>2KtAPSLO|)RqlMq(7$5uOl(>`96xX3>t_qgntd5h z*q)5vd$BQ$b|iD);5stLIhE;0o=zhiHP0*$^K8Nd+kTF-(1tnFhEcsSTpo0$aTs0X zIi;5WEH@4#x6JC-@Z~s5EZm8*#n@= z!w)=N z$Q&nb`N}Pyrh{vL%2Zv=1D$d!Eq}uD`}2)s1(;VF9g|=6Re)Z!+J>vK;iNv>^42&R zCY+Z7#93>@*4eO{Pruv-m*$njG^EF$K5Qce-tk=l-*s|izIhDtn>1TnI1}92-Jcx5 zNvq+mWIw!8_4f_2Zl98occ`Pi&tt{ju*jTCnOnQISxG&Vk%2ap#M~$YZGbe?$$(4~ zV-NSCBk&aG#Z@Zl80zy9;?Wj{Xbh<`Z8#0q;ZI|T7RVdFQ6!UFhcsYBT9g#XcSxq> zThqdCB@o%60sS(=GzL_C@%sgn64qA`AJiAWT_8-K8^~8~A)2ILqh`jalZ7`*|fWf08P`^7NB``ig;w#1o6ec!SK7HG(R>Dix1`} zNHh7-aLs}ElcGDNtu?d`H!@$ILbO1=;CBJm3ma}Ai!P-8sxH`XCnNHlGV;=N9>80j zt1RyQZyhp0IKFD1vYoP$?K}Vr=a#x}ZnnV(Q(fKLeQoqT*)uTs)@!%eV zmuIEfU;!HU*!=N<=;q6%c>&#gY1uTjZL^+jK}FG)D-0Me%$&im-@SDYI9@SM|a-f5lO0Pmj*a^GF&wS4AW@GIa~9evde z>y2fc2X5YJos>wr&ECJx6*cUCxqRWUu2Tm>W3cmI7g*^ zsUM!|)Of!w@yf|`cOI^3Q{8_@cwEPHZaTRBLp?Hqk&e4_&Ay|WjuP8%YC;iov!CeQ z(M$#`BpSL}jFPaPeMAYX#-fDg8b>tY)IyZdXfjMJh8da~h7uYqUN_4%Nkdb6P$ryf z1X1Es^G`}Mwhm1=HTWbnm^EbH)UuP|_e>g+rUspamS)b-$W(()!s9nlXmzKioIE;h zBpC~Zj6-cWnfPI{&xTWbO@gN}LW@`XOoETHMQHidLX(L%Y>LpNT@5q|kI(QR)1{V~ zgr-)x#OR<2t7e&m?l(DT<5!DJLQk_eXk@5eCgBl#K%Tupra=uc`RHyM+}HqhPKg91ao zS!TRN`5=C;VFCZj5y3uB?1F{O5{AEh|%Pg-6?& znn`oZ%*PWpl4p6ePfU-?XU@*@Y9A@Q@=dU|mL~1gE@rbWSM4u_&lj(cQSzXDsPKiY z`F$ceUz$N02=6}||2c;wN(R(R5E z;h8jPKkLcy*|4*D*M3%bf`;%U&Dz&$JU$6R*S=Qh=qCdv@N68~-&z^g6rD+<_On96 zb$FOUjk13yacQ3`yphK5jLc}$cZN2e;XCSfVn*+byzx!m8NP81-dSCZWA9G%kjdB` z)1J}Los}Q+TSk&`&9igI@R@DgnS5llaA)OD$iSWD9ml?%t(dJ5xpzHDSki zCt$u#>c@Dt>nLk{yLBdg*{#+Yo{8D4GrSYCSZ8X?TBU2N5vaG5OCF-#^a zb);poP)AxO>vW`LvP?%>CaZL$WwJ;|8cxNCogL}dU2A*i$QmeoC@9y+hl3Is2D#d<1d+7(e>;yU{&orIteIA1PtaR=GIWt`~I?Vbe?W7G==Ol&LEx zWX#Ky!6eVvS6zHP&j}RF#%FHP&rhv>)QpL%9E)JxJPf_`x0_Xw=!GUz9>ec0+|ky( zC4Niq6)RQF{wHmn$NDwh(4j5sG&_eDA8F>$(ju)KT3VWsLyHgDI28S7F>omKjMfdU z%xL3=ri`LZ8yZ@`u%VR|vTG>uhm0BuE@08nh7B1s6uvZThL$&zF+B>qwmoA+=BZIr!NpJ~ap5Timt;t5gBULPk#kw?a1k ze#byeGrX}NERBJQxm;-r*!q;TJ%M=8FQ~~YZ3_0?^bzc*X&Q_5cr~_Rc!rR2#e5L# zMvL`6&o7hc1eOwAGf&BYyCswEXlF}?mfh8o;feH|Wb>cNaT3#<*+G(#3y%|Cy4iC; zCdW3MnGk(FW%T7SxnrA$(sKNz)fw+K-R>UV;vgdLzJ2KX0ut$d}Xv(Z1o*!uGrGT)`}@F-S)82O{C>vD<{(M zu%)Hj9X9eZTOBs^Y&M6P&Io(M(pJ-r4I6o3Q^S;z#munCDz^5dYnox55guGBld#r| z&tUWilWeGhODil+kWY?v7^-Egd*0R$zoAZd&gMgEefWc|4}Zg)ZJs;Uc}6!w9*t#A zfnibNdJ$n!6+LEePSL>6dgbxv1mii3Z#5nLy)={7KG1EyukA&gFX2Z&+c&yn9eidb z;O%0Axx<3FWlOTY6{Z-C?$yhmsjr~H!yljX#b23uo+QsJ1wWb36&vKafX~tzj4aRX zo_P;?)iXGs*E}i5sgwafUz(nPlRH~a13vC7ZkoiMsHmaKD2r3abWDE<>8&+Ols3b> zFV**%=3UNmkYAn4@p-nP$+;oEAH{ccDjN1^Lzn)C^f`PNd$J~v$M9VZyxO!KOI%}1 zlgc=b@6B;^QB6&8TQ+lvt1t-4J)ZCUzF!FkMfGq_VP%~_d~G9)KbtZ=(Y%X!X@>Lr zn&bP)q$B9Wn%k2rB~j!|yk%lVF&6Y)B!0~O}Ip((yv+8g7m z^mx!N%^XY9o=|>|BK4q(c*YarUrl^PmBdvo&*J4x!qo5`-(~0;1>$U~OkNI6r#zrc z;)UNS7XFHsh9;5c#PIIZzf;CA8|bA)_;W{t9_N_1+|fgaz*SRQn^=vSCwvl@#ni={ zFGfjucv@;D68eKrliAB{|F9436bmwO=`MYceL0*yL9H(i?-)q&vIEz6G{yWU{4T`& zSI<6xd@uk%VCU} z{hKbwMxHg3O8vfpbo>=Ro+o?U(_IDJJ~X$`?zpEfc$kE*GTY`+-z$=J%@sIU11{TN z5N8pryQuTvi3fO4&*?wDQbgN&h&qn=8r>Kf7WEi>8z|fz-%wv6uW_A8hFebs=T8Uf zDC3oV4z8JD(oyCl2aL`s5|^jfdNUG>VBbTXya_(8nQ2JrPJ7PH$>PkC=?&4*@nY4B zjK*P9o^<1H5+8NZR$4YBCfbn)<2+)j>u_qc-jk-Ikwx%oF(;{gB%5 zA-Y)mx5Y2vi-YN-<2}(?Nf2-HWpx$h+LU?@;Z0ojyW=X%_xqe}a_AYVYS40F`krejI90C1$rrTc)_VF>kTWoDpEzC^v}bW^2G@Z$ z%s=EX*4C|mBuo-M2op^>s8d^6RnvsVY-M0pioNpM_=b%6lU;+_cm-yX^nVv2!x=p^ zo{*{rxQxY=puPp3y4IrX_4`x-4pEO2*!0KaFtLw5jPF=D0=~IZ*Nb%Edjx)O`Q{dp zb3?gaY7YiiKv3PaM8>1I-L=ATE_d_7elFk!+LoD% zrw?esg&jas|6%9P#F;TyWY$#HJNw!1>fZcJ#2@N+mm1ZFu_o`FbI|!T``vTU@9H{b zUer8SFCpTdxz2}cqWH{u#@XcRfaf^O6qrjgxVda>l$|4!Z*z{{PxrZzcI$FjhS`Oz zN8V9&WR5k*m-h%?E`iY}o$l#_K4GYjkDLPIDB4Gl9`bzg;TSL~yOf#Zy6A)ZRl8S! zg@rr+@#sOnfGkJXO&>Q1j88zV2O)=m+HSohm|a$r2Gj@3kA2yuR=6KEZTH1I#rxA{ z=BA8)uS=IH3sWue7oV!(3|_zY>$<pdYkr%j7m}`|jzH9+G*+}CH(=u*DJoReS3HB2<#V_Hsj)J z`s8LI_xijxasum#WKB#LVJ3`&H*jqae>1kJL=%xSnWNLm6>XL*MLXBA{(80pab@I< z^}JV)xdNvO?)|cC?TX{&J+7Wwnyx)>lhlw9;@6xUlnN&B;>>mt-CddLKMcv z%V~(i&f&y9E$u7tE|=ct;yds7pFuv%`4(D!z1u{3&?ZB!v&iz6THYz>CunmdCbDRM zA_+qw#=ZvQ$#>efws-dsDRwF50axe@_Yb#wIEF0}+Z9O~6%js$Ew*8aWE>1T%Z61P zZ9&ZO+4MLa>4GhjVOphPm^1Mnb9S0jGAMWA&H`?Mvs0#{d}khE&t#ze$`P5L632TG zuxUbPR@~Zh<6rEwclN+QG*v)8TQZKIX?yk{3WwLun?0MqyuzUBA_9D#9LsJLT9vkJpgfKd1 zR~t1t?wv+?q5V0}g20eFJ~l@3xf^-z_!v2-v*V-2N&A(k7}8TE2ioCwCgu<3INzpOburVlk&Xe_fKfSF#$veqqpec?25-A+zwcPLkMYsOb*%Qm0enR(zg z^*E2XHj$JsuZ{S8)neltrH!VLOiUswF0M?Jx31=eJ?Y1p_9oq^$Hvq}d|RqxM;cAS zU{A~+rUv)I1kXI++*1M{DX>su(v!7``qkKh(Xl|nweUOO>Ud*-!<4Pf3C16%U6HMi8bJAJ zUsk|AG1L#MMH$N1^~X68eAeoTj3Kkp&b6=Cab4|8oG4+%P6fR98K09XH#&Z^7}qpr z>D!ac3&)z@A`UzEko})?k)Gr>bH82t@(+T?cunK@W#$nq3s~hE>FwQt^ZLdI!&>N5 z|MJ65Y&oVz%zs!8ba~5h^-*kygyQV&$6Q+TlWlH_0c1jDGhsfgAxquys0MS1<}D+` zaIc5?k?AX{`Ug8woh}w-&hrGhww_*!JfUw_a$u3~M{1vc8Th$2{|@Htdf%KjqLMwl zgWoN-A+%nMuwGc3B<;ifgZ_C1Z8~EPBKv=^^(kdqwW_T$+9zEHtT7IDZ))2*G&};^ zN^M&^mYgj%6eV26sbIF*fcEah%Ktgn2>BVI4d-X>}?#1{4S_w;Y>k1bla z48Qe@Vv8C&@!Nri%5^pM%a#IOg7Gbhmw00h-jWqfINZ=s&+jXM=&i7(s=#p_rOEh> zE+>NI3$`xaRF56cW`?ROuK--#i%9D#5&i1sMb7`){Kgh_4Xhe~m&NX(6jI!=%6cu9 z=dS+2<_@$mdFk%!flEAuhJ==i*rIlr!`!hm1)*Y4U@$e%KR66g{k;Rj(9^uPSt{0@ z;Jm{S(LUVM+tr~y@j{YN*3+E)qfq~y6zXvoek}XVfH8mVS!bP8UTmFI*7SAsjC7{b zom7V8XBNV1$|_}~_iY6;U&r58Q0$rx4kIM)92{%QzO=N>{I4z_(KoEMw2V!_t>*r= z*oOMvc1ch7re-XZDpQ+AHn-8FAD2y~1D%_obNI$NYLe3dEqCJAjo; zgIZVTs*^h}pcTkie^(6Mc>mxIl+mgf`rIM@=d_N!yzAw{T~`$z8lH9e%tN!;h3|SW ze|O^GuB#3@Bl*kj+jqfOqOfrb375|tt2?-6ui+^kYb|Ob$%iZ2oj5Soda%irGlus+ zTzY?@^Ar1r_|_mcXJpc@hY#(mL3l(33D@i>ZkUT+vjoAf*;)KGBy(6;P8mZ|w$HV1 zb9P--lsipgcD6ag(?oLH|CxB=my5VH z=QoYTS29myYi7CmDBhiTeRu1DvBc~169;x3IAl^k&6jg1ib=?KGwS8n=-247BAlFI zsL{iAjMkQk2hb$kU-mOC2czpR~=#Jj}ubN%(HBLQC*&8J zRHjL-d;PpRN^L!GUMr=d-Xzkbx~2D%pJ;mjiSk50Z@C%Y^K-_f|c7{suZ;p#@v*-~DM9LPHqa=!t zy9hl=(eAq9eJ23DYv+1rcs5IcYIbqOr!JnXSdU>sSMJUG=In{rz7D`RXaVu6o&-e(h~|zB~ua z%YKA@Wg(;&ANPaCCTS>v&fxjot$W83&(BZnWoMvS{1A>;vR(t&YF#EzOrunAsq~Us zsp{w`-KtI=>0>3b!o1d^v3SwUL@{1>uPNLeFQR&&o2H_dPKW$maA|UN*SjaPF%Mma z6x%Mt)oZ><3$l^72DPwwW*q8*Qi~D{v;EuEybUu@0pySM`rIla`m$NMowo6 zOP1ZYyY=baiD$>^o;|Ow`082jE*xup`n=YnZBwZ0Li7>)CbMsDWnUrv1_CW)7kUsq z4tv-9JoDC=k3MDD;~?Z!7tU-fB1d)M?#3ch2xLMjn8c$3Osy*(J_gFzQ@);hW^AYl zQY&^hw(!+g&|^PfBQEweVrg$?d?+;ad*8aW$~_D6br4dnB@n%9J1Sy{q`r|ki?<+W z`wFM8yRU2dOmvCJR=h9|4{K1%WZ?6)bTc4C#DCR<;$L@pj_n`Es%Ndy0agd5*4O8^ z9@zE2hekBHry;pIj2wl8QNgb-jBkOik9&l@Rvkw(bW@>D7U^5F775z5eWNoxA9Vta z_#g+VLiGQQ8ZC;fa8G?kr#VD0F*0zyJFMZrF9>n9n zkxXfGw4cu(dlgMyJM;Vxv`o%(2VPD@L>TJCMwyYIAr$T@Z(}FDuZsP=Z8e2sYvweW zXGC5-$CU@^t;O2V@;^{HIgf+F*qV)sn{yd-@PId7BfdS%1Y3limW-eqLab$i1zDRj zl(1NEqk-tddTNQ|iN+dlIjbCf#nqvin}T2YV!2J`IekaGj8m zdJCv1-aTb#l1wE=(wGyYTG1*t0%fRJ3|eZnjA*37kiDgzX{g21?=89h@#)t+CwROS z?s{|ayHAA5rr(>p>%h5Jqa!EJu0JkDl)D?NU-}|B1!o%fuDuIUpLSjKdfoK*eNbqx zPrv&HNAp$b&F# zF{cXSnHTy$udm> zox}Y(%DfkP!6YAzn!TKK?3n32Pwc)pN5x^hzKpLz4yQve6K{0GSve<#d$H>*w7sm^ zV|6cI^P?OjacbS(-F458wLX8%BhIMf>~4J)i9Ylm3_sAwQ~Sy!3&(A_8>|>MB>8T- zcPF0ScZ?w=o@E2|vIG*wmffvSF|Tz`?XG5_?Akf&&N^9Q;7bNFW0N1`&227mAluR57ynSzZgsWVyx~LV~s24uQ{JxYzc(!DO*Xk>?xxQYvjgV z73DKY=uU{9@ZXe-e>px%?vy;=+mw91Oqw#;#TD?W@CY{hh4@W&PRGAEHG!w)`1dsY zW{IoixID4DIs?DSP7DQdt~{0FsSHoEoarcG_E&HaiYIv4#?#GsqSNbH&b@dtQvQG^ z>R^_09-1K?aL;na@I)utvz%w}Wcc24pBCXXh>2|!Pe$H!Z2p}kA-;|Kr-r&1b<3m= z%SFixB)d-^!;{J719)PdCp(Yf3A<)^`nAjVlKb>`Je?+SY`}M56Ypp6WTdRe`GIl? zo5WLvJbeI9CIx?YpH6{74Xz$f>_jI!J$Rz7XE|5nX`$dgfhWWFBRm(`pIPhNoJ2+K8u%<*5@- zb@H?YPgU~NgQpsK8o<*<@-&R6N_pCjr-VGc8&B2pG>WHsdBRBbEj&1vK7fwFX%HNr z-oS4Ge)`88`u{$FlE?q-PMrPtU58(}vzi6v{xJ-BP()6PONnQ-{XSRRow_1?53y@! z;PY}($$S@=Y%m7no3UX^*NC}JL&cU6&qk$70dAN%H5gerqW+C!G8La$X2xm zltSUdKllr`s^@`Q8Y(h|VGXRquQ#g5@X_Y~bHie(v(PvlNY?guwD+W>v9X5>6eJnh z0#6~MZEVw=b4xg&@$VwwwYywtQ1UPHcprXfxH7x}INc~(=KFF$w#+_2>Y(2i`6+ld zMb0Nv{h-AzMgZ&g=M>-25w$6#3;G0c>6l>jmZf>Kz{%O_w7R zft+eEFhBe|B25nFPLRW{hH@4_a*%28upTq?{lD#fEM3kt z;c0^$&DW7`%BWxd6*w`GVEhajoRMTEzr-Br@^DJPzo{ zV3@*t0~n_85kF=rQ~0DGLl);*7sI!$&<0yS|8ku>@RrOvZBHhrAG$ZRuc&e7@qM2v;okBEd8KjM!-K zA_-LY2j8vsv|=URuI3q$LhvJ017cwx3uC@VX+>|AHcS<9EMjQReSEMK{7`Lg9J z&ppS7#N(31i&v~z5sNKbxqPJ|ZJbh@lkePc#TDx-Z)Wdi{`?~^F&uaAG9>TcDaC=F znuP6V;p`7;&cCw4;g5ZPnNwWuAAyNKv(s_DYkBz2KjHI@R>WZ_clO?dz6NRIAA60M z)3^~?ISbby;;pqUI3BWU-pELIXDL3Z&zlgsu6ZqvkyM758)_@%oaDS1$AkU&G17HT zP6>c>*kAlxdI#Dz@9gO5A4-+tJ`Z*XczBqD&P@D!BQ&hgJDGD@)9EoTcze5d;#OCz z0#hcO;E@624Fp=i@b-_IV(Vqv`S)+qW14s7Wf;Fjq1i3Nu&*h{Z$J`*2Pem-GRwr) z!HRJ@rkjj#4gz)|Ragp5E#dt91R%_baGh;39{uC)bvjLe#Jdf@N{Mu=x6_n7r9kvA)^7h6RdBq#$ZitbIRNLJ>_&auXD7?T$5+8k_9$c^2<9W!bIXX-wnU zy<>SZrVO_4PP63k&EIK+;~BtHzVVFUu`MuRSq$OLvn<(c;hkl9CTtH+g=RB|H{S}) zY7|dnp0HKCn3bB@EFK#_brLp=hl{_0pNMh1g_d_h2J*D9#XT-mdc17n59(VS?J*$*ZahML`+E7kBX zl2lkV3K+O$4@^qH#4Y=5Mu`!^i*j|MKG6irD(t&RL`UxtYwG3tD-H2+prS;-fn3cc z`gt#md8~@VzEveA4Fx4vAr!uPG*l*V_tjjdRdmQQIY)eQrx_<_yoTUU$Q zICXNLh7Yu?!U2WU2(z^1;n~0a9OcPPPc-~A|ho{AYfw+9HtbM(20`c zq+jT##(4Q3U(5W5|C###mPELBc=c{Cl{N@cq}#V?Abt`=wW+7?u+=Pf^;j(#SbZaj zS&e{SIA)(5>LE!uJkM~{9m(n-Nyx5qIHg9rhf`{_gScXwbkBsJCPf`285PXC z<~3;JPa{!JNgBv_ljFpdVSF|KSvi>_b(tgq;9`#Lgm`t4WCVF`=GY=gSNBLlPjfZL z-i8qdj0!3;U{#Ryo$}P3lF0MBrQ>i&2KA-nG4NiP@k_@#NFMd2WD*VEbXpPAK%p|K zGbLf9v$|8Q1ofaKgeY%yntyepWReqhSEuo+aYNOrI#!ZUJ_mMMLDjL6(ABw?II&Yb zscR+S@Vl|ogsER8VMz01r`l8xOTr}{e>_ii>|0rQertxTE}sJqV_?8C9UD3E7}nCP z({Tbt8U{4b>Ju>S;@(9}tcPvbW=C1F7^%}3Fh)@d?;X;TOl?g?3%;tF7%)VECe{xa z15D-M?g_4eg0rp>CJJGJQOv|)rq9_26NM29K@#g>DLPSGh1+&l0RIFY)ZhQW()2Z84c!+2JINK+oLZ&td2L(rcct?abc|_I?a>| zV;})5WW%pM#4yh>6fBYrh1MhGLLcL17%Y+vg{FW|!`XonA8FHt)#6SNas3(wOI%}M z@$%+|+SV4>)oH4cH4=G32CKwcg2c=!N`{a{Dlt{UK}tphGK9=XT|##j?E2~I#H1i# zGKE?r$yhQI60N2%qeO=drzk#bJY^a9?-BlSEd9_RN1{m#63MjdufBPyT

})zo9ntIJ)|b+i+@-ya||LcA(g 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
  • X?LW3rRnQgjkkJy16tu{<$<-=TTTc!xLI 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 URdM_d|E> -- hpdf.h + * + * URL http://libharu.org/ + * + * Copyright (c) 1999-2006 Takeshi Kanno + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_H +#define _HPDF_H + +#include "hpdf_config.h" +#include "hpdf_version.h" + +#define HPDF_UNUSED(a) ((void)(a)) + +#ifdef HPDF_DLL_MAKE +# define HPDF_EXPORT(A) __declspec(dllexport) A __stdcall +#else +# ifdef HPDF_DLL_MAKE_CDECL +# define HPDF_EXPORT(A) __declspec(dllexport) A +# else +# ifdef HPDF_SHARED_MAKE +# define HPDF_EXPORT(A) extern A +# endif /* HPDF_SHARED_MAKE */ +# endif /* HPDF_DLL_MAKE_CDECL */ +#endif /* HPDF_DLL_MAKE */ + +#ifdef HPDF_DLL +# define HPDF_SHARED +# define HPDF_EXPORT(A) __declspec(dllimport) A __stdcall +#else +# ifdef HPDF_DLL_CDECL +# define HPDF_SHARED +# define HPDF_EXPORT(A) __declspec(dllimport) A +# endif /* HPDF_DLL_CDECL */ +#endif /* HPDF_DLL */ + +#ifdef HPDF_SHARED + +#ifndef HPDF_EXPORT +#define HPDF_EXPORT(A) extern A +#endif /* HPDF_EXPORT */ + +#include "hpdf_consts.h" +#include "hpdf_types.h" + +typedef void *HPDF_HANDLE; +typedef HPDF_HANDLE HPDF_Doc; +typedef HPDF_HANDLE HPDF_Page; +typedef HPDF_HANDLE HPDF_Pages; +typedef HPDF_HANDLE HPDF_Stream; +typedef HPDF_HANDLE HPDF_Image; +typedef HPDF_HANDLE HPDF_Font; +typedef HPDF_HANDLE HPDF_Outline; +typedef HPDF_HANDLE HPDF_Encoder; +typedef HPDF_HANDLE HPDF_3DMeasure; +typedef HPDF_HANDLE HPDF_ExData; +typedef HPDF_HANDLE HPDF_Destination; +typedef HPDF_HANDLE HPDF_XObject; +typedef HPDF_HANDLE HPDF_Annotation; +typedef HPDF_HANDLE HPDF_ExtGState; +typedef HPDF_HANDLE HPDF_FontDef; +typedef HPDF_HANDLE HPDF_U3D; +typedef HPDF_HANDLE HPDF_JavaScript; +typedef HPDF_HANDLE HPDF_Error; +typedef HPDF_HANDLE HPDF_MMgr; +typedef HPDF_HANDLE HPDF_Dict; +typedef HPDF_HANDLE HPDF_EmbeddedFile; +typedef HPDF_HANDLE HPDF_OutputIntent; +typedef HPDF_HANDLE HPDF_Xref; + +#else + +#ifndef HPDF_EXPORT +#define HPDF_EXPORT(A) A +#endif /* HPDF_EXPORT */ + +#include "hpdf_consts.h" +#include "hpdf_doc.h" +#include "hpdf_error.h" +#include "hpdf_pdfa.h" + +#endif /* HPDF_SHARED */ + +#ifdef __cplusplus +extern "C" { +#endif + +HPDF_EXPORT(const char *) +HPDF_GetVersion (void); + + +HPDF_EXPORT(HPDF_Doc) +HPDF_NewEx (HPDF_Error_Handler user_error_fn, + HPDF_Alloc_Func user_alloc_fn, + HPDF_Free_Func user_free_fn, + HPDF_UINT mem_pool_buf_size, + void *user_data); + +HPDF_EXPORT(HPDF_Doc) +HPDF_New (HPDF_Error_Handler user_error_fn, + void *user_data); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetErrorHandler (HPDF_Doc pdf, + HPDF_Error_Handler user_error_fn); + + +HPDF_EXPORT(void) +HPDF_Free (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_NewDoc (HPDF_Doc pdf); + + +HPDF_EXPORT(void) +HPDF_FreeDoc (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_BOOL) +HPDF_HasDoc (HPDF_Doc pdf); + + +HPDF_EXPORT(void) +HPDF_FreeDocAll (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SaveToStream (HPDF_Doc pdf); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_GetContents (HPDF_Doc pdf, + HPDF_BYTE *buf, + HPDF_UINT32 *size); + +HPDF_EXPORT(HPDF_UINT32) +HPDF_GetStreamSize (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_ReadFromStream (HPDF_Doc pdf, + HPDF_BYTE *buf, + HPDF_UINT32 *size); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_ResetStream (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SaveToFile (HPDF_Doc pdf, + const char *file_name); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_GetError (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_GetErrorDetail (HPDF_Doc pdf); + +HPDF_EXPORT(void) +HPDF_ResetError (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_CheckError (HPDF_Error error); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetPagesConfiguration (HPDF_Doc pdf, + HPDF_UINT page_per_pages); + + +HPDF_EXPORT(HPDF_Page) +HPDF_GetPageByIndex (HPDF_Doc pdf, + HPDF_UINT index); + + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_PageLayout) +HPDF_GetPageLayout (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetPageLayout (HPDF_Doc pdf, + HPDF_PageLayout layout); + + +HPDF_EXPORT(HPDF_PageMode) +HPDF_GetPageMode (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetPageMode (HPDF_Doc pdf, + HPDF_PageMode mode); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_GetViewerPreference (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetViewerPreference (HPDF_Doc pdf, + HPDF_UINT value); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetOpenAction (HPDF_Doc pdf, + HPDF_Destination open_action); + + +/*---------------------------------------------------------------------------*/ +/*----- page handling -------------------------------------------------------*/ + + +HPDF_EXPORT(HPDF_Page) +HPDF_GetCurrentPage (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_Page) +HPDF_AddPage (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_Page) +HPDF_InsertPage (HPDF_Doc pdf, + HPDF_Page page); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetWidth (HPDF_Page page, + HPDF_REAL value); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetHeight (HPDF_Page page, + HPDF_REAL value); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetSize (HPDF_Page page, + HPDF_PageSizes size, + HPDF_PageDirection direction); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetRotate (HPDF_Page page, + HPDF_UINT16 angle); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetZoom (HPDF_Page page, + HPDF_REAL zoom); + +/*---------------------------------------------------------------------------*/ +/*----- font handling -------------------------------------------------------*/ + + +HPDF_EXPORT(HPDF_Font) +HPDF_GetFont (HPDF_Doc pdf, + const char *font_name, + const char *encoding_name); + + +HPDF_EXPORT(const char*) +HPDF_LoadType1FontFromFile (HPDF_Doc pdf, + const char *afm_file_name, + const char *data_file_name); + + +HPDF_EXPORT(HPDF_FontDef) +HPDF_GetTTFontDefFromFile (HPDF_Doc pdf, + const char *file_name, + HPDF_BOOL embedding); + +HPDF_EXPORT(const char*) +HPDF_LoadTTFontFromFile (HPDF_Doc pdf, + const char *file_name, + HPDF_BOOL embedding); + + +HPDF_EXPORT(const char*) +HPDF_LoadTTFontFromFile2 (HPDF_Doc pdf, + const char *file_name, + HPDF_UINT index, + HPDF_BOOL embedding); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_AddPageLabel (HPDF_Doc pdf, + HPDF_UINT page_num, + HPDF_PageNumStyle style, + HPDF_UINT first_page, + const char *prefix); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseJPFonts (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseKRFonts (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseCNSFonts (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseCNTFonts (HPDF_Doc pdf); + + +/*--------------------------------------------------------------------------*/ +/*----- outline ------------------------------------------------------------*/ + + +HPDF_EXPORT(HPDF_Outline) +HPDF_CreateOutline (HPDF_Doc pdf, + HPDF_Outline parent, + const char *title, + HPDF_Encoder encoder); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Outline_SetOpened (HPDF_Outline outline, + HPDF_BOOL opened); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Outline_SetDestination (HPDF_Outline outline, + HPDF_Destination dst); + + +/*--------------------------------------------------------------------------*/ +/*----- destination --------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_Destination) +HPDF_Page_CreateDestination (HPDF_Page page); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetXYZ (HPDF_Destination dst, + HPDF_REAL left, + HPDF_REAL top, + HPDF_REAL zoom); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFit (HPDF_Destination dst); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFitH (HPDF_Destination dst, + HPDF_REAL top); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFitV (HPDF_Destination dst, + HPDF_REAL left); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFitR (HPDF_Destination dst, + HPDF_REAL left, + HPDF_REAL bottom, + HPDF_REAL right, + HPDF_REAL top); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFitB (HPDF_Destination dst); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFitBH (HPDF_Destination dst, + HPDF_REAL top); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Destination_SetFitBV (HPDF_Destination dst, + HPDF_REAL left); + +/*--------------------------------------------------------------------------*/ +/*----- encoder ------------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_Encoder) +HPDF_GetEncoder (HPDF_Doc pdf, + const char *encoding_name); + + +HPDF_EXPORT(HPDF_Encoder) +HPDF_GetCurrentEncoder (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetCurrentEncoder (HPDF_Doc pdf, + const char *encoding_name); + + +HPDF_EXPORT(HPDF_EncoderType) +HPDF_Encoder_GetType (HPDF_Encoder encoder); + + +HPDF_EXPORT(HPDF_ByteType) +HPDF_Encoder_GetByteType (HPDF_Encoder encoder, + const char *text, + HPDF_UINT index); + + +HPDF_EXPORT(HPDF_UNICODE) +HPDF_Encoder_GetUnicode (HPDF_Encoder encoder, + HPDF_UINT16 code); + + +HPDF_EXPORT(HPDF_WritingMode) +HPDF_Encoder_GetWritingMode (HPDF_Encoder encoder); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseJPEncodings (HPDF_Doc pdf); + + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseKREncodings (HPDF_Doc pdf); + + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseCNSEncodings (HPDF_Doc pdf); + + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseCNTEncodings (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_UseUTFEncodings (HPDF_Doc pdf); + + +/*--------------------------------------------------------------------------*/ +/*----- annotation ---------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_Create3DAnnot (HPDF_Page page, + HPDF_Rect rect, + HPDF_U3D u3d); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateTextAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateFreeTextAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateLineAnnot (HPDF_Page page, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateLinkAnnot (HPDF_Page page, + HPDF_Rect rect, + HPDF_Destination dst); + + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateURILinkAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *uri); + + +HPDF_Annotation +HPDF_Page_CreateTextMarkupAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder, + HPDF_AnnotType subType); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateHighlightAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateUnderlineAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateSquigglyAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateStrikeOutAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreatePopupAnnot ( HPDF_Page page, + HPDF_Rect rect, + HPDF_Annotation parent); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateStampAnnot ( HPDF_Page page, + HPDF_Rect rect, + HPDF_StampAnnotName name, + const char* text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateProjectionAnnot(HPDF_Page page, + HPDF_Rect rect, + const char* text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateSquareAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_Annotation) +HPDF_Page_CreateCircleAnnot (HPDF_Page page, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_LinkAnnot_SetHighlightMode (HPDF_Annotation annot, + HPDF_AnnotHighlightMode mode); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_LinkAnnot_SetBorderStyle (HPDF_Annotation annot, + HPDF_REAL width, + HPDF_UINT16 dash_on, + HPDF_UINT16 dash_off); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_TextAnnot_SetIcon (HPDF_Annotation annot, + HPDF_AnnotIcon icon); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_TextAnnot_SetOpened (HPDF_Annotation annot, + HPDF_BOOL opened); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Annot_SetRGBColor (HPDF_Annotation annot, HPDF_RGBColor color); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Annot_SetCMYKColor (HPDF_Annotation annot, HPDF_CMYKColor color); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Annot_SetGrayColor (HPDF_Annotation annot, HPDF_REAL color); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Annot_SetNoColor (HPDF_Annotation annot); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetTitle (HPDF_Annotation annot, const char* name); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetSubject (HPDF_Annotation annot, const char* name); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetCreationDate (HPDF_Annotation annot, HPDF_Date value); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetTransparency (HPDF_Annotation annot, HPDF_REAL value); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetIntent (HPDF_Annotation annot, HPDF_AnnotIntent intent); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetPopup (HPDF_Annotation annot, HPDF_Annotation popup); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetRectDiff (HPDF_Annotation annot, HPDF_Rect rect); /* RD entry */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetCloudEffect (HPDF_Annotation annot, HPDF_INT cloudIntensity); /* BE entry */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetInteriorRGBColor (HPDF_Annotation annot, HPDF_RGBColor color); /* IC with RGB entry */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetInteriorCMYKColor (HPDF_Annotation annot, HPDF_CMYKColor color); /* IC with CMYK entry */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetInteriorGrayColor (HPDF_Annotation annot, HPDF_REAL color); /* IC with Gray entry */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_MarkupAnnot_SetInteriorTransparent (HPDF_Annotation annot); /* IC with No Color entry */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_TextMarkupAnnot_SetQuadPoints ( HPDF_Annotation annot, HPDF_Point lb, HPDF_Point rb, HPDF_Point rt, HPDF_Point lt); /* l-left, r-right, b-bottom, t-top positions */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Annot_Set3DView ( HPDF_MMgr mmgr, + HPDF_Annotation annot, + HPDF_Annotation annot3d, + HPDF_Dict view); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_PopupAnnot_SetOpened (HPDF_Annotation annot, + HPDF_BOOL opened); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_FreeTextAnnot_SetLineEndingStyle (HPDF_Annotation annot, HPDF_LineAnnotEndingStyle startStyle, HPDF_LineAnnotEndingStyle endStyle); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_FreeTextAnnot_Set3PointCalloutLine (HPDF_Annotation annot, HPDF_Point startPoint, HPDF_Point kneePoint, HPDF_Point endPoint); /* Callout line will be in default user space */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_FreeTextAnnot_Set2PointCalloutLine (HPDF_Annotation annot, HPDF_Point startPoint, HPDF_Point endPoint); /* Callout line will be in default user space */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_FreeTextAnnot_SetDefaultStyle (HPDF_Annotation annot, const char* style); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_LineAnnot_SetPosition (HPDF_Annotation annot, + HPDF_Point startPoint, HPDF_LineAnnotEndingStyle startStyle, + HPDF_Point endPoint, HPDF_LineAnnotEndingStyle endStyle); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_LineAnnot_SetLeader (HPDF_Annotation annot, HPDF_INT leaderLen, HPDF_INT leaderExtLen, HPDF_INT leaderOffsetLen); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_LineAnnot_SetCaption (HPDF_Annotation annot, HPDF_BOOL showCaption, HPDF_LineAnnotCapPosition position, HPDF_INT horzOffset, HPDF_INT vertOffset); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Annotation_SetBorderStyle (HPDF_Annotation annot, + HPDF_BSSubtype subtype, + HPDF_REAL width, + HPDF_UINT16 dash_on, + HPDF_UINT16 dash_off, + HPDF_UINT16 dash_phase); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_ProjectionAnnot_SetExData(HPDF_Annotation annot, HPDF_ExData exdata); + + +/*--------------------------------------------------------------------------*/ +/*----- 3D Measure ---------------------------------------------------------*/ +HPDF_EXPORT(HPDF_3DMeasure) +HPDF_Page_Create3DC3DMeasure(HPDF_Page page, + HPDF_Point3D firstanchorpoint, + HPDF_Point3D textanchorpoint + ); + +HPDF_EXPORT(HPDF_3DMeasure) +HPDF_Page_CreatePD33DMeasure(HPDF_Page page, + HPDF_Point3D annotationPlaneNormal, + HPDF_Point3D firstAnchorPoint, + HPDF_Point3D secondAnchorPoint, + HPDF_Point3D leaderLinesDirection, + HPDF_Point3D measurementValuePoint, + HPDF_Point3D textYDirection, + HPDF_REAL value, + const char* unitsString + ); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DMeasure_SetName(HPDF_3DMeasure measure, + const char* name); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DMeasure_SetColor(HPDF_3DMeasure measure, + HPDF_RGBColor color); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DMeasure_SetTextSize(HPDF_3DMeasure measure, + HPDF_REAL textsize); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DC3DMeasure_SetTextBoxSize(HPDF_3DMeasure measure, + HPDF_INT32 x, + HPDF_INT32 y); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DC3DMeasure_SetText(HPDF_3DMeasure measure, + const char* text, + HPDF_Encoder encoder); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DC3DMeasure_SetProjectionAnotation(HPDF_3DMeasure measure, + HPDF_Annotation projectionanotation); + +/*--------------------------------------------------------------------------*/ +/*----- External Data ---------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_ExData) +HPDF_Page_Create3DAnnotExData(HPDF_Page page ); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DAnnotExData_Set3DMeasurement(HPDF_ExData exdata, HPDF_3DMeasure measure); + +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +/*----- 3D View ---------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_Dict) +HPDF_Page_Create3DView (HPDF_Page page, + HPDF_U3D u3d, + HPDF_Annotation annot3d, + const char *name); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_3DView_Add3DC3DMeasure(HPDF_Dict view, + HPDF_3DMeasure measure); + +/*--------------------------------------------------------------------------*/ +/*----- image data ---------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadPngImageFromMem (HPDF_Doc pdf, + const HPDF_BYTE *buffer, + HPDF_UINT size); + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadPngImageFromFile (HPDF_Doc pdf, + const char *filename); + + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadPngImageFromFile2 (HPDF_Doc pdf, + const char *filename); + + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadJpegImageFromFile (HPDF_Doc pdf, + const char *filename); + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadJpegImageFromMem (HPDF_Doc pdf, + const HPDF_BYTE *buffer, + HPDF_UINT size); + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadU3DFromFile (HPDF_Doc pdf, + const char *filename); + +HPDF_EXPORT(HPDF_Image) +HPDF_Image_LoadRaw1BitImageFromMem (HPDF_Doc pdf, + const HPDF_BYTE *buf, + HPDF_UINT width, + HPDF_UINT height, + HPDF_UINT line_width, + HPDF_BOOL black_is1, + HPDF_BOOL top_is_first); + + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadRawImageFromFile (HPDF_Doc pdf, + const char *filename, + HPDF_UINT width, + HPDF_UINT height, + HPDF_ColorSpace color_space); + + +HPDF_EXPORT(HPDF_Image) +HPDF_LoadRawImageFromMem (HPDF_Doc pdf, + const HPDF_BYTE *buf, + HPDF_UINT width, + HPDF_UINT height, + HPDF_ColorSpace color_space, + HPDF_UINT bits_per_component); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Image_AddSMask (HPDF_Image image, + HPDF_Image smask); + +HPDF_EXPORT(HPDF_Point) +HPDF_Image_GetSize (HPDF_Image image); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Image_GetSize2 (HPDF_Image image, HPDF_Point *size); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Image_GetWidth (HPDF_Image image); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Image_GetHeight (HPDF_Image image); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Image_GetBitsPerComponent (HPDF_Image image); + + +HPDF_EXPORT(const char*) +HPDF_Image_GetColorSpace (HPDF_Image image); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Image_SetColorMask (HPDF_Image image, + HPDF_UINT rmin, + HPDF_UINT rmax, + HPDF_UINT gmin, + HPDF_UINT gmax, + HPDF_UINT bmin, + HPDF_UINT bmax); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Image_SetMaskImage (HPDF_Image image, + HPDF_Image mask_image); + + +/*--------------------------------------------------------------------------*/ +/*----- info dictionary ----------------------------------------------------*/ + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetInfoAttr (HPDF_Doc pdf, + HPDF_InfoType type, + const char *value); + + +HPDF_EXPORT(const char*) +HPDF_GetInfoAttr (HPDF_Doc pdf, + HPDF_InfoType type); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetInfoDateAttr (HPDF_Doc pdf, + HPDF_InfoType type, + HPDF_Date value); + + +/*--------------------------------------------------------------------------*/ +/*----- encryption ---------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetPassword (HPDF_Doc pdf, + const char *owner_passwd, + const char *user_passwd); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetPermission (HPDF_Doc pdf, + HPDF_UINT permission); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetEncryptionMode (HPDF_Doc pdf, + HPDF_EncryptMode mode, + HPDF_UINT key_len); + + +/*--------------------------------------------------------------------------*/ +/*----- compression --------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_SetCompressionMode (HPDF_Doc pdf, + HPDF_UINT mode); + + +/*--------------------------------------------------------------------------*/ +/*----- font ---------------------------------------------------------------*/ + +HPDF_EXPORT(const char*) +HPDF_Font_GetFontName (HPDF_Font font); + + +HPDF_EXPORT(const char*) +HPDF_Font_GetEncodingName (HPDF_Font font); + + +HPDF_EXPORT(HPDF_INT) +HPDF_Font_GetUnicodeWidth (HPDF_Font font, + HPDF_UNICODE code); + +HPDF_EXPORT(HPDF_Box) +HPDF_Font_GetBBox (HPDF_Font font); + + +HPDF_EXPORT(HPDF_INT) +HPDF_Font_GetAscent (HPDF_Font font); + + +HPDF_EXPORT(HPDF_INT) +HPDF_Font_GetDescent (HPDF_Font font); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Font_GetXHeight (HPDF_Font font); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Font_GetCapHeight (HPDF_Font font); + + +HPDF_EXPORT(HPDF_TextWidth) +HPDF_Font_TextWidth (HPDF_Font font, + const HPDF_BYTE *text, + HPDF_UINT len); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Font_MeasureText (HPDF_Font font, + const HPDF_BYTE *text, + HPDF_UINT len, + HPDF_REAL width, + HPDF_REAL font_size, + HPDF_REAL char_space, + HPDF_REAL word_space, + HPDF_BOOL wordwrap, + HPDF_REAL *real_width); + + +/*--------------------------------------------------------------------------*/ +/*----- attachements -------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_EmbeddedFile) +HPDF_AttachFile (HPDF_Doc pdf, + const char *file); + + +/*--------------------------------------------------------------------------*/ +/*----- extended graphics state --------------------------------------------*/ + +HPDF_EXPORT(HPDF_ExtGState) +HPDF_CreateExtGState (HPDF_Doc pdf); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_ExtGState_SetAlphaStroke (HPDF_ExtGState ext_gstate, + HPDF_REAL value); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_ExtGState_SetAlphaFill (HPDF_ExtGState ext_gstate, + HPDF_REAL value); + + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_ExtGState_SetBlendMode (HPDF_ExtGState ext_gstate, + HPDF_BlendMode mode); + + +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_TextWidth (HPDF_Page page, + const char *text); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Page_MeasureText (HPDF_Page page, + const char *text, + HPDF_REAL width, + HPDF_BOOL wordwrap, + HPDF_REAL *real_width); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetWidth (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetHeight (HPDF_Page page); + + +HPDF_EXPORT(HPDF_UINT16) +HPDF_Page_GetGMode (HPDF_Page page); + + +HPDF_EXPORT(HPDF_Point) +HPDF_Page_GetCurrentPos (HPDF_Page page); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_GetCurrentPos2 (HPDF_Page page, + HPDF_Point *pos); + + +HPDF_EXPORT(HPDF_Point) +HPDF_Page_GetCurrentTextPos (HPDF_Page page); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_GetCurrentTextPos2 (HPDF_Page page, + HPDF_Point *pos); + + +HPDF_EXPORT(HPDF_Font) +HPDF_Page_GetCurrentFont (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetCurrentFontSize (HPDF_Page page); + + +HPDF_EXPORT(HPDF_TransMatrix) +HPDF_Page_GetTransMatrix (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetLineWidth (HPDF_Page page); + + +HPDF_EXPORT(HPDF_LineCap) +HPDF_Page_GetLineCap (HPDF_Page page); + + +HPDF_EXPORT(HPDF_LineJoin) +HPDF_Page_GetLineJoin (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetMiterLimit (HPDF_Page page); + + +HPDF_EXPORT(HPDF_DashMode) +HPDF_Page_GetDash (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetFlat (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetCharSpace (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetWordSpace (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetHorizontalScalling (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetTextLeading (HPDF_Page page); + + +HPDF_EXPORT(HPDF_TextRenderingMode) +HPDF_Page_GetTextRenderingMode (HPDF_Page page); + + +/* This function is obsolete. Use HPDF_Page_GetTextRise. */ +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetTextRaise (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetTextRise (HPDF_Page page); + + +HPDF_EXPORT(HPDF_RGBColor) +HPDF_Page_GetRGBFill (HPDF_Page page); + + +HPDF_EXPORT(HPDF_RGBColor) +HPDF_Page_GetRGBStroke (HPDF_Page page); + + +HPDF_EXPORT(HPDF_CMYKColor) +HPDF_Page_GetCMYKFill (HPDF_Page page); + + +HPDF_EXPORT(HPDF_CMYKColor) +HPDF_Page_GetCMYKStroke (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetGrayFill (HPDF_Page page); + + +HPDF_EXPORT(HPDF_REAL) +HPDF_Page_GetGrayStroke (HPDF_Page page); + + +HPDF_EXPORT(HPDF_ColorSpace) +HPDF_Page_GetStrokingColorSpace (HPDF_Page page); + + +HPDF_EXPORT(HPDF_ColorSpace) +HPDF_Page_GetFillingColorSpace (HPDF_Page page); + + +HPDF_EXPORT(HPDF_TransMatrix) +HPDF_Page_GetTextMatrix (HPDF_Page page); + + +HPDF_EXPORT(HPDF_UINT) +HPDF_Page_GetGStateDepth (HPDF_Page page); + + +/*--------------------------------------------------------------------------*/ +/*----- GRAPHICS OPERATORS -------------------------------------------------*/ + + +/*--- General graphics state ---------------------------------------------*/ + +/* w */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetLineWidth (HPDF_Page page, + HPDF_REAL line_width); + +/* J */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetLineCap (HPDF_Page page, + HPDF_LineCap line_cap); + +/* j */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetLineJoin (HPDF_Page page, + HPDF_LineJoin line_join); + +/* M */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetMiterLimit (HPDF_Page page, + HPDF_REAL miter_limit); + +/* d */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetDash (HPDF_Page page, + const HPDF_UINT16 *dash_ptn, + HPDF_UINT num_param, + HPDF_UINT phase); + + + +/* ri --not implemented yet */ + +/* i */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetFlat (HPDF_Page page, + HPDF_REAL flatness); + +/* gs */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetExtGState (HPDF_Page page, + HPDF_ExtGState ext_gstate); + + +/*--- Special graphic state operator --------------------------------------*/ + +/* q */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_GSave (HPDF_Page page); + +/* Q */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_GRestore (HPDF_Page page); + +/* cm */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Concat (HPDF_Page page, + HPDF_REAL a, + HPDF_REAL b, + HPDF_REAL c, + HPDF_REAL d, + HPDF_REAL x, + HPDF_REAL y); + +/*--- Path construction operator ------------------------------------------*/ + +/* m */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_MoveTo (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y); + +/* l */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_LineTo (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y); + +/* c */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_CurveTo (HPDF_Page page, + HPDF_REAL x1, + HPDF_REAL y1, + HPDF_REAL x2, + HPDF_REAL y2, + HPDF_REAL x3, + HPDF_REAL y3); + +/* v */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_CurveTo2 (HPDF_Page page, + HPDF_REAL x2, + HPDF_REAL y2, + HPDF_REAL x3, + HPDF_REAL y3); + +/* y */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_CurveTo3 (HPDF_Page page, + HPDF_REAL x1, + HPDF_REAL y1, + HPDF_REAL x3, + HPDF_REAL y3); + +/* h */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ClosePath (HPDF_Page page); + +/* re */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Rectangle (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y, + HPDF_REAL width, + HPDF_REAL height); + + +/*--- Path painting operator ---------------------------------------------*/ + +/* S */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Stroke (HPDF_Page page); + +/* s */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ClosePathStroke (HPDF_Page page); + +/* f */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Fill (HPDF_Page page); + +/* f* */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Eofill (HPDF_Page page); + +/* B */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_FillStroke (HPDF_Page page); + +/* B* */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_EofillStroke (HPDF_Page page); + +/* b */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ClosePathFillStroke (HPDF_Page page); + +/* b* */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ClosePathEofillStroke (HPDF_Page page); + +/* n */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_EndPath (HPDF_Page page); + + +/*--- Clipping paths operator --------------------------------------------*/ + +/* W */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Clip (HPDF_Page page); + +/* W* */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Eoclip (HPDF_Page page); + + +/*--- Text object operator -----------------------------------------------*/ + +/* BT */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_BeginText (HPDF_Page page); + +/* ET */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_EndText (HPDF_Page page); + +/*--- Text state ---------------------------------------------------------*/ + +/* Tc */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetCharSpace (HPDF_Page page, + HPDF_REAL value); + +/* Tw */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetWordSpace (HPDF_Page page, + HPDF_REAL value); + +/* Tz */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetHorizontalScalling (HPDF_Page page, + HPDF_REAL value); + +/* TL */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetTextLeading (HPDF_Page page, + HPDF_REAL value); + +/* Tf */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetFontAndSize (HPDF_Page page, + HPDF_Font font, + HPDF_REAL size); + +/* Tr */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetTextRenderingMode (HPDF_Page page, + HPDF_TextRenderingMode mode); + +/* Ts */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetTextRise (HPDF_Page page, + HPDF_REAL value); + +/* This function is obsolete. Use HPDF_Page_SetTextRise. */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetTextRaise (HPDF_Page page, + HPDF_REAL value); + +/*--- Text positioning ---------------------------------------------------*/ + +/* Td */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_MoveTextPos (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y); + +/* TD */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_MoveTextPos2 (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y); + +/* Tm */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetTextMatrix (HPDF_Page page, + HPDF_REAL a, + HPDF_REAL b, + HPDF_REAL c, + HPDF_REAL d, + HPDF_REAL x, + HPDF_REAL y); + + +/* T* */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_MoveToNextLine (HPDF_Page page); + +/*--- Text showing -------------------------------------------------------*/ + +/* Tj */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ShowText (HPDF_Page page, + const char *text); + +/* TJ */ + +/* ' */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ShowTextNextLine (HPDF_Page page, + const char *text); + +/* " */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ShowTextNextLineEx (HPDF_Page page, + HPDF_REAL word_space, + HPDF_REAL char_space, + const char *text); + + +/*--- Color showing ------------------------------------------------------*/ + +/* cs --not implemented yet */ +/* CS --not implemented yet */ +/* sc --not implemented yet */ +/* scn --not implemented yet */ +/* SC --not implemented yet */ +/* SCN --not implemented yet */ + +/* g */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetGrayFill (HPDF_Page page, + HPDF_REAL gray); + +/* G */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetGrayStroke (HPDF_Page page, + HPDF_REAL gray); + +/* rg */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetRGBFill (HPDF_Page page, + HPDF_REAL r, + HPDF_REAL g, + HPDF_REAL b); + +/* RG */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetRGBStroke (HPDF_Page page, + HPDF_REAL r, + HPDF_REAL g, + HPDF_REAL b); + +/* k */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetCMYKFill (HPDF_Page page, + HPDF_REAL c, + HPDF_REAL m, + HPDF_REAL y, + HPDF_REAL k); + +/* K */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetCMYKStroke (HPDF_Page page, + HPDF_REAL c, + HPDF_REAL m, + HPDF_REAL y, + HPDF_REAL k); + +/*--- Shading patterns ---------------------------------------------------*/ + +/* sh --not implemented yet */ + +/*--- In-line images -----------------------------------------------------*/ + +/* BI --not implemented yet */ +/* ID --not implemented yet */ +/* EI --not implemented yet */ + +/*--- XObjects -----------------------------------------------------------*/ + +/* Do */ +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_ExecuteXObject (HPDF_Page page, + HPDF_XObject obj); + +/*--- Content streams ----------------------------------------------------*/ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_New_Content_Stream (HPDF_Page page, + HPDF_Dict* new_stream); + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Insert_Shared_Content_Stream (HPDF_Page page, + HPDF_Dict shared_stream); + + +/*--- Marked content -----------------------------------------------------*/ + +/* BMC --not implemented yet */ +/* BDC --not implemented yet */ +/* EMC --not implemented yet */ +/* MP --not implemented yet */ +/* DP --not implemented yet */ + +/*--- Compatibility ------------------------------------------------------*/ + +/* BX --not implemented yet */ +/* EX --not implemented yet */ + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_DrawImage (HPDF_Page page, + HPDF_Image image, + HPDF_REAL x, + HPDF_REAL y, + HPDF_REAL width, + HPDF_REAL height); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Circle (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y, + HPDF_REAL ray); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Ellipse (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y, + HPDF_REAL xray, + HPDF_REAL yray); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_Arc (HPDF_Page page, + HPDF_REAL x, + HPDF_REAL y, + HPDF_REAL ray, + HPDF_REAL ang1, + HPDF_REAL ang2); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_TextOut (HPDF_Page page, + HPDF_REAL xpos, + HPDF_REAL ypos, + const char *text); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_TextRect (HPDF_Page page, + HPDF_REAL left, + HPDF_REAL top, + HPDF_REAL right, + HPDF_REAL bottom, + const char *text, + HPDF_TextAlignment align, + HPDF_UINT *len); + + +HPDF_EXPORT(HPDF_STATUS) +HPDF_Page_SetSlideShow (HPDF_Page page, + HPDF_TransitionStyle type, + HPDF_REAL disp_time, + HPDF_REAL trans_time); + + +HPDF_EXPORT(HPDF_OutputIntent) +HPDF_ICC_LoadIccFromMem (HPDF_Doc pdf, + HPDF_MMgr mmgr, + HPDF_Stream iccdata, + HPDF_Xref xref, + int numcomponent); + +HPDF_EXPORT(HPDF_OutputIntent) +HPDF_LoadIccProfileFromFile (HPDF_Doc pdf, + const char* icc_file_name, + int numcomponent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_H */ + diff --git a/code/libharu/hpdf_3dmeasure.h b/code/libharu/hpdf_3dmeasure.h new file mode 100644 index 0000000..1f3d8ba --- /dev/null +++ b/code/libharu/hpdf_3dmeasure.h @@ -0,0 +1,57 @@ +/* + * << Haru Free PDF Library >> -- hpdf_annotation.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_3DMEASURE_H +#define _HPDF_3DMEASURE_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*------ HPDF_3DMeasure -----------------------------------------------------*/ + + +HPDF_3DMeasure +HPDF_3DC3DMeasure_New(HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Point3D firstanchorpoint, + HPDF_Point3D textanchorpoint + ); + +HPDF_3DMeasure +HPDF_PD33DMeasure_New(HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Point3D annotationPlaneNormal, + HPDF_Point3D firstAnchorPoint, + HPDF_Point3D secondAnchorPoint, + HPDF_Point3D leaderLinesDirection, + HPDF_Point3D measurementValuePoint, + HPDF_Point3D textYDirection, + HPDF_REAL value, + const char* unitsString + ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_3DMEASURE_H */ + diff --git a/code/libharu/hpdf_annotation.h b/code/libharu/hpdf_annotation.h new file mode 100644 index 0000000..febd1f8 --- /dev/null +++ b/code/libharu/hpdf_annotation.h @@ -0,0 +1,95 @@ +/* + * << Haru Free PDF Library >> -- hpdf_annotation.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_ANNOTATION_H +#define _HPDF_ANNOTATION_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*------ HPDF_Annotation -----------------------------------------------------*/ + + +HPDF_Annotation +HPDF_Annotation_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_AnnotType type, + HPDF_Rect rect); + + +HPDF_Annotation +HPDF_LinkAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + HPDF_Destination dst); + + +HPDF_Annotation +HPDF_URILinkAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + const char *uri); + + +HPDF_Annotation +HPDF_3DAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + HPDF_U3D u3d); + +HPDF_Annotation +HPDF_MarkupAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + const char *text, + HPDF_Encoder encoder, + HPDF_AnnotType subtype); + +HPDF_Annotation +HPDF_PopupAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + HPDF_Annotation parent); + +HPDF_Annotation +HPDF_StampAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + HPDF_StampAnnotName name, + const char* text, + HPDF_Encoder encoder); + +HPDF_Annotation +HPDF_ProjectionAnnot_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_Rect rect, + const char* text, + HPDF_Encoder encoder); + +HPDF_BOOL +HPDF_Annotation_Validate (HPDF_Annotation annot); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_ANNOTATION_H */ + diff --git a/code/libharu/hpdf_catalog.h b/code/libharu/hpdf_catalog.h new file mode 100644 index 0000000..91ad034 --- /dev/null +++ b/code/libharu/hpdf_catalog.h @@ -0,0 +1,93 @@ +/* + * << Haru Free PDF Library >> -- hpdf_catalog.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_CATALOG_H +#define _HPDF_CATALOG_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef HPDF_Dict HPDF_Catalog; + +HPDF_Catalog +HPDF_Catalog_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + + +HPDF_NameDict +HPDF_Catalog_GetNames (HPDF_Catalog catalog); + + +HPDF_STATUS +HPDF_Catalog_SetNames (HPDF_Catalog catalog, + HPDF_NameDict dict); + + +HPDF_Pages +HPDF_Catalog_GetRoot (HPDF_Catalog catalog); + + +HPDF_PageLayout +HPDF_Catalog_GetPageLayout (HPDF_Catalog catalog); + + +HPDF_STATUS +HPDF_Catalog_SetPageLayout (HPDF_Catalog catalog, + HPDF_PageLayout layout); + + +HPDF_PageMode +HPDF_Catalog_GetPageMode (HPDF_Catalog catalog); + + +HPDF_STATUS +HPDF_Catalog_SetPageMode (HPDF_Catalog catalog, + HPDF_PageMode mode); + + +HPDF_STATUS +HPDF_Catalog_SetOpenAction (HPDF_Catalog catalog, + HPDF_Destination open_action); + + +HPDF_STATUS +HPDF_Catalog_AddPageLabel (HPDF_Catalog catalog, + HPDF_UINT page_num, + HPDF_Dict page_label); + + +HPDF_UINT +HPDF_Catalog_GetViewerPreference (HPDF_Catalog catalog); + + +HPDF_STATUS +HPDF_Catalog_SetViewerPreference (HPDF_Catalog catalog, + HPDF_UINT value); + + +HPDF_BOOL +HPDF_Catalog_Validate (HPDF_Catalog catalog); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_CATALOG_H */ + diff --git a/code/libharu/hpdf_conf.h b/code/libharu/hpdf_conf.h new file mode 100644 index 0000000..e216910 --- /dev/null +++ b/code/libharu/hpdf_conf.h @@ -0,0 +1,85 @@ +/* + * << Haru Free PDF Library >> -- hpdf_conf.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_CONF_H +#define _HPDF_CONF_H + +#include +#include +#if defined(_MSC_VER) +#ifndef _USE_MATH_DEFINES +#define _USE_MATH_DEFINES 1 +#endif /* _USE_MATH_DEFINES */ +#endif +#ifndef __USE_XOPEN +#define __USE_XOPEN /* for M_PI */ +#endif /* __USE_XOPEN */ +#include + +/*----------------------------------------------------------------------------*/ +/*----- standard C library functions -----------------------------------------*/ + +#define HPDF_FOPEN fopen +#define HPDF_FCLOSE fclose +#define HPDF_FREAD fread +#define HPDF_FWRITE fwrite +#define HPDF_FFLUSH fflush +#define HPDF_FSEEK fseek +#define HPDF_FTELL ftell +#define HPDF_FEOF feof +#define HPDF_FERROR ferror +#define HPDF_MALLOC malloc +#define HPDF_FREE free +#define HPDF_FILEP FILE* +#define HPDF_TIME time +#define HPDF_PRINTF printf +#define HPDF_SIN sin +#define HPDF_COS cos + +/*----------------------------------------------------------------------------*/ +/*----- parameters in relation to performance --------------------------------*/ + +/* default buffer size of memory-stream-object */ +#define HPDF_STREAM_BUF_SIZ 4096 + +/* default array size of list-object */ +#define HPDF_DEF_ITEMS_PER_BLOCK 20 + +/* default array size of cross-reference-table */ +#define HPDF_DEFALUT_XREF_ENTRY_NUM 1024 + +/* default array size of widths-table of cid-fontdef */ +#define HPDF_DEF_CHAR_WIDTHS_NUM 128 + +/* default array size of page-list-tablef */ +#define HPDF_DEF_PAGE_LIST_NUM 256 + +/* default array size of range-table of cid-fontdef */ +#define HPDF_DEF_RANGE_TBL_NUM 128 + +/* default buffer size of memory-pool-object */ +#define HPDF_MPOOL_BUF_SIZ 8192 +#define HPDF_MIN_MPOOL_BUF_SIZ 256 +#define HPDF_MAX_MPOOL_BUF_SIZ 1048576 + +/* alignment size of memory-pool-object + */ +#define HPDF_ALIGN_SIZ sizeof int; + + +#endif /* _HPDF_CONF_H */ + diff --git a/code/libharu/hpdf_config.h b/code/libharu/hpdf_config.h new file mode 100644 index 0000000..242d503 --- /dev/null +++ b/code/libharu/hpdf_config.h @@ -0,0 +1,75 @@ +/* include/hpdf_config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef LIBHPDF_HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef LIBHPDF_HAVE_INTTYPES_H + +/* Define to 1 if you have the `png' library (-lpng). */ +#define LIBHPDF_HAVE_LIBPNG 1 + +/* Define to 1 if you have the `z' library (-lz). */ +#define LIBHPDF_HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#undef LIBHPDF_HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef LIBHPDF_HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#define LIBHPDF_HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define LIBHPDF_HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define LIBHPDF_HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define LIBHPDF_HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#undef LIBHPDF_HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define LIBHPDF_HAVE_UNISTD_H 1 + +/* define pi */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ + +/* debug build */ +#undef LIBHPDF_DEBUG + +/* debug trace enabled */ +#undef LIBHPDF_DEBUG_TRACE + +/* libpng is not available */ +#undef LIBHPDF_HAVE_NOPNGLIB + +/* zlib is not available */ +#undef LIBHPDF_HAVE_NOZLIB + +/* Define to the address where bug reports for this package should be sent. */ +#undef LIBHPDF_PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef LIBHPDF_PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#define LIBHPDF_PACKAGE_STRING "libhpdf 2.2.0" + +/* Define to the one symbol short name of this package. */ +#undef LIBHPDF_PACKAGE_TARNAME + +/* Define to the version of this package. */ +#define LIBHPDF_PACKAGE_VERSION "2.2.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define LIBHPDF_STDC_HEADERS 1 + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/code/libharu/hpdf_consts.h b/code/libharu/hpdf_consts.h new file mode 100644 index 0000000..2c6d55c --- /dev/null +++ b/code/libharu/hpdf_consts.h @@ -0,0 +1,549 @@ +/* + * << Haru Free PDF Library >> -- hpdf_consts.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + + +#ifndef _HPDF_CONSTS_H +#define _HPDF_CONSTS_H + +/*----------------------------------------------------------------------------*/ + +#define HPDF_TRUE 1 +#define HPDF_FALSE 0 + +#define HPDF_OK 0 +#define HPDF_NOERROR 0 + +/*----- default values -------------------------------------------------------*/ + +/* buffer size which is required when we convert to character string. */ +#define HPDF_TMP_BUF_SIZ 512 +#define HPDF_SHORT_BUF_SIZ 32 +#define HPDF_REAL_LEN 11 +#define HPDF_INT_LEN 11 +#define HPDF_TEXT_DEFAULT_LEN 256 +#define HPDF_UNICODE_HEADER_LEN 2 +#define HPDF_DATE_TIME_STR_LEN 23 + +/* length of each item defined in PDF */ +#define HPDF_BYTE_OFFSET_LEN 10 +#define HPDF_OBJ_ID_LEN 7 +#define HPDF_GEN_NO_LEN 5 + +/* default value of Graphic State */ +#define HPDF_DEF_FONT "Helvetica" +#define HPDF_DEF_PAGE_LAYOUT HPDF_PAGE_LAYOUT_SINGLE +#define HPDF_DEF_PAGE_MODE HPDF_PAGE_MODE_USE_NONE +#define HPDF_DEF_WORDSPACE 0 +#define HPDF_DEF_CHARSPACE 0 +#define HPDF_DEF_FONTSIZE 10 +#define HPDF_DEF_HSCALING 100 +#define HPDF_DEF_LEADING 0 +#define HPDF_DEF_RENDERING_MODE HPDF_FILL +#define HPDF_DEF_RISE 0 +#define HPDF_DEF_RAISE HPDF_DEF_RISE +#define HPDF_DEF_LINEWIDTH 1 +#define HPDF_DEF_LINECAP HPDF_BUTT_END +#define HPDF_DEF_LINEJOIN HPDF_MITER_JOIN +#define HPDF_DEF_MITERLIMIT 10 +#define HPDF_DEF_FLATNESS 1 +#define HPDF_DEF_PAGE_NUM 1 + +#define HPDF_BS_DEF_WIDTH 1 + +/* defalt page-size */ +#define HPDF_DEF_PAGE_WIDTH 595.276F +#define HPDF_DEF_PAGE_HEIGHT 841.89F + +/*---------------------------------------------------------------------------*/ +/*----- compression mode ----------------------------------------------------*/ + +#define HPDF_COMP_NONE 0x00 +#define HPDF_COMP_TEXT 0x01 +#define HPDF_COMP_IMAGE 0x02 +#define HPDF_COMP_METADATA 0x04 +#define HPDF_COMP_ALL 0x0F +/* #define HPDF_COMP_BEST_COMPRESS 0x10 + * #define HPDF_COMP_BEST_SPEED 0x20 + */ +#define HPDF_COMP_MASK 0xFF + + +/*----------------------------------------------------------------------------*/ +/*----- permission flags (only Revision 2 is supported)-----------------------*/ + +#define HPDF_ENABLE_READ 0 +#define HPDF_ENABLE_PRINT 4 +#define HPDF_ENABLE_EDIT_ALL 8 +#define HPDF_ENABLE_COPY 16 +#define HPDF_ENABLE_EDIT 32 + + +/*----------------------------------------------------------------------------*/ +/*------ viewer preferences definitions --------------------------------------*/ + +#define HPDF_HIDE_TOOLBAR 1 +#define HPDF_HIDE_MENUBAR 2 +#define HPDF_HIDE_WINDOW_UI 4 +#define HPDF_FIT_WINDOW 8 +#define HPDF_CENTER_WINDOW 16 +#define HPDF_PRINT_SCALING_NONE 32 + + +/*---------------------------------------------------------------------------*/ +/*------ limitation of object implementation (PDF1.4) -----------------------*/ + +#define HPDF_LIMIT_MAX_INT 2147483647 +#define HPDF_LIMIT_MIN_INT -2147483647 + +#define HPDF_LIMIT_MAX_REAL 32767 +#define HPDF_LIMIT_MIN_REAL -32767 + +#define HPDF_LIMIT_MAX_STRING_LEN 65535 +#define HPDF_LIMIT_MAX_NAME_LEN 127 + +#define HPDF_LIMIT_MAX_ARRAY 32767 +#define HPDF_LIMIT_MAX_DICT_ELEMENT 4095 +#define HPDF_LIMIT_MAX_XREF_ELEMENT 8388607 +#define HPDF_LIMIT_MAX_GSTATE 28 +#define HPDF_LIMIT_MAX_DEVICE_N 8 +#define HPDF_LIMIT_MAX_DEVICE_N_V15 32 +#define HPDF_LIMIT_MAX_CID 65535 +#define HPDF_MAX_GENERATION_NUM 65535 + +#define HPDF_MIN_PAGE_HEIGHT 3 +#define HPDF_MIN_PAGE_WIDTH 3 +#define HPDF_MAX_PAGE_HEIGHT 14400 +#define HPDF_MAX_PAGE_WIDTH 14400 +#define HPDF_MIN_MAGNIFICATION_FACTOR 8 +#define HPDF_MAX_MAGNIFICATION_FACTOR 3200 + +/*---------------------------------------------------------------------------*/ +/*------ limitation of various properties -----------------------------------*/ + +#define HPDF_MIN_PAGE_SIZE 3 +#define HPDF_MAX_PAGE_SIZE 14400 +#define HPDF_MIN_HORIZONTALSCALING 10 +#define HPDF_MAX_HORIZONTALSCALING 300 +#define HPDF_MIN_WORDSPACE -30 +#define HPDF_MAX_WORDSPACE 300 +#define HPDF_MIN_CHARSPACE -30 +#define HPDF_MAX_CHARSPACE 300 +#define HPDF_MAX_FONTSIZE 300 +#define HPDF_MAX_ZOOMSIZE 10 +#define HPDF_MAX_LEADING 300 +#define HPDF_MAX_LINEWIDTH 100 +#define HPDF_MAX_DASH_PATTERN 100 + +#define HPDF_MAX_JWW_NUM 128 + +/*----------------------------------------------------------------------------*/ +/*----- country code definition ----------------------------------------------*/ + +#define HPDF_COUNTRY_AF "AF" /* AFGHANISTAN */ +#define HPDF_COUNTRY_AL "AL" /* ALBANIA */ +#define HPDF_COUNTRY_DZ "DZ" /* ALGERIA */ +#define HPDF_COUNTRY_AS "AS" /* AMERICAN SAMOA */ +#define HPDF_COUNTRY_AD "AD" /* ANDORRA */ +#define HPDF_COUNTRY_AO "AO" /* ANGOLA */ +#define HPDF_COUNTRY_AI "AI" /* ANGUILLA */ +#define HPDF_COUNTRY_AQ "AQ" /* ANTARCTICA */ +#define HPDF_COUNTRY_AG "AG" /* ANTIGUA AND BARBUDA */ +#define HPDF_COUNTRY_AR "AR" /* ARGENTINA */ +#define HPDF_COUNTRY_AM "AM" /* ARMENIA */ +#define HPDF_COUNTRY_AW "AW" /* ARUBA */ +#define HPDF_COUNTRY_AU "AU" /* AUSTRALIA */ +#define HPDF_COUNTRY_AT "AT" /* AUSTRIA */ +#define HPDF_COUNTRY_AZ "AZ" /* AZERBAIJAN */ +#define HPDF_COUNTRY_BS "BS" /* BAHAMAS */ +#define HPDF_COUNTRY_BH "BH" /* BAHRAIN */ +#define HPDF_COUNTRY_BD "BD" /* BANGLADESH */ +#define HPDF_COUNTRY_BB "BB" /* BARBADOS */ +#define HPDF_COUNTRY_BY "BY" /* BELARUS */ +#define HPDF_COUNTRY_BE "BE" /* BELGIUM */ +#define HPDF_COUNTRY_BZ "BZ" /* BELIZE */ +#define HPDF_COUNTRY_BJ "BJ" /* BENIN */ +#define HPDF_COUNTRY_BM "BM" /* BERMUDA */ +#define HPDF_COUNTRY_BT "BT" /* BHUTAN */ +#define HPDF_COUNTRY_BO "BO" /* BOLIVIA */ +#define HPDF_COUNTRY_BA "BA" /* BOSNIA AND HERZEGOWINA */ +#define HPDF_COUNTRY_BW "BW" /* BOTSWANA */ +#define HPDF_COUNTRY_BV "BV" /* BOUVET ISLAND */ +#define HPDF_COUNTRY_BR "BR" /* BRAZIL */ +#define HPDF_COUNTRY_IO "IO" /* BRITISH INDIAN OCEAN TERRITORY */ +#define HPDF_COUNTRY_BN "BN" /* BRUNEI DARUSSALAM */ +#define HPDF_COUNTRY_BG "BG" /* BULGARIA */ +#define HPDF_COUNTRY_BF "BF" /* BURKINA FASO */ +#define HPDF_COUNTRY_BI "BI" /* BURUNDI */ +#define HPDF_COUNTRY_KH "KH" /* CAMBODIA */ +#define HPDF_COUNTRY_CM "CM" /* CAMEROON */ +#define HPDF_COUNTRY_CA "CA" /* CANADA */ +#define HPDF_COUNTRY_CV "CV" /* CAPE VERDE */ +#define HPDF_COUNTRY_KY "KY" /* CAYMAN ISLANDS */ +#define HPDF_COUNTRY_CF "CF" /* CENTRAL AFRICAN REPUBLIC */ +#define HPDF_COUNTRY_TD "TD" /* CHAD */ +#define HPDF_COUNTRY_CL "CL" /* CHILE */ +#define HPDF_COUNTRY_CN "CN" /* CHINA */ +#define HPDF_COUNTRY_CX "CX" /* CHRISTMAS ISLAND */ +#define HPDF_COUNTRY_CC "CC" /* COCOS (KEELING) ISLANDS */ +#define HPDF_COUNTRY_CO "CO" /* COLOMBIA */ +#define HPDF_COUNTRY_KM "KM" /* COMOROS */ +#define HPDF_COUNTRY_CG "CG" /* CONGO */ +#define HPDF_COUNTRY_CK "CK" /* COOK ISLANDS */ +#define HPDF_COUNTRY_CR "CR" /* COSTA RICA */ +#define HPDF_COUNTRY_CI "CI" /* COTE D'IVOIRE */ +#define HPDF_COUNTRY_HR "HR" /* CROATIA (local name: Hrvatska) */ +#define HPDF_COUNTRY_CU "CU" /* CUBA */ +#define HPDF_COUNTRY_CY "CY" /* CYPRUS */ +#define HPDF_COUNTRY_CZ "CZ" /* CZECH REPUBLIC */ +#define HPDF_COUNTRY_DK "DK" /* DENMARK */ +#define HPDF_COUNTRY_DJ "DJ" /* DJIBOUTI */ +#define HPDF_COUNTRY_DM "DM" /* DOMINICA */ +#define HPDF_COUNTRY_DO "DO" /* DOMINICAN REPUBLIC */ +#define HPDF_COUNTRY_TP "TP" /* EAST TIMOR */ +#define HPDF_COUNTRY_EC "EC" /* ECUADOR */ +#define HPDF_COUNTRY_EG "EG" /* EGYPT */ +#define HPDF_COUNTRY_SV "SV" /* EL SALVADOR */ +#define HPDF_COUNTRY_GQ "GQ" /* EQUATORIAL GUINEA */ +#define HPDF_COUNTRY_ER "ER" /* ERITREA */ +#define HPDF_COUNTRY_EE "EE" /* ESTONIA */ +#define HPDF_COUNTRY_ET "ET" /* ETHIOPIA */ +#define HPDF_COUNTRY_FK "FK" /* FALKLAND ISLANDS (MALVINAS) */ +#define HPDF_COUNTRY_FO "FO" /* FAROE ISLANDS */ +#define HPDF_COUNTRY_FJ "FJ" /* FIJI */ +#define HPDF_COUNTRY_FI "FI" /* FINLAND */ +#define HPDF_COUNTRY_FR "FR" /* FRANCE */ +#define HPDF_COUNTRY_FX "FX" /* FRANCE, METROPOLITAN */ +#define HPDF_COUNTRY_GF "GF" /* FRENCH GUIANA */ +#define HPDF_COUNTRY_PF "PF" /* FRENCH POLYNESIA */ +#define HPDF_COUNTRY_TF "TF" /* FRENCH SOUTHERN TERRITORIES */ +#define HPDF_COUNTRY_GA "GA" /* GABON */ +#define HPDF_COUNTRY_GM "GM" /* GAMBIA */ +#define HPDF_COUNTRY_GE "GE" /* GEORGIA */ +#define HPDF_COUNTRY_DE "DE" /* GERMANY */ +#define HPDF_COUNTRY_GH "GH" /* GHANA */ +#define HPDF_COUNTRY_GI "GI" /* GIBRALTAR */ +#define HPDF_COUNTRY_GR "GR" /* GREECE */ +#define HPDF_COUNTRY_GL "GL" /* GREENLAND */ +#define HPDF_COUNTRY_GD "GD" /* GRENADA */ +#define HPDF_COUNTRY_GP "GP" /* GUADELOUPE */ +#define HPDF_COUNTRY_GU "GU" /* GUAM */ +#define HPDF_COUNTRY_GT "GT" /* GUATEMALA */ +#define HPDF_COUNTRY_GN "GN" /* GUINEA */ +#define HPDF_COUNTRY_GW "GW" /* GUINEA-BISSAU */ +#define HPDF_COUNTRY_GY "GY" /* GUYANA */ +#define HPDF_COUNTRY_HT "HT" /* HAITI */ +#define HPDF_COUNTRY_HM "HM" /* HEARD AND MC DONALD ISLANDS */ +#define HPDF_COUNTRY_HN "HN" /* HONDURAS */ +#define HPDF_COUNTRY_HK "HK" /* HONG KONG */ +#define HPDF_COUNTRY_HU "HU" /* HUNGARY */ +#define HPDF_COUNTRY_IS "IS" /* ICELAND */ +#define HPDF_COUNTRY_IN "IN" /* INDIA */ +#define HPDF_COUNTRY_ID "ID" /* INDONESIA */ +#define HPDF_COUNTRY_IR "IR" /* IRAN (ISLAMIC REPUBLIC OF) */ +#define HPDF_COUNTRY_IQ "IQ" /* IRAQ */ +#define HPDF_COUNTRY_IE "IE" /* IRELAND */ +#define HPDF_COUNTRY_IL "IL" /* ISRAEL */ +#define HPDF_COUNTRY_IT "IT" /* ITALY */ +#define HPDF_COUNTRY_JM "JM" /* JAMAICA */ +#define HPDF_COUNTRY_JP "JP" /* JAPAN */ +#define HPDF_COUNTRY_JO "JO" /* JORDAN */ +#define HPDF_COUNTRY_KZ "KZ" /* KAZAKHSTAN */ +#define HPDF_COUNTRY_KE "KE" /* KENYA */ +#define HPDF_COUNTRY_KI "KI" /* KIRIBATI */ +#define HPDF_COUNTRY_KP "KP" /* KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF */ +#define HPDF_COUNTRY_KR "KR" /* KOREA, REPUBLIC OF */ +#define HPDF_COUNTRY_KW "KW" /* KUWAIT */ +#define HPDF_COUNTRY_KG "KG" /* KYRGYZSTAN */ +#define HPDF_COUNTRY_LA "LA" /* LAO PEOPLE'S DEMOCRATIC REPUBLIC */ +#define HPDF_COUNTRY_LV "LV" /* LATVIA */ +#define HPDF_COUNTRY_LB "LB" /* LEBANON */ +#define HPDF_COUNTRY_LS "LS" /* LESOTHO */ +#define HPDF_COUNTRY_LR "LR" /* LIBERIA */ +#define HPDF_COUNTRY_LY "LY" /* LIBYAN ARAB JAMAHIRIYA */ +#define HPDF_COUNTRY_LI "LI" /* LIECHTENSTEIN */ +#define HPDF_COUNTRY_LT "LT" /* LITHUANIA */ +#define HPDF_COUNTRY_LU "LU" /* LUXEMBOURG */ +#define HPDF_COUNTRY_MO "MO" /* MACAU */ +#define HPDF_COUNTRY_MK "MK" /* MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF */ +#define HPDF_COUNTRY_MG "MG" /* MADAGASCAR */ +#define HPDF_COUNTRY_MW "MW" /* MALAWI */ +#define HPDF_COUNTRY_MY "MY" /* MALAYSIA */ +#define HPDF_COUNTRY_MV "MV" /* MALDIVES */ +#define HPDF_COUNTRY_ML "ML" /* MALI */ +#define HPDF_COUNTRY_MT "MT" /* MALTA */ +#define HPDF_COUNTRY_MH "MH" /* MARSHALL ISLANDS */ +#define HPDF_COUNTRY_MQ "MQ" /* MARTINIQUE */ +#define HPDF_COUNTRY_MR "MR" /* MAURITANIA */ +#define HPDF_COUNTRY_MU "MU" /* MAURITIUS */ +#define HPDF_COUNTRY_YT "YT" /* MAYOTTE */ +#define HPDF_COUNTRY_MX "MX" /* MEXICO */ +#define HPDF_COUNTRY_FM "FM" /* MICRONESIA, FEDERATED STATES OF */ +#define HPDF_COUNTRY_MD "MD" /* MOLDOVA, REPUBLIC OF */ +#define HPDF_COUNTRY_MC "MC" /* MONACO */ +#define HPDF_COUNTRY_MN "MN" /* MONGOLIA */ +#define HPDF_COUNTRY_MS "MS" /* MONTSERRAT */ +#define HPDF_COUNTRY_MA "MA" /* MOROCCO */ +#define HPDF_COUNTRY_MZ "MZ" /* MOZAMBIQUE */ +#define HPDF_COUNTRY_MM "MM" /* MYANMAR */ +#define HPDF_COUNTRY_NA "NA" /* NAMIBIA */ +#define HPDF_COUNTRY_NR "NR" /* NAURU */ +#define HPDF_COUNTRY_NP "NP" /* NEPAL */ +#define HPDF_COUNTRY_NL "NL" /* NETHERLANDS */ +#define HPDF_COUNTRY_AN "AN" /* NETHERLANDS ANTILLES */ +#define HPDF_COUNTRY_NC "NC" /* NEW CALEDONIA */ +#define HPDF_COUNTRY_NZ "NZ" /* NEW ZEALAND */ +#define HPDF_COUNTRY_NI "NI" /* NICARAGUA */ +#define HPDF_COUNTRY_NE "NE" /* NIGER */ +#define HPDF_COUNTRY_NG "NG" /* NIGERIA */ +#define HPDF_COUNTRY_NU "NU" /* NIUE */ +#define HPDF_COUNTRY_NF "NF" /* NORFOLK ISLAND */ +#define HPDF_COUNTRY_MP "MP" /* NORTHERN MARIANA ISLANDS */ +#define HPDF_COUNTRY_NO "NO" /* NORWAY */ +#define HPDF_COUNTRY_OM "OM" /* OMAN */ +#define HPDF_COUNTRY_PK "PK" /* PAKISTAN */ +#define HPDF_COUNTRY_PW "PW" /* PALAU */ +#define HPDF_COUNTRY_PA "PA" /* PANAMA */ +#define HPDF_COUNTRY_PG "PG" /* PAPUA NEW GUINEA */ +#define HPDF_COUNTRY_PY "PY" /* PARAGUAY */ +#define HPDF_COUNTRY_PE "PE" /* PERU */ +#define HPDF_COUNTRY_PH "PH" /* PHILIPPINES */ +#define HPDF_COUNTRY_PN "PN" /* PITCAIRN */ +#define HPDF_COUNTRY_PL "PL" /* POLAND */ +#define HPDF_COUNTRY_PT "PT" /* PORTUGAL */ +#define HPDF_COUNTRY_PR "PR" /* PUERTO RICO */ +#define HPDF_COUNTRY_QA "QA" /* QATAR */ +#define HPDF_COUNTRY_RE "RE" /* REUNION */ +#define HPDF_COUNTRY_RO "RO" /* ROMANIA */ +#define HPDF_COUNTRY_RU "RU" /* RUSSIAN FEDERATION */ +#define HPDF_COUNTRY_RW "RW" /* RWANDA */ +#define HPDF_COUNTRY_KN "KN" /* SAINT KITTS AND NEVIS */ +#define HPDF_COUNTRY_LC "LC" /* SAINT LUCIA */ +#define HPDF_COUNTRY_VC "VC" /* SAINT VINCENT AND THE GRENADINES */ +#define HPDF_COUNTRY_WS "WS" /* SAMOA */ +#define HPDF_COUNTRY_SM "SM" /* SAN MARINO */ +#define HPDF_COUNTRY_ST "ST" /* SAO TOME AND PRINCIPE */ +#define HPDF_COUNTRY_SA "SA" /* SAUDI ARABIA */ +#define HPDF_COUNTRY_SN "SN" /* SENEGAL */ +#define HPDF_COUNTRY_SC "SC" /* SEYCHELLES */ +#define HPDF_COUNTRY_SL "SL" /* SIERRA LEONE */ +#define HPDF_COUNTRY_SG "SG" /* SINGAPORE */ +#define HPDF_COUNTRY_SK "SK" /* SLOVAKIA (Slovak Republic) */ +#define HPDF_COUNTRY_SI "SI" /* SLOVENIA */ +#define HPDF_COUNTRY_SB "SB" /* SOLOMON ISLANDS */ +#define HPDF_COUNTRY_SO "SO" /* SOMALIA */ +#define HPDF_COUNTRY_ZA "ZA" /* SOUTH AFRICA */ +#define HPDF_COUNTRY_ES "ES" /* SPAIN */ +#define HPDF_COUNTRY_LK "LK" /* SRI LANKA */ +#define HPDF_COUNTRY_SH "SH" /* ST. HELENA */ +#define HPDF_COUNTRY_PM "PM" /* ST. PIERRE AND MIQUELON */ +#define HPDF_COUNTRY_SD "SD" /* SUDAN */ +#define HPDF_COUNTRY_SR "SR" /* SURINAME */ +#define HPDF_COUNTRY_SJ "SJ" /* SVALBARD AND JAN MAYEN ISLANDS */ +#define HPDF_COUNTRY_SZ "SZ" /* SWAZILAND */ +#define HPDF_COUNTRY_SE "SE" /* SWEDEN */ +#define HPDF_COUNTRY_CH "CH" /* SWITZERLAND */ +#define HPDF_COUNTRY_SY "SY" /* SYRIAN ARAB REPUBLIC */ +#define HPDF_COUNTRY_TW "TW" /* TAIWAN, PROVINCE OF CHINA */ +#define HPDF_COUNTRY_TJ "TJ" /* TAJIKISTAN */ +#define HPDF_COUNTRY_TZ "TZ" /* TANZANIA, UNITED REPUBLIC OF */ +#define HPDF_COUNTRY_TH "TH" /* THAILAND */ +#define HPDF_COUNTRY_TG "TG" /* TOGO */ +#define HPDF_COUNTRY_TK "TK" /* TOKELAU */ +#define HPDF_COUNTRY_TO "TO" /* TONGA */ +#define HPDF_COUNTRY_TT "TT" /* TRINIDAD AND TOBAGO */ +#define HPDF_COUNTRY_TN "TN" /* TUNISIA */ +#define HPDF_COUNTRY_TR "TR" /* TURKEY */ +#define HPDF_COUNTRY_TM "TM" /* TURKMENISTAN */ +#define HPDF_COUNTRY_TC "TC" /* TURKS AND CAICOS ISLANDS */ +#define HPDF_COUNTRY_TV "TV" /* TUVALU */ +#define HPDF_COUNTRY_UG "UG" /* UGANDA */ +#define HPDF_COUNTRY_UA "UA" /* UKRAINE */ +#define HPDF_COUNTRY_AE "AE" /* UNITED ARAB EMIRATES */ +#define HPDF_COUNTRY_GB "GB" /* UNITED KINGDOM */ +#define HPDF_COUNTRY_US "US" /* UNITED STATES */ +#define HPDF_COUNTRY_UM "UM" /* UNITED STATES MINOR OUTLYING ISLANDS */ +#define HPDF_COUNTRY_UY "UY" /* URUGUAY */ +#define HPDF_COUNTRY_UZ "UZ" /* UZBEKISTAN */ +#define HPDF_COUNTRY_VU "VU" /* VANUATU */ +#define HPDF_COUNTRY_VA "VA" /* VATICAN CITY STATE (HOLY SEE) */ +#define HPDF_COUNTRY_VE "VE" /* VENEZUELA */ +#define HPDF_COUNTRY_VN "VN" /* VIET NAM */ +#define HPDF_COUNTRY_VG "VG" /* VIRGIN ISLANDS (BRITISH) */ +#define HPDF_COUNTRY_VI "VI" /* VIRGIN ISLANDS (U.S.) */ +#define HPDF_COUNTRY_WF "WF" /* WALLIS AND FUTUNA ISLANDS */ +#define HPDF_COUNTRY_EH "EH" /* WESTERN SAHARA */ +#define HPDF_COUNTRY_YE "YE" /* YEMEN */ +#define HPDF_COUNTRY_YU "YU" /* YUGOSLAVIA */ +#define HPDF_COUNTRY_ZR "ZR" /* ZAIRE */ +#define HPDF_COUNTRY_ZM "ZM" /* ZAMBIA */ +#define HPDF_COUNTRY_ZW "ZW" /* ZIMBABWE */ + +/*----------------------------------------------------------------------------*/ +/*----- lang code definition -------------------------------------------------*/ + +#define HPDF_LANG_AA "aa" /* Afar */ +#define HPDF_LANG_AB "ab" /* Abkhazian */ +#define HPDF_LANG_AF "af" /* Afrikaans */ +#define HPDF_LANG_AM "am" /* Amharic */ +#define HPDF_LANG_AR "ar" /* Arabic */ +#define HPDF_LANG_AS "as" /* Assamese */ +#define HPDF_LANG_AY "ay" /* Aymara */ +#define HPDF_LANG_AZ "az" /* Azerbaijani */ +#define HPDF_LANG_BA "ba" /* Bashkir */ +#define HPDF_LANG_BE "be" /* Byelorussian */ +#define HPDF_LANG_BG "bg" /* Bulgarian */ +#define HPDF_LANG_BH "bh" /* Bihari */ +#define HPDF_LANG_BI "bi" /* Bislama */ +#define HPDF_LANG_BN "bn" /* Bengali Bangla */ +#define HPDF_LANG_BO "bo" /* Tibetan */ +#define HPDF_LANG_BR "br" /* Breton */ +#define HPDF_LANG_CA "ca" /* Catalan */ +#define HPDF_LANG_CO "co" /* Corsican */ +#define HPDF_LANG_CS "cs" /* Czech */ +#define HPDF_LANG_CY "cy" /* Welsh */ +#define HPDF_LANG_DA "da" /* Danish */ +#define HPDF_LANG_DE "de" /* German */ +#define HPDF_LANG_DZ "dz" /* Bhutani */ +#define HPDF_LANG_EL "el" /* Greek */ +#define HPDF_LANG_EN "en" /* English */ +#define HPDF_LANG_EO "eo" /* Esperanto */ +#define HPDF_LANG_ES "es" /* Spanish */ +#define HPDF_LANG_ET "et" /* Estonian */ +#define HPDF_LANG_EU "eu" /* Basque */ +#define HPDF_LANG_FA "fa" /* Persian */ +#define HPDF_LANG_FI "fi" /* Finnish */ +#define HPDF_LANG_FJ "fj" /* Fiji */ +#define HPDF_LANG_FO "fo" /* Faeroese */ +#define HPDF_LANG_FR "fr" /* French */ +#define HPDF_LANG_FY "fy" /* Frisian */ +#define HPDF_LANG_GA "ga" /* Irish */ +#define HPDF_LANG_GD "gd" /* Scots Gaelic */ +#define HPDF_LANG_GL "gl" /* Galician */ +#define HPDF_LANG_GN "gn" /* Guarani */ +#define HPDF_LANG_GU "gu" /* Gujarati */ +#define HPDF_LANG_HA "ha" /* Hausa */ +#define HPDF_LANG_HI "hi" /* Hindi */ +#define HPDF_LANG_HR "hr" /* Croatian */ +#define HPDF_LANG_HU "hu" /* Hungarian */ +#define HPDF_LANG_HY "hy" /* Armenian */ +#define HPDF_LANG_IA "ia" /* Interlingua */ +#define HPDF_LANG_IE "ie" /* Interlingue */ +#define HPDF_LANG_IK "ik" /* Inupiak */ +#define HPDF_LANG_IN "in" /* Indonesian */ +#define HPDF_LANG_IS "is" /* Icelandic */ +#define HPDF_LANG_IT "it" /* Italian */ +#define HPDF_LANG_IW "iw" /* Hebrew */ +#define HPDF_LANG_JA "ja" /* Japanese */ +#define HPDF_LANG_JI "ji" /* Yiddish */ +#define HPDF_LANG_JW "jw" /* Javanese */ +#define HPDF_LANG_KA "ka" /* Georgian */ +#define HPDF_LANG_KK "kk" /* Kazakh */ +#define HPDF_LANG_KL "kl" /* Greenlandic */ +#define HPDF_LANG_KM "km" /* Cambodian */ +#define HPDF_LANG_KN "kn" /* Kannada */ +#define HPDF_LANG_KO "ko" /* Korean */ +#define HPDF_LANG_KS "ks" /* Kashmiri */ +#define HPDF_LANG_KU "ku" /* Kurdish */ +#define HPDF_LANG_KY "ky" /* Kirghiz */ +#define HPDF_LANG_LA "la" /* Latin */ +#define HPDF_LANG_LN "ln" /* Lingala */ +#define HPDF_LANG_LO "lo" /* Laothian */ +#define HPDF_LANG_LT "lt" /* Lithuanian */ +#define HPDF_LANG_LV "lv" /* Latvian,Lettish */ +#define HPDF_LANG_MG "mg" /* Malagasy */ +#define HPDF_LANG_MI "mi" /* Maori */ +#define HPDF_LANG_MK "mk" /* Macedonian */ +#define HPDF_LANG_ML "ml" /* Malayalam */ +#define HPDF_LANG_MN "mn" /* Mongolian */ +#define HPDF_LANG_MO "mo" /* Moldavian */ +#define HPDF_LANG_MR "mr" /* Marathi */ +#define HPDF_LANG_MS "ms" /* Malay */ +#define HPDF_LANG_MT "mt" /* Maltese */ +#define HPDF_LANG_MY "my" /* Burmese */ +#define HPDF_LANG_NA "na" /* Nauru */ +#define HPDF_LANG_NE "ne" /* Nepali */ +#define HPDF_LANG_NL "nl" /* Dutch */ +#define HPDF_LANG_NO "no" /* Norwegian */ +#define HPDF_LANG_OC "oc" /* Occitan */ +#define HPDF_LANG_OM "om" /* (Afan)Oromo */ +#define HPDF_LANG_OR "or" /* Oriya */ +#define HPDF_LANG_PA "pa" /* Punjabi */ +#define HPDF_LANG_PL "pl" /* Polish */ +#define HPDF_LANG_PS "ps" /* Pashto,Pushto */ +#define HPDF_LANG_PT "pt" /* Portuguese */ +#define HPDF_LANG_QU "qu" /* Quechua */ +#define HPDF_LANG_RM "rm" /* Rhaeto-Romance */ +#define HPDF_LANG_RN "rn" /* Kirundi */ +#define HPDF_LANG_RO "ro" /* Romanian */ +#define HPDF_LANG_RU "ru" /* Russian */ +#define HPDF_LANG_RW "rw" /* Kinyarwanda */ +#define HPDF_LANG_SA "sa" /* Sanskrit */ +#define HPDF_LANG_SD "sd" /* Sindhi */ +#define HPDF_LANG_SG "sg" /* Sangro */ +#define HPDF_LANG_SH "sh" /* Serbo-Croatian */ +#define HPDF_LANG_SI "si" /* Singhalese */ +#define HPDF_LANG_SK "sk" /* Slovak */ +#define HPDF_LANG_SL "sl" /* Slovenian */ +#define HPDF_LANG_SM "sm" /* Samoan */ +#define HPDF_LANG_SN "sn" /* Shona */ +#define HPDF_LANG_SO "so" /* Somali */ +#define HPDF_LANG_SQ "sq" /* Albanian */ +#define HPDF_LANG_SR "sr" /* Serbian */ +#define HPDF_LANG_SS "ss" /* Siswati */ +#define HPDF_LANG_ST "st" /* Sesotho */ +#define HPDF_LANG_SU "su" /* Sundanese */ +#define HPDF_LANG_SV "sv" /* Swedish */ +#define HPDF_LANG_SW "sw" /* Swahili */ +#define HPDF_LANG_TA "ta" /* Tamil */ +#define HPDF_LANG_TE "te" /* Tegulu */ +#define HPDF_LANG_TG "tg" /* Tajik */ +#define HPDF_LANG_TH "th" /* Thai */ +#define HPDF_LANG_TI "ti" /* Tigrinya */ +#define HPDF_LANG_TK "tk" /* Turkmen */ +#define HPDF_LANG_TL "tl" /* Tagalog */ +#define HPDF_LANG_TN "tn" /* Setswanato Tonga */ +#define HPDF_LANG_TR "tr" /* Turkish */ +#define HPDF_LANG_TS "ts" /* Tsonga */ +#define HPDF_LANG_TT "tt" /* Tatar */ +#define HPDF_LANG_TW "tw" /* Twi */ +#define HPDF_LANG_UK "uk" /* Ukrainian */ +#define HPDF_LANG_UR "ur" /* Urdu */ +#define HPDF_LANG_UZ "uz" /* Uzbek */ +#define HPDF_LANG_VI "vi" /* Vietnamese */ +#define HPDF_LANG_VO "vo" /* Volapuk */ +#define HPDF_LANG_WO "wo" /* Wolof */ +#define HPDF_LANG_XH "xh" /* Xhosa */ +#define HPDF_LANG_YO "yo" /* Yoruba */ +#define HPDF_LANG_ZH "zh" /* Chinese */ +#define HPDF_LANG_ZU "zu" /* Zulu */ + + +/*----------------------------------------------------------------------------*/ +/*----- Graphis mode ---------------------------------------------------------*/ + +#define HPDF_GMODE_PAGE_DESCRIPTION 0x0001 +#define HPDF_GMODE_PATH_OBJECT 0x0002 +#define HPDF_GMODE_TEXT_OBJECT 0x0004 +#define HPDF_GMODE_CLIPPING_PATH 0x0008 +#define HPDF_GMODE_SHADING 0x0010 +#define HPDF_GMODE_INLINE_IMAGE 0x0020 +#define HPDF_GMODE_EXTERNAL_OBJECT 0x0040 + + +/*----------------------------------------------------------------------------*/ + +#endif /* _HPDF_CONSTS_H */ diff --git a/code/libharu/hpdf_destination.h b/code/libharu/hpdf_destination.h new file mode 100644 index 0000000..d7ec27a --- /dev/null +++ b/code/libharu/hpdf_destination.h @@ -0,0 +1,44 @@ +/* + * << Haru Free PDF Library >> -- hpdf_destination.c + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_DESTINATION_H +#define _HPDF_DESTINATION_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_Destination -----------------------------------------------------*/ + +HPDF_Destination +HPDF_Destination_New (HPDF_MMgr mmgr, + HPDF_Page target, + HPDF_Xref xref); + + +HPDF_BOOL +HPDF_Destination_Validate (HPDF_Destination dst); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_DESTINATION_H */ + diff --git a/code/libharu/hpdf_doc.h b/code/libharu/hpdf_doc.h new file mode 100644 index 0000000..89779c0 --- /dev/null +++ b/code/libharu/hpdf_doc.h @@ -0,0 +1,162 @@ +/* + * << Haru Free PDF Library >> -- hpdf_doc.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + + +#ifndef _HPDF_DOC_H +#define _HPDF_DOC_H + +#define HPDF_SIG_BYTES 0x41504446L + +#include "hpdf_catalog.h" +#include "hpdf_image.h" +#include "hpdf_pages.h" +#include "hpdf_outline.h" +#include "hpdf_ext_gstate.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HPDF_VER_DEFAULT HPDF_VER_12 + +typedef struct _HPDF_Doc_Rec { + HPDF_UINT32 sig_bytes; + HPDF_PDFVer pdf_version; + + HPDF_MMgr mmgr; + HPDF_Catalog catalog; + HPDF_Outline outlines; + HPDF_Xref xref; + HPDF_Pages root_pages; + HPDF_Pages cur_pages; + HPDF_Page cur_page; + HPDF_List page_list; + HPDF_Error_Rec error; + HPDF_Dict info; + HPDF_Dict trailer; + + HPDF_List font_mgr; + HPDF_BYTE ttfont_tag[6]; + + /* list for loaded fontdefs */ + HPDF_List fontdef_list; + + /* list for loaded encodings */ + HPDF_List encoder_list; + + HPDF_Encoder cur_encoder; + + /* default compression mode */ + HPDF_BOOL compression_mode; + + HPDF_BOOL encrypt_on; + HPDF_EncryptDict encrypt_dict; + + HPDF_Encoder def_encoder; + + HPDF_UINT page_per_pages; + HPDF_UINT cur_page_num; + + /* buffer for saving into memory stream */ + HPDF_Stream stream; +} HPDF_Doc_Rec; + +typedef struct _HPDF_Doc_Rec *HPDF_Doc; + + +HPDF_Encoder +HPDF_Doc_FindEncoder (HPDF_Doc pdf, + const char *encoding_name); + + +HPDF_FontDef +HPDF_Doc_FindFontDef (HPDF_Doc pdf, + const char *font_name); + + +HPDF_Font +HPDF_Doc_FindFont (HPDF_Doc pdf, + const char *font_name, + const char *encoding_name); + + +HPDF_BOOL +HPDF_Doc_Validate (HPDF_Doc pdf); + + +/*----- page handling -------------------------------------------------------*/ + +HPDF_Pages +HPDF_Doc_GetCurrentPages (HPDF_Doc pdf); + + +HPDF_Pages +HPDF_Doc_AddPagesTo (HPDF_Doc pdf, + HPDF_Pages parent); + + +HPDF_STATUS +HPDF_Doc_SetCurrentPages (HPDF_Doc pdf, + HPDF_Pages pages); + + +HPDF_STATUS +HPDF_Doc_SetCurrentPage (HPDF_Doc pdf, + HPDF_Page page); + + + + +/*----- font handling -------------------------------------------------------*/ + +HPDF_FontDef +HPDF_GetFontDef (HPDF_Doc pdf, + const char *font_name); + + +HPDF_STATUS +HPDF_Doc_RegisterFontDef (HPDF_Doc pdf, + HPDF_FontDef fontdef); + + +/*----- encoding handling ---------------------------------------------------*/ + +HPDF_STATUS +HPDF_Doc_RegisterEncoder (HPDF_Doc pdf, + HPDF_Encoder encoder); + + + +/*----- encryptio------------------------------------------------------------*/ + +HPDF_STATUS +HPDF_Doc_SetEncryptOn (HPDF_Doc pdf); + + +HPDF_STATUS +HPDF_Doc_SetEncryptOff (HPDF_Doc pdf); + + +HPDF_STATUS +HPDF_Doc_PrepareEncryption (HPDF_Doc pdf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_DOC_H */ + diff --git a/code/libharu/hpdf_encoder.h b/code/libharu/hpdf_encoder.h new file mode 100644 index 0000000..411d78d --- /dev/null +++ b/code/libharu/hpdf_encoder.h @@ -0,0 +1,318 @@ +/* + * << Haru Free PDF Library >> -- hpdf_encoder.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_ENCODER_H +#define _HPDF_ENCODER_H + +#include "hpdf_consts.h" +#include "hpdf_streams.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*-- HPDF_Encoder ---------------------------------------*/ + +#define HPDF_ENCODER_SIG_BYTES 0x454E4344L + +/*----------------------------------------------------------------------------*/ +/*------ predefined font encodings -------------------------------------------*/ + +#define HPDF_ENCODING_FONT_SPECIFIC "FontSpecific" +#define HPDF_ENCODING_STANDARD "StandardEncoding" +#define HPDF_ENCODING_MAC_ROMAN "MacRomanEncoding" +#define HPDF_ENCODING_WIN_ANSI "WinAnsiEncoding" +#define HPDF_ENCODING_ISO8859_2 "ISO8859-2" +#define HPDF_ENCODING_ISO8859_3 "ISO8859-3" +#define HPDF_ENCODING_ISO8859_4 "ISO8859-4" +#define HPDF_ENCODING_ISO8859_5 "ISO8859-5" +#define HPDF_ENCODING_ISO8859_6 "ISO8859-6" +#define HPDF_ENCODING_ISO8859_7 "ISO8859-7" +#define HPDF_ENCODING_ISO8859_8 "ISO8859-8" +#define HPDF_ENCODING_ISO8859_9 "ISO8859-9" +#define HPDF_ENCODING_ISO8859_10 "ISO8859-10" +#define HPDF_ENCODING_ISO8859_11 "ISO8859-11" +#define HPDF_ENCODING_ISO8859_13 "ISO8859-13" +#define HPDF_ENCODING_ISO8859_14 "ISO8859-14" +#define HPDF_ENCODING_ISO8859_15 "ISO8859-15" +#define HPDF_ENCODING_ISO8859_16 "ISO8859-16" +#define HPDF_ENCODING_CP1250 "CP1250" +#define HPDF_ENCODING_CP1251 "CP1251" +#define HPDF_ENCODING_CP1252 "CP1252" +#define HPDF_ENCODING_CP1253 "CP1253" +#define HPDF_ENCODING_CP1254 "CP1254" +#define HPDF_ENCODING_CP1255 "CP1255" +#define HPDF_ENCODING_CP1256 "CP1256" +#define HPDF_ENCODING_CP1257 "CP1257" +#define HPDF_ENCODING_CP1258 "CP1258" +#define HPDF_ENCODING_KOI8_R "KOI8-R" + +/*----------------------------------------------------------------------------*/ +/*----- definition for font encoding -----------------------------------------*/ + +#define char_NOTDEF ".notdef" + +typedef enum _HPDF_EncodingType { + HPDF_STANDARD_ENCODING = 0, + HPDF_MAC_ROMAN_ENCODING, + HPDF_WIN_ANSI_ENCODING, + HPDF_FONT_SPECIFIC, + HPDF_ENCODING_EOF +} HPDF_EncodingType; + + +typedef struct _HPDF_ParseText_Rec { + const HPDF_BYTE *text; + HPDF_UINT index; + HPDF_UINT len; + HPDF_ByteType byte_type; +} HPDF_ParseText_Rec; + + +typedef struct _HPDF_Encoder_Rec *HPDF_Encoder; + +typedef HPDF_ByteType +(*HPDF_Encoder_ByteType_Func) (HPDF_Encoder encoder, + HPDF_ParseText_Rec *state); + +typedef HPDF_UNICODE +(*HPDF_Encoder_ToUnicode_Func) (HPDF_Encoder encoder, + HPDF_UINT16 code); + +typedef char * +(*HPDF_Encoder_EncodeText_Func) (HPDF_Encoder encoder, + const char *text, + HPDF_UINT len, + HPDF_UINT *encoded_length); + +typedef HPDF_STATUS +(*HPDF_Encoder_Write_Func) (HPDF_Encoder encoder, + HPDF_Stream out); + + +typedef HPDF_STATUS +(*HPDF_Encoder_Init_Func) (HPDF_Encoder encoder); + + +typedef void +(*HPDF_Encoder_Free_Func) (HPDF_Encoder encoder); + + +typedef struct _HPDF_Encoder_Rec { + HPDF_UINT32 sig_bytes; + char name[HPDF_LIMIT_MAX_NAME_LEN + 1]; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_EncoderType type; + + HPDF_Encoder_ByteType_Func byte_type_fn; + HPDF_Encoder_ToUnicode_Func to_unicode_fn; + HPDF_Encoder_EncodeText_Func encode_text_fn; + HPDF_Encoder_Write_Func write_fn; + HPDF_Encoder_Free_Func free_fn; + HPDF_Encoder_Init_Func init_fn; + /* + char lang_code[3]; + char country_code[3]; + */ + void *attr; +} HPDF_Encoder_Rec; + + +typedef enum _HPDF_BaseEncodings { + HPDF_BASE_ENCODING_STANDARD, + HPDF_BASE_ENCODING_WIN_ANSI, + HPDF_BASE_ENCODING_MAC_ROMAN, + HPDF_BASE_ENCODING_FONT_SPECIFIC, + HPDF_BASE_ENCODING_EOF +} HPDF_BaseEncodings; + +HPDF_STATUS +HPDF_Encoder_Validate (HPDF_Encoder encoder); + +void +HPDF_Encoder_SetParseText (HPDF_Encoder encoder, + HPDF_ParseText_Rec *state, + const HPDF_BYTE *text, + HPDF_UINT len); + +HPDF_ByteType +HPDF_Encoder_ByteType (HPDF_Encoder encoder, + HPDF_ParseText_Rec *state); + + + +HPDF_UNICODE +HPDF_Encoder_ToUnicode (HPDF_Encoder encoder, + HPDF_UINT16 code); + + +void +HPDF_Encoder_Free (HPDF_Encoder encoder); + +/*-- HPDF_BasicEncoder ----------------------------------*/ + + +typedef struct _HPDF_BasicEncoderAttr_Rec *HPDF_BasicEncoderAttr; + +typedef struct _HPDF_BasicEncoderAttr_Rec { + char base_encoding[HPDF_LIMIT_MAX_NAME_LEN + 1]; + HPDF_BYTE first_char; + HPDF_BYTE last_char; + HPDF_UNICODE unicode_map[256]; + HPDF_BOOL has_differences; + HPDF_BYTE differences[256]; +} HPDF_BasicEncoderAttr_Rec; + + +HPDF_Encoder +HPDF_BasicEncoder_New (HPDF_MMgr mmgr, + const char *encoding_name); + + +void +HPDF_BasicEncoder_Free (HPDF_Encoder encoder); + + +HPDF_STATUS +HPDF_BasicEncoder_Write (HPDF_Encoder encoder, + HPDF_Stream out); + + +HPDF_UNICODE +HPDF_BasicEncoder_ToUnicode (HPDF_Encoder encoder, + HPDF_UINT16 code); + +/*-- HPDF_CMapEncoder ----------------------------------*/ + +typedef HPDF_BOOL +(*HPDF_CMapEncoder_ByteType_Func) (HPDF_Encoder encoder, + HPDF_BYTE b); + +typedef struct _HPDF_CidRange_Rec { + HPDF_UINT16 from; + HPDF_UINT16 to; + HPDF_UINT16 cid; +} HPDF_CidRange_Rec; + + +typedef struct _HPDF_UnicodeMap_Rec { + HPDF_UINT16 code; + HPDF_UINT16 unicode; +} HPDF_UnicodeMap_Rec; + +typedef struct _HPDF_CMapEncoderAttr_Rec *HPDF_CMapEncoderAttr; + +typedef struct _HPDF_CMapEncoderAttr_Rec { + HPDF_UNICODE unicode_map[256][256]; + HPDF_UINT16 cid_map[256][256]; + HPDF_UINT16 jww_line_head[HPDF_MAX_JWW_NUM]; + HPDF_List cmap_range; + HPDF_List notdef_range; + HPDF_List code_space_range; + HPDF_WritingMode writing_mode; + char registry[HPDF_LIMIT_MAX_NAME_LEN + 1]; + char ordering[HPDF_LIMIT_MAX_NAME_LEN + 1]; + HPDF_INT suppliment; + HPDF_CMapEncoder_ByteType_Func is_lead_byte_fn; + HPDF_CMapEncoder_ByteType_Func is_trial_byte_fn; + HPDF_INT uid_offset; + HPDF_UINT xuid[3]; +} HPDF_CMapEncoderAttr_Rec; + + +HPDF_Encoder +HPDF_CMapEncoder_New (HPDF_MMgr mmgr, + char *name, + HPDF_Encoder_Init_Func init_fn); + + +HPDF_STATUS +HPDF_CMapEncoder_InitAttr (HPDF_Encoder encoder); + + +void +HPDF_CMapEncoder_Free (HPDF_Encoder encoder); + + +HPDF_STATUS +HPDF_CMapEncoder_Write (HPDF_Encoder encoder, + HPDF_Stream out); + + +HPDF_UNICODE +HPDF_CMapEncoder_ToUnicode (HPDF_Encoder encoder, + HPDF_UINT16 code); + +HPDF_UINT16 +HPDF_CMapEncoder_ToCID (HPDF_Encoder encoder, + HPDF_UINT16 code); + +HPDF_STATUS +HPDF_CMapEncoder_SetParseText (HPDF_Encoder encoder, + HPDF_ParseText_Rec *state, + const HPDF_BYTE *text, + HPDF_UINT len); + +HPDF_ByteType +HPDF_CMapEncoder_ByteType (HPDF_Encoder encoder, + HPDF_ParseText_Rec *state); + + +HPDF_STATUS +HPDF_CMapEncoder_AddCMap (HPDF_Encoder encoder, + const HPDF_CidRange_Rec *range); + + +HPDF_STATUS +HPDF_CMapEncoder_AddNotDefRange (HPDF_Encoder encoder, + HPDF_CidRange_Rec range); + + +HPDF_STATUS +HPDF_CMapEncoder_AddCodeSpaceRange (HPDF_Encoder encoder, + HPDF_CidRange_Rec range); + + +void +HPDF_CMapEncoder_SetUnicodeArray (HPDF_Encoder encoder, + const HPDF_UnicodeMap_Rec *array1); + + +HPDF_STATUS +HPDF_CMapEncoder_AddJWWLineHead (HPDF_Encoder encoder, + const HPDF_UINT16 *code); + +HPDF_BOOL +HPDF_Encoder_CheckJWWLineHead (HPDF_Encoder encoder, + const HPDF_UINT16 code); + +/*-- utility functions ----------------------------------*/ + +const char* +HPDF_UnicodeToGryphName (HPDF_UNICODE unicode); + + +HPDF_UNICODE +HPDF_GryphNameToUnicode (const char *gryph_name); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_ENCODER_H */ + diff --git a/code/libharu/hpdf_encrypt.h b/code/libharu/hpdf_encrypt.h new file mode 100644 index 0000000..f9fddb8 --- /dev/null +++ b/code/libharu/hpdf_encrypt.h @@ -0,0 +1,159 @@ +/* + * << Haru Free PDF Library >> -- hpdf_encrypt.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + *------------------------------------------------------------------------------ + * + * The code implements MD5 message-digest algorithm is based on the code + * written by Colin Plumb. + * The copyright of it is as follows. + * + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + *---------------------------------------------------------------------------*/ + +#ifndef HPDF_ENCRYPT_H +#define HPDF_ENCRYPT_H + +#include "hpdf_mmgr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*----- encrypt-dict ---------------------------------------------------------*/ + +#define HPDF_ID_LEN 16 +#define HPDF_PASSWD_LEN 32 +#define HPDF_ENCRYPT_KEY_MAX 16 +#define HPDF_MD5_KEY_LEN 16 +#define HPDF_PERMISSION_PAD 0xFFFFFFC0 +#define HPDF_ARC4_BUF_SIZE 256 + + +typedef struct HPDF_MD5Context +{ + HPDF_UINT32 buf[4]; + HPDF_UINT32 bits[2]; + HPDF_BYTE in[64]; +} HPDF_MD5_CTX; + + +typedef struct _HPDF_ARC4_Ctx_Rec { + HPDF_BYTE idx1; + HPDF_BYTE idx2; + HPDF_BYTE state[HPDF_ARC4_BUF_SIZE]; +} HPDF_ARC4_Ctx_Rec; + + +typedef struct _HPDF_Encrypt_Rec *HPDF_Encrypt; + +typedef struct _HPDF_Encrypt_Rec { + HPDF_EncryptMode mode; + + /* key_len must be a multiple of 8, and between 40 to 128 */ + HPDF_UINT key_len; + + /* owner-password (not encrypted) */ + HPDF_BYTE owner_passwd[HPDF_PASSWD_LEN]; + + /* user-password (not encrypted) */ + HPDF_BYTE user_passwd[HPDF_PASSWD_LEN]; + + /* owner-password (encrypted) */ + HPDF_BYTE owner_key[HPDF_PASSWD_LEN]; + + /* user-password (encrypted) */ + HPDF_BYTE user_key[HPDF_PASSWD_LEN]; + + HPDF_INT permission; + HPDF_BYTE encrypt_id[HPDF_ID_LEN]; + HPDF_BYTE encryption_key[HPDF_MD5_KEY_LEN + 5]; + HPDF_BYTE md5_encryption_key[HPDF_MD5_KEY_LEN]; + HPDF_ARC4_Ctx_Rec arc4ctx; +} HPDF_Encrypt_Rec; + + +void +HPDF_MD5Init (struct HPDF_MD5Context *ctx); + + +void +HPDF_MD5Update (struct HPDF_MD5Context *ctx, + const HPDF_BYTE *buf, + HPDF_UINT32 len); + + +void +HPDF_MD5Final (HPDF_BYTE digest[16], + struct HPDF_MD5Context *ctx); + +void +HPDF_PadOrTrancatePasswd (const char *pwd, + HPDF_BYTE *new_pwd); + + +void +HPDF_Encrypt_Init (HPDF_Encrypt attr); + + +void +HPDF_Encrypt_CreateUserKey (HPDF_Encrypt attr); + + +void +HPDF_Encrypt_CreateOwnerKey (HPDF_Encrypt attr); + + +void +HPDF_Encrypt_CreateEncryptionKey (HPDF_Encrypt attr); + + +void +HPDF_Encrypt_InitKey (HPDF_Encrypt attr, + HPDF_UINT32 object_id, + HPDF_UINT16 gen_no); + + +void +HPDF_Encrypt_Reset (HPDF_Encrypt attr); + + +void +HPDF_Encrypt_CryptBuf (HPDF_Encrypt attr, + const HPDF_BYTE *src, + HPDF_BYTE *dst, + HPDF_UINT len); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_ENCRYPT_H */ + + diff --git a/code/libharu/hpdf_encryptdict.h b/code/libharu/hpdf_encryptdict.h new file mode 100644 index 0000000..433eb67 --- /dev/null +++ b/code/libharu/hpdf_encryptdict.h @@ -0,0 +1,69 @@ +/* + * << Haru Free PDF Library >> -- hpdf_encryptdict.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_ENCRYPTDICT_H +#define _HPDF_ENCRYPTDICT_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ +/*------ HPDF_EncryptDict ---------------------------------------------------*/ + +HPDF_EncryptDict +HPDF_EncryptDict_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + + +void +HPDF_EncryptDict_CreateID (HPDF_EncryptDict dict, + HPDF_Dict info, + HPDF_Xref xref); + + +void +HPDF_EncryptDict_OnFree (HPDF_Dict obj); + + +HPDF_STATUS +HPDF_EncryptDict_SetPassword (HPDF_EncryptDict dict, + const char *owner_passwd, + const char *user_passwd); + + +HPDF_BOOL +HPDF_EncryptDict_Validate (HPDF_EncryptDict dict); + + +HPDF_STATUS +HPDF_EncryptDict_Prepare (HPDF_EncryptDict dict, + HPDF_Dict info, + HPDF_Xref xref); + + +HPDF_Encrypt +HPDF_EncryptDict_GetAttr (HPDF_EncryptDict dict); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_ENCRYPTDICT_H */ + diff --git a/code/libharu/hpdf_error.h b/code/libharu/hpdf_error.h new file mode 100644 index 0000000..49374fe --- /dev/null +++ b/code/libharu/hpdf_error.h @@ -0,0 +1,203 @@ +/* + * << Haru Free PDF Library >> -- hpdf_error.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_ERROR_H +#define _HPDF_ERROR_H + +#include "hpdf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* error-code */ +#define HPDF_ARRAY_COUNT_ERR 0x1001 +#define HPDF_ARRAY_ITEM_NOT_FOUND 0x1002 +#define HPDF_ARRAY_ITEM_UNEXPECTED_TYPE 0x1003 +#define HPDF_BINARY_LENGTH_ERR 0x1004 +#define HPDF_CANNOT_GET_PALLET 0x1005 +#define HPDF_DICT_COUNT_ERR 0x1007 +#define HPDF_DICT_ITEM_NOT_FOUND 0x1008 +#define HPDF_DICT_ITEM_UNEXPECTED_TYPE 0x1009 +#define HPDF_DICT_STREAM_LENGTH_NOT_FOUND 0x100A +#define HPDF_DOC_ENCRYPTDICT_NOT_FOUND 0x100B +#define HPDF_DOC_INVALID_OBJECT 0x100C +/* 0x100D */ +#define HPDF_DUPLICATE_REGISTRATION 0x100E +#define HPDF_EXCEED_JWW_CODE_NUM_LIMIT 0x100F +/* 0x1010 */ +#define HPDF_ENCRYPT_INVALID_PASSWORD 0x1011 +/* 0x1012 */ +#define HPDF_ERR_UNKNOWN_CLASS 0x1013 +#define HPDF_EXCEED_GSTATE_LIMIT 0x1014 +#define HPDF_FAILD_TO_ALLOC_MEM 0x1015 +#define HPDF_FILE_IO_ERROR 0x1016 +#define HPDF_FILE_OPEN_ERROR 0x1017 +/* 0x1018 */ +#define HPDF_FONT_EXISTS 0x1019 +#define HPDF_FONT_INVALID_WIDTHS_TABLE 0x101A +#define HPDF_INVALID_AFM_HEADER 0x101B +#define HPDF_INVALID_ANNOTATION 0x101C +/* 0x101D */ +#define HPDF_INVALID_BIT_PER_COMPONENT 0x101E +#define HPDF_INVALID_CHAR_MATRICS_DATA 0x101F +#define HPDF_INVALID_COLOR_SPACE 0x1020 +#define HPDF_INVALID_COMPRESSION_MODE 0x1021 +#define HPDF_INVALID_DATE_TIME 0x1022 +#define HPDF_INVALID_DESTINATION 0x1023 +/* 0x1024 */ +#define HPDF_INVALID_DOCUMENT 0x1025 +#define HPDF_INVALID_DOCUMENT_STATE 0x1026 +#define HPDF_INVALID_ENCODER 0x1027 +#define HPDF_INVALID_ENCODER_TYPE 0x1028 +/* 0x1029 */ +/* 0x102A */ +#define HPDF_INVALID_ENCODING_NAME 0x102B +#define HPDF_INVALID_ENCRYPT_KEY_LEN 0x102C +#define HPDF_INVALID_FONTDEF_DATA 0x102D +#define HPDF_INVALID_FONTDEF_TYPE 0x102E +#define HPDF_INVALID_FONT_NAME 0x102F +#define HPDF_INVALID_IMAGE 0x1030 +#define HPDF_INVALID_JPEG_DATA 0x1031 +#define HPDF_INVALID_N_DATA 0x1032 +#define HPDF_INVALID_OBJECT 0x1033 +#define HPDF_INVALID_OBJ_ID 0x1034 +#define HPDF_INVALID_OPERATION 0x1035 +#define HPDF_INVALID_OUTLINE 0x1036 +#define HPDF_INVALID_PAGE 0x1037 +#define HPDF_INVALID_PAGES 0x1038 +#define HPDF_INVALID_PARAMETER 0x1039 +/* 0x103A */ +#define HPDF_INVALID_PNG_IMAGE 0x103B +#define HPDF_INVALID_STREAM 0x103C +#define HPDF_MISSING_FILE_NAME_ENTRY 0x103D +/* 0x103E */ +#define HPDF_INVALID_TTC_FILE 0x103F +#define HPDF_INVALID_TTC_INDEX 0x1040 +#define HPDF_INVALID_WX_DATA 0x1041 +#define HPDF_ITEM_NOT_FOUND 0x1042 +#define HPDF_LIBPNG_ERROR 0x1043 +#define HPDF_NAME_INVALID_VALUE 0x1044 +#define HPDF_NAME_OUT_OF_RANGE 0x1045 +/* 0x1046 */ +/* 0x1047 */ +#define HPDF_PAGE_INVALID_PARAM_COUNT 0x1048 +#define HPDF_PAGES_MISSING_KIDS_ENTRY 0x1049 +#define HPDF_PAGE_CANNOT_FIND_OBJECT 0x104A +#define HPDF_PAGE_CANNOT_GET_ROOT_PAGES 0x104B +#define HPDF_PAGE_CANNOT_RESTORE_GSTATE 0x104C +#define HPDF_PAGE_CANNOT_SET_PARENT 0x104D +#define HPDF_PAGE_FONT_NOT_FOUND 0x104E +#define HPDF_PAGE_INVALID_FONT 0x104F +#define HPDF_PAGE_INVALID_FONT_SIZE 0x1050 +#define HPDF_PAGE_INVALID_GMODE 0x1051 +#define HPDF_PAGE_INVALID_INDEX 0x1052 +#define HPDF_PAGE_INVALID_ROTATE_VALUE 0x1053 +#define HPDF_PAGE_INVALID_SIZE 0x1054 +#define HPDF_PAGE_INVALID_XOBJECT 0x1055 +#define HPDF_PAGE_OUT_OF_RANGE 0x1056 +#define HPDF_REAL_OUT_OF_RANGE 0x1057 +#define HPDF_STREAM_EOF 0x1058 +#define HPDF_STREAM_READLN_CONTINUE 0x1059 +/* 0x105A */ +#define HPDF_STRING_OUT_OF_RANGE 0x105B +#define HPDF_THIS_FUNC_WAS_SKIPPED 0x105C +#define HPDF_TTF_CANNOT_EMBEDDING_FONT 0x105D +#define HPDF_TTF_INVALID_CMAP 0x105E +#define HPDF_TTF_INVALID_FOMAT 0x105F +#define HPDF_TTF_MISSING_TABLE 0x1060 +#define HPDF_UNSUPPORTED_FONT_TYPE 0x1061 +#define HPDF_UNSUPPORTED_FUNC 0x1062 +#define HPDF_UNSUPPORTED_JPEG_FORMAT 0x1063 +#define HPDF_UNSUPPORTED_TYPE1_FONT 0x1064 +#define HPDF_XREF_COUNT_ERR 0x1065 +#define HPDF_ZLIB_ERROR 0x1066 +#define HPDF_INVALID_PAGE_INDEX 0x1067 +#define HPDF_INVALID_URI 0x1068 +#define HPDF_PAGE_LAYOUT_OUT_OF_RANGE 0x1069 +#define HPDF_PAGE_MODE_OUT_OF_RANGE 0x1070 +#define HPDF_PAGE_NUM_STYLE_OUT_OF_RANGE 0x1071 +#define HPDF_ANNOT_INVALID_ICON 0x1072 +#define HPDF_ANNOT_INVALID_BORDER_STYLE 0x1073 +#define HPDF_PAGE_INVALID_DIRECTION 0x1074 +#define HPDF_INVALID_FONT 0x1075 +#define HPDF_PAGE_INSUFFICIENT_SPACE 0x1076 +#define HPDF_PAGE_INVALID_DISPLAY_TIME 0x1077 +#define HPDF_PAGE_INVALID_TRANSITION_TIME 0x1078 +#define HPDF_INVALID_PAGE_SLIDESHOW_TYPE 0x1079 +#define HPDF_EXT_GSTATE_OUT_OF_RANGE 0x1080 +#define HPDF_INVALID_EXT_GSTATE 0x1081 +#define HPDF_EXT_GSTATE_READ_ONLY 0x1082 +#define HPDF_INVALID_U3D_DATA 0x1083 +#define HPDF_NAME_CANNOT_GET_NAMES 0x1084 +#define HPDF_INVALID_ICC_COMPONENT_NUM 0x1085 + +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Error ----------------------------------------------------------*/ + +typedef struct _HPDF_Error_Rec *HPDF_Error; + +typedef struct _HPDF_Error_Rec { + HPDF_STATUS error_no; + HPDF_STATUS detail_no; + HPDF_Error_Handler error_fn; + void *user_data; +} HPDF_Error_Rec; + + +/* HPDF_Error_init + * + * if error_fn is NULL, the default-handlers are set as error-handler. + * user_data is used to identify the object which threw an error. + * + */ +void +HPDF_Error_Init (HPDF_Error error, + void *user_data); + + +void +HPDF_Error_Reset (HPDF_Error error); + + +HPDF_STATUS +HPDF_Error_GetCode (HPDF_Error error); + + +HPDF_STATUS +HPDF_Error_GetDetailCode (HPDF_Error error); + + +HPDF_STATUS +HPDF_SetError (HPDF_Error error, + HPDF_STATUS error_no, + HPDF_STATUS detail_no); + + +HPDF_STATUS +HPDF_RaiseError (HPDF_Error error, + HPDF_STATUS error_no, + HPDF_STATUS detail_no); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_ERROR_H */ + diff --git a/code/libharu/hpdf_exdata.h b/code/libharu/hpdf_exdata.h new file mode 100644 index 0000000..e14245f --- /dev/null +++ b/code/libharu/hpdf_exdata.h @@ -0,0 +1,41 @@ +/* + * << Haru Free PDF Library >> -- hpdf_annotation.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_EXDATA_H +#define _HPDF_EXDATA_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*------ HPDF_ExData -----------------------------------------------------*/ + +HPDF_ExData +HPDF_3DAnnotExData_New(HPDF_MMgr mmgr, + HPDF_Xref xref ); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_EXDATA_H */ + diff --git a/code/libharu/hpdf_ext_gstate.h b/code/libharu/hpdf_ext_gstate.h new file mode 100644 index 0000000..415f117 --- /dev/null +++ b/code/libharu/hpdf_ext_gstate.h @@ -0,0 +1,41 @@ +/* + * << Haru Free PDF Library >> -- hpdf_ext_gstate.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_EXT_GSTATE_H +#define _HPDF_EXT_GSTATE_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HPDF_Dict +HPDF_ExtGState_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + + +HPDF_BOOL +HPDF_ExtGState_Validate (HPDF_ExtGState ext_gstate); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_EXT_GSTATE_H */ + diff --git a/code/libharu/hpdf_font.h b/code/libharu/hpdf_font.h new file mode 100644 index 0000000..140e128 --- /dev/null +++ b/code/libharu/hpdf_font.h @@ -0,0 +1,115 @@ +/* + * << Haru Free PDF Library >> -- hpdf_font.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_FONT_H +#define _HPDF_FONT_H + +#include "hpdf_fontdef.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*----------------------------------------------------------------------------*/ +/*----- Writing Mode ---------------------------------------------------------*/ + +typedef enum _HPDF_FontType { + HPDF_FONT_TYPE1 = 0, + HPDF_FONT_TRUETYPE, + HPDF_FONT_TYPE3, + HPDF_FONT_TYPE0_CID, + HPDF_FONT_TYPE0_TT, + HPDF_FONT_CID_TYPE0, + HPDF_FONT_CID_TYPE2, + HPDF_FONT_MMTYPE1 +} HPDF_FontType; + + +typedef HPDF_Dict HPDF_Font; + + +typedef HPDF_TextWidth +(*HPDF_Font_TextWidths_Func) (HPDF_Font font, + const HPDF_BYTE *text, + HPDF_UINT len); + + +typedef HPDF_UINT +(*HPDF_Font_MeasureText_Func) (HPDF_Font font, + const HPDF_BYTE *text, + HPDF_UINT len, + HPDF_REAL width, + HPDF_REAL fontsize, + HPDF_REAL charspace, + HPDF_REAL wordspace, + HPDF_BOOL wordwrap, + HPDF_REAL *real_width); + + +typedef struct _HPDF_FontAttr_Rec *HPDF_FontAttr; + +typedef struct _HPDF_FontAttr_Rec { + HPDF_FontType type; + HPDF_WritingMode writing_mode; + HPDF_Font_TextWidths_Func text_width_fn; + HPDF_Font_MeasureText_Func measure_text_fn; + HPDF_FontDef fontdef; + HPDF_Encoder encoder; + + /* if the encoding-type is HPDF_ENCODER_TYPE_SINGLE_BYTE, the width of + * each charactors are cashed in 'widths'. + * when HPDF_ENCODER_TYPE_DOUBLE_BYTE the width is calculate each time. + */ + HPDF_INT16* widths; + HPDF_BYTE* used; + + HPDF_Xref xref; + HPDF_Font descendant_font; + HPDF_Dict map_stream; + HPDF_Dict cmap_stream; +} HPDF_FontAttr_Rec; + + +HPDF_Font +HPDF_Type1Font_New (HPDF_MMgr mmgr, + HPDF_FontDef fontdef, + HPDF_Encoder encoder, + HPDF_Xref xref); + +HPDF_Font +HPDF_TTFont_New (HPDF_MMgr mmgr, + HPDF_FontDef fontdef, + HPDF_Encoder encoder, + HPDF_Xref xref); + +HPDF_Font +HPDF_Type0Font_New (HPDF_MMgr mmgr, + HPDF_FontDef fontdef, + HPDF_Encoder encoder, + HPDF_Xref xref); + + +HPDF_BOOL +HPDF_Font_Validate (HPDF_Font font); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_FONT_H */ + diff --git a/code/libharu/hpdf_fontdef.h b/code/libharu/hpdf_fontdef.h new file mode 100644 index 0000000..27679b5 --- /dev/null +++ b/code/libharu/hpdf_fontdef.h @@ -0,0 +1,406 @@ +/* + * << Haru Free PDF Library >> -- hpdf_fontdef.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_FONTDEF_H +#define _HPDF_FONTDEF_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define HPDF_FONTDEF_SIG_BYTES 0x464F4E54L + +/*------ collection of flags for defining characteristics. ---*/ + +#define HPDF_FONT_FIXED_WIDTH 1 +#define HPDF_FONT_SERIF 2 +#define HPDF_FONT_SYMBOLIC 4 +#define HPDF_FONT_SCRIPT 8 + /* Reserved 16 */ +#define HPDF_FONT_STD_CHARSET 32 +#define HPDF_FONT_ITALIC 64 + /* Reserved 128 + Reserved 256 + Reserved 512 + Reserved 1024 + Reserved 2048 + Reserved 4096 + Reserved 8192 + Reserved 16384 + Reserved 32768 */ +#define HPDF_FONT_ALL_CAP 65536 +#define HPDF_FONT_SMALL_CAP 131072 +#define HPDF_FONT_FOURCE_BOLD 262144 + +#define HPDF_CID_W_TYPE_FROM_TO 0 +#define HPDF_CID_W_TYPE_FROM_ARRAY 1 + +/*-- HPDF_FontDef ---------------------------------------*/ + +typedef struct _HPDF_CharData { + HPDF_INT16 char_cd; + HPDF_UNICODE unicode; + HPDF_INT16 width; +} HPDF_CharData; + +typedef enum _HPDF_FontDefType { + HPDF_FONTDEF_TYPE_TYPE1, + HPDF_FONTDEF_TYPE_TRUETYPE, + HPDF_FONTDEF_TYPE_CID, + HPDF_FONTDEF_TYPE_UNINITIALIZED, + HPDF_FONTDEF_TYPE_EOF +} HPDF_FontDefType; + +typedef struct _HPDF_CID_Width { + HPDF_UINT16 cid; + HPDF_INT16 width; +} HPDF_CID_Width; + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_FontDef ---------------------------------------------------------*/ + +typedef struct _HPDF_FontDef_Rec *HPDF_FontDef; + +typedef void (*HPDF_FontDef_FreeFunc) (HPDF_FontDef fontdef); + +typedef void (*HPDF_FontDef_CleanFunc) (HPDF_FontDef fontdef); + +typedef HPDF_STATUS (*HPDF_FontDef_InitFunc) (HPDF_FontDef fontdef); + +typedef struct _HPDF_FontDef_Rec { + HPDF_UINT32 sig_bytes; + char base_font[HPDF_LIMIT_MAX_NAME_LEN + 1]; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_FontDefType type; + HPDF_FontDef_CleanFunc clean_fn; + HPDF_FontDef_FreeFunc free_fn; + HPDF_FontDef_InitFunc init_fn; + + HPDF_INT16 ascent; + HPDF_INT16 descent; + HPDF_UINT flags; + HPDF_Box font_bbox; + HPDF_INT16 italic_angle; + HPDF_UINT16 stemv; + HPDF_INT16 avg_width; + HPDF_INT16 max_width; + HPDF_INT16 missing_width; + HPDF_UINT16 stemh; + HPDF_UINT16 x_height; + HPDF_UINT16 cap_height; + + /* the initial value of descriptor entry is NULL. + * when first font-object besed on the fontdef object is created, + * the font-descriptor object is created and descriptor entry is set. + */ + HPDF_Dict descriptor; + HPDF_Stream data; + + HPDF_BOOL valid; + void *attr; +} HPDF_FontDef_Rec; + + +void +HPDF_FontDef_Free (HPDF_FontDef fontdef); + + +void +HPDF_FontDef_Cleanup (HPDF_FontDef fontdef); + + +HPDF_BOOL +HPDF_FontDef_Validate (HPDF_FontDef fontdef); + + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_Type1FontDef ---------------------------------------------------*/ + +typedef struct _HPDF_Type1FontDefAttrRec *HPDF_Type1FontDefAttr; + +typedef struct _HPDF_Type1FontDefAttrRec { + HPDF_BYTE first_char; /* Required */ + HPDF_BYTE last_char; /* Required */ + HPDF_CharData *widths; /* Required */ + HPDF_UINT widths_count; + + HPDF_INT16 leading; + char *char_set; + char encoding_scheme[HPDF_LIMIT_MAX_NAME_LEN + 1]; + HPDF_UINT length1; + HPDF_UINT length2; + HPDF_UINT length3; + HPDF_BOOL is_base14font; + HPDF_BOOL is_fixed_pitch; + + HPDF_Stream font_data; +} HPDF_Type1FontDefAttr_Rec; + + + +HPDF_FontDef +HPDF_Type1FontDef_New (HPDF_MMgr mmgr); + + +HPDF_FontDef +HPDF_Type1FontDef_Load (HPDF_MMgr mmgr, + HPDF_Stream afm, + HPDF_Stream font_data); + + +HPDF_FontDef +HPDF_Type1FontDef_Duplicate (HPDF_MMgr mmgr, + HPDF_FontDef src); + + +HPDF_STATUS +HPDF_Type1FontDef_SetWidths (HPDF_FontDef fontdef, + const HPDF_CharData *widths); + + +HPDF_INT16 +HPDF_Type1FontDef_GetWidthByName (HPDF_FontDef fontdef, + const char *gryph_name); + + +HPDF_INT16 +HPDF_Type1FontDef_GetWidth (HPDF_FontDef fontdef, + HPDF_UNICODE unicode); + + +HPDF_FontDef +HPDF_Base14FontDef_New (HPDF_MMgr mmgr, + const char *font_name); + + + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_TTFontDef ------------------------------------------------------*/ + +#define HPDF_TTF_FONT_TAG_LEN 6 + +typedef struct _HPDF_TTF_Table { + char tag[4]; + HPDF_UINT32 check_sum; + HPDF_UINT32 offset; + HPDF_UINT32 length; +} HPDF_TTFTable; + + +typedef struct _HPDF_TTF_OffsetTbl { + HPDF_UINT32 sfnt_version; + HPDF_UINT16 num_tables; + HPDF_UINT16 search_range; + HPDF_UINT16 entry_selector; + HPDF_UINT16 range_shift; + HPDF_TTFTable *table; +} HPDF_TTF_OffsetTbl; + + +typedef struct _HPDF_TTF_CmapRange { + HPDF_UINT16 format; + HPDF_UINT16 length; + HPDF_UINT16 language; + HPDF_UINT16 seg_count_x2; + HPDF_UINT16 search_range; + HPDF_UINT16 entry_selector; + HPDF_UINT16 range_shift; + HPDF_UINT16 *end_count; + HPDF_UINT16 reserved_pad; + HPDF_UINT16 *start_count; + HPDF_INT16 *id_delta; + HPDF_UINT16 *id_range_offset; + HPDF_UINT16 *glyph_id_array; + HPDF_UINT glyph_id_array_count; +} HPDF_TTF_CmapRange; + + +typedef struct _HPDF_TTF_GryphOffsets { + HPDF_UINT32 base_offset; + HPDF_UINT32 *offsets; + HPDF_BYTE *flgs; /* 0: unused, 1: used */ +} HPDF_TTF_GryphOffsets; + + +typedef struct _HPDF_TTF_LongHorMetric { + HPDF_UINT16 advance_width; + HPDF_INT16 lsb; +} HPDF_TTF_LongHorMetric; + + +typedef struct _HPDF_TTF_FontHeader { + HPDF_BYTE version_number[4]; + HPDF_UINT32 font_revision; + HPDF_UINT32 check_sum_adjustment; + HPDF_UINT32 magic_number; + HPDF_UINT16 flags; + HPDF_UINT16 units_per_em; + HPDF_BYTE created[8]; + HPDF_BYTE modified[8]; + HPDF_INT16 x_min; + HPDF_INT16 y_min; + HPDF_INT16 x_max; + HPDF_INT16 y_max; + HPDF_UINT16 mac_style; + HPDF_UINT16 lowest_rec_ppem; + HPDF_INT16 font_direction_hint; + HPDF_INT16 index_to_loc_format; + HPDF_INT16 glyph_data_format; +} HPDF_TTF_FontHeader; + + +typedef struct _HPDF_TTF_NameRecord { + HPDF_UINT16 platform_id; + HPDF_UINT16 encoding_id; + HPDF_UINT16 language_id; + HPDF_UINT16 name_id; + HPDF_UINT16 length; + HPDF_UINT16 offset; +} HPDF_TTF_NameRecord; + + +typedef struct _HPDF_TTF_NamingTable { + HPDF_UINT16 format; + HPDF_UINT16 count; + HPDF_UINT16 string_offset; + HPDF_TTF_NameRecord *name_records; +} HPDF_TTF_NamingTable; + + +typedef struct _HPDF_TTFontDefAttr_Rec *HPDF_TTFontDefAttr; + +typedef struct _HPDF_TTFontDefAttr_Rec { + char base_font[HPDF_LIMIT_MAX_NAME_LEN + 1]; + HPDF_BYTE first_char; + HPDF_BYTE last_char; + char *char_set; + char tag_name[HPDF_TTF_FONT_TAG_LEN + 1]; + char tag_name2[(HPDF_TTF_FONT_TAG_LEN + 1) * 2]; + HPDF_TTF_FontHeader header; + HPDF_TTF_GryphOffsets glyph_tbl; + HPDF_UINT16 num_glyphs; + HPDF_TTF_NamingTable name_tbl; + HPDF_TTF_LongHorMetric *h_metric; + HPDF_UINT16 num_h_metric; + HPDF_TTF_OffsetTbl offset_tbl; + HPDF_TTF_CmapRange cmap; + HPDF_UINT16 fs_type; + HPDF_BYTE sfamilyclass[2]; + HPDF_BYTE panose[10]; + HPDF_UINT32 code_page_range1; + HPDF_UINT32 code_page_range2; + + HPDF_UINT length1; + + HPDF_BOOL embedding; + HPDF_BOOL is_cidfont; + + HPDF_Stream stream; +} HPDF_TTFontDefAttr_Rec; + + + +HPDF_FontDef +HPDF_TTFontDef_New (HPDF_MMgr mmgr); + + +HPDF_FontDef +HPDF_TTFontDef_Load (HPDF_MMgr mmgr, + HPDF_Stream stream, + HPDF_BOOL embedding); + + +HPDF_FontDef +HPDF_TTFontDef_Load2 (HPDF_MMgr mmgr, + HPDF_Stream stream, + HPDF_UINT index, + HPDF_BOOL embedding); + + +HPDF_UINT16 +HPDF_TTFontDef_GetGlyphid (HPDF_FontDef fontdef, + HPDF_UINT16 unicode); + + +HPDF_INT16 +HPDF_TTFontDef_GetCharWidth (HPDF_FontDef fontdef, + HPDF_UINT16 unicode); + + +HPDF_INT16 +HPDF_TTFontDef_GetGidWidth (HPDF_FontDef fontdef, + HPDF_UINT16 gid); + + +HPDF_STATUS +HPDF_TTFontDef_SaveFontData (HPDF_FontDef fontdef, + HPDF_Stream stream); + + +HPDF_Box +HPDF_TTFontDef_GetCharBBox (HPDF_FontDef fontdef, + HPDF_UINT16 unicode); + + +void +HPDF_TTFontDef_SetTagName (HPDF_FontDef fontdef, + char *tag); + + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_CIDFontDef -----------------------------------------------------*/ + +typedef struct _HPDF_CIDFontDefAttrRec *HPDF_CIDFontDefAttr; + +typedef struct _HPDF_CIDFontDefAttrRec { + HPDF_List widths; + HPDF_INT16 DW; + HPDF_INT16 DW2[2]; +} HPDF_CIDFontDefAttr_Rec; + + +HPDF_FontDef +HPDF_CIDFontDef_New (HPDF_MMgr mmgr, + char *name, + HPDF_FontDef_InitFunc init_fn); + + +HPDF_STATUS +HPDF_CIDFontDef_AddWidth (HPDF_FontDef fontdef, + const HPDF_CID_Width *widths); + + +HPDF_INT16 +HPDF_CIDFontDef_GetCIDWidth (HPDF_FontDef fontdef, + HPDF_UINT16 cid); + + + +HPDF_STATUS +HPDF_CIDFontDef_ChangeStyle (HPDF_FontDef fontdef, + HPDF_BOOL bold, + HPDF_BOOL italic); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_FONTDEF_H */ diff --git a/code/libharu/hpdf_gstate.h b/code/libharu/hpdf_gstate.h new file mode 100644 index 0000000..8f120ac --- /dev/null +++ b/code/libharu/hpdf_gstate.h @@ -0,0 +1,83 @@ +/* + * << Haru Free PDF Library >> -- hpdf_gstate.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_GSTATE_H +#define _HPDF_GSTATE_H + +#include "hpdf_font.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*----------------------------------------------------------------------------*/ +/*------ graphic state stack -------------------------------------------------*/ + +typedef struct _HPDF_GState_Rec *HPDF_GState; + +typedef struct _HPDF_GState_Rec { + HPDF_TransMatrix trans_matrix; + HPDF_REAL line_width; + HPDF_LineCap line_cap; + HPDF_LineJoin line_join; + HPDF_REAL miter_limit; + HPDF_DashMode dash_mode; + HPDF_REAL flatness; + + HPDF_REAL char_space; + HPDF_REAL word_space; + HPDF_REAL h_scalling; + HPDF_REAL text_leading; + HPDF_TextRenderingMode rendering_mode; + HPDF_REAL text_rise; + + HPDF_ColorSpace cs_fill; + HPDF_ColorSpace cs_stroke; + HPDF_RGBColor rgb_fill; + HPDF_RGBColor rgb_stroke; + HPDF_CMYKColor cmyk_fill; + HPDF_CMYKColor cmyk_stroke; + HPDF_REAL gray_fill; + HPDF_REAL gray_stroke; + + HPDF_Font font; + HPDF_REAL font_size; + HPDF_WritingMode writing_mode; + + HPDF_GState prev; + HPDF_UINT depth; +} HPDF_GState_Rec; + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +HPDF_GState +HPDF_GState_New (HPDF_MMgr mmgr, + HPDF_GState current); + + +HPDF_GState +HPDF_GState_Free (HPDF_MMgr mmgr, + HPDF_GState gstate); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_GSTATE_H */ + diff --git a/code/libharu/hpdf_image.h b/code/libharu/hpdf_image.h new file mode 100644 index 0000000..909c8fe --- /dev/null +++ b/code/libharu/hpdf_image.h @@ -0,0 +1,99 @@ +/* + * << Haru Free PDF Library >> -- hpdf_image.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_IMAGE_H +#define _HPDF_IMAGE_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HPDF_Image +HPDF_Image_Load1BitImageFromMem (HPDF_MMgr mmgr, + const HPDF_BYTE *buf, + HPDF_Xref xref, + HPDF_UINT width, + HPDF_UINT height, + HPDF_UINT line_width, + HPDF_BOOL top_is_first + ); + + +#ifndef LIBHPDF_HAVE_NOPNGLIB + +HPDF_Image +HPDF_Image_LoadPngImage (HPDF_MMgr mmgr, + HPDF_Stream png_data, + HPDF_Xref xref, + HPDF_BOOL delayed_loading); + +#endif + +HPDF_Image +HPDF_Image_LoadJpegImage (HPDF_MMgr mmgr, + HPDF_Stream jpeg_data, + HPDF_Xref xref); + +HPDF_Image +HPDF_Image_LoadJpegImageFromMem (HPDF_MMgr mmgr, + const HPDF_BYTE *buf, + HPDF_UINT size, + HPDF_Xref xref); + +HPDF_Image +HPDF_Image_LoadRawImage (HPDF_MMgr mmgr, + HPDF_Stream stream, + HPDF_Xref xref, + HPDF_UINT width, + HPDF_UINT height, + HPDF_ColorSpace color_space); + + +HPDF_Image +HPDF_Image_LoadRawImageFromMem (HPDF_MMgr mmgr, + const HPDF_BYTE *buf, + HPDF_Xref xref, + HPDF_UINT width, + HPDF_UINT height, + HPDF_ColorSpace color_space, + HPDF_UINT bits_per_component); + + +HPDF_BOOL +HPDF_Image_Validate (HPDF_Image image); + + +HPDF_STATUS +HPDF_Image_SetMask (HPDF_Image image, + HPDF_BOOL mask); + +HPDF_STATUS +HPDF_Image_SetColorSpace (HPDF_Image image, + HPDF_Array colorspace); + +HPDF_STATUS +HPDF_Image_SetRenderingIntent (HPDF_Image image, + const char* intent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_XOBJECTS_H */ + diff --git a/code/libharu/hpdf_info.h b/code/libharu/hpdf_info.h new file mode 100644 index 0000000..9fb2a7f --- /dev/null +++ b/code/libharu/hpdf_info.h @@ -0,0 +1,51 @@ +/* + * << Haru Free PDF Library >> -- hpdf_info.c + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + + +#ifndef _HPDF_INFO_H +#define _HPDF_INFO_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +HPDF_STATUS +HPDF_Info_SetInfoAttr (HPDF_Dict info, + HPDF_InfoType type, + const char *value, + HPDF_Encoder encoder); + + +const char* +HPDF_Info_GetInfoAttr (HPDF_Dict info, + HPDF_InfoType type); + + +HPDF_STATUS +HPDF_Info_SetInfoDateAttr (HPDF_Dict info, + HPDF_InfoType type, + HPDF_Date value); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_INFO_H */ + diff --git a/code/libharu/hpdf_list.h b/code/libharu/hpdf_list.h new file mode 100644 index 0000000..09a7047 --- /dev/null +++ b/code/libharu/hpdf_list.h @@ -0,0 +1,88 @@ +/* + * << Haru Free PDF Library >> -- hpdf_list.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_LIST_H +#define _HPDF_LIST_H + +#include "hpdf_error.h" +#include "hpdf_mmgr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _HPDF_List_Rec *HPDF_List; + +typedef struct _HPDF_List_Rec { + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_UINT block_siz; + HPDF_UINT items_per_block; + HPDF_UINT count; + void **obj; +} HPDF_List_Rec; + + +HPDF_List +HPDF_List_New (HPDF_MMgr mmgr, + HPDF_UINT items_per_block); + + +void +HPDF_List_Free (HPDF_List list); + + +HPDF_STATUS +HPDF_List_Add (HPDF_List list, + void *item); + + +HPDF_STATUS +HPDF_List_Insert (HPDF_List list, + void *target, + void *item); + + +HPDF_STATUS +HPDF_List_Remove (HPDF_List list, + void *item); + + +void* +HPDF_List_RemoveByIndex (HPDF_List list, + HPDF_UINT index); + + +void* +HPDF_List_ItemAt (HPDF_List list, + HPDF_UINT index); + + +HPDF_INT32 +HPDF_List_Find (HPDF_List list, + void *item); + + +void +HPDF_List_Clear (HPDF_List list); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_LIST_H */ + diff --git a/code/libharu/hpdf_mmgr.h b/code/libharu/hpdf_mmgr.h new file mode 100644 index 0000000..11ec9b8 --- /dev/null +++ b/code/libharu/hpdf_mmgr.h @@ -0,0 +1,85 @@ +/* + * << Haru Free PDF Library >> -- hpdf_mmgr.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_MMGR_H +#define _HPDF_MMGR_H + +#include "hpdf_types.h" +#include "hpdf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _HPDF_MPool_Node_Rec *HPDF_MPool_Node; + +typedef struct _HPDF_MPool_Node_Rec { + HPDF_BYTE* buf; + HPDF_UINT size; + HPDF_UINT used_size; + HPDF_MPool_Node next_node; +} HPDF_MPool_Node_Rec; + + +typedef struct _HPDF_MMgr_Rec *HPDF_MMgr; + +typedef struct _HPDF_MMgr_Rec { + HPDF_Error error; + HPDF_Alloc_Func alloc_fn; + HPDF_Free_Func free_fn; + HPDF_MPool_Node mpool; + HPDF_UINT buf_size; + +#ifdef HPDF_MEM_DEBUG + HPDF_UINT alloc_cnt; + HPDF_UINT free_cnt; +#endif +} HPDF_MMgr_Rec; + + +/* HPDF_mpool_new + * + * create new HPDF_mpool object. when memory allocation goes wrong, + * it returns NULL and error handling function will be called. + * if buf_size is non-zero, mmgr is configured to be using memory-pool + */ +HPDF_MMgr +HPDF_MMgr_New (HPDF_Error error, + HPDF_UINT buf_size, + HPDF_Alloc_Func alloc_fn, + HPDF_Free_Func free_fn); + + +void +HPDF_MMgr_Free (HPDF_MMgr mmgr); + + +void* +HPDF_GetMem (HPDF_MMgr mmgr, + HPDF_UINT size); + + +void +HPDF_FreeMem (HPDF_MMgr mmgr, + void *aptr); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_MMGR_H */ + diff --git a/code/libharu/hpdf_namedict.h b/code/libharu/hpdf_namedict.h new file mode 100644 index 0000000..5632f99 --- /dev/null +++ b/code/libharu/hpdf_namedict.h @@ -0,0 +1,76 @@ +/* + * << Haru Free PDF Library >> -- hpdf_namedict.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_NAMEDICT_H +#define _HPDF_NAMEDICT_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +HPDF_NameDict +HPDF_NameDict_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + +HPDF_NameTree +HPDF_NameDict_GetNameTree (HPDF_NameDict namedict, + HPDF_NameDictKey key); + +HPDF_STATUS +HPDF_NameDict_SetNameTree (HPDF_NameDict namedict, + HPDF_NameDictKey key, + HPDF_NameTree tree); + +HPDF_BOOL +HPDF_NameDict_Validate (HPDF_NameDict namedict); + + +/*------- NameTree -------*/ + +HPDF_NameTree +HPDF_NameTree_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + +HPDF_STATUS +HPDF_NameTree_Add (HPDF_NameTree tree, + HPDF_String name, + void *obj); + +HPDF_BOOL +HPDF_NameTree_Validate (HPDF_NameTree tree); + + +/*------- EmbeddedFile -------*/ + +HPDF_EmbeddedFile +HPDF_EmbeddedFile_New (HPDF_MMgr mmgr, + HPDF_Xref xref, + const char *file); + +HPDF_BOOL +HPDF_EmbeddedFile_Validate (HPDF_EmbeddedFile emfile); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_NAMEDICT_H */ + diff --git a/code/libharu/hpdf_objects.h b/code/libharu/hpdf_objects.h new file mode 100644 index 0000000..74fc445 --- /dev/null +++ b/code/libharu/hpdf_objects.h @@ -0,0 +1,604 @@ +/* + * << Haru Free PDF Library >> -- hpdf_objects.c + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_OBJECTS_H +#define _HPDF_OBJECTS_H + +#include "hpdf_encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* if HPDF_OTYPE_DIRECT bit is set, the object owned by other container + * object. if HPDF_OTYPE_INDIRECT bit is set, the object managed by xref. + */ + +#define HPDF_OTYPE_NONE 0x00000000 +#define HPDF_OTYPE_DIRECT 0x80000000 +#define HPDF_OTYPE_INDIRECT 0x40000000 +#define HPDF_OTYPE_ANY (HPDF_OTYPE_DIRECT | HPDF_OTYPE_INDIRECT) +#define HPDF_OTYPE_HIDDEN 0x10000000 + +#define HPDF_OCLASS_UNKNOWN 0x0001 +#define HPDF_OCLASS_NULL 0x0002 +#define HPDF_OCLASS_BOOLEAN 0x0003 +#define HPDF_OCLASS_NUMBER 0x0004 +#define HPDF_OCLASS_REAL 0x0005 +#define HPDF_OCLASS_NAME 0x0006 +#define HPDF_OCLASS_STRING 0x0007 +#define HPDF_OCLASS_BINARY 0x0008 +#define HPDF_OCLASS_ARRAY 0x0010 +#define HPDF_OCLASS_DICT 0x0011 +#define HPDF_OCLASS_PROXY 0x0012 +#define HPDF_OCLASS_ANY 0x00FF + +#define HPDF_OSUBCLASS_FONT 0x0100 +#define HPDF_OSUBCLASS_CATALOG 0x0200 +#define HPDF_OSUBCLASS_PAGES 0x0300 +#define HPDF_OSUBCLASS_PAGE 0x0400 +#define HPDF_OSUBCLASS_XOBJECT 0x0500 +#define HPDF_OSUBCLASS_OUTLINE 0x0600 +#define HPDF_OSUBCLASS_DESTINATION 0x0700 +#define HPDF_OSUBCLASS_ANNOTATION 0x0800 +#define HPDF_OSUBCLASS_ENCRYPT 0x0900 +#define HPDF_OSUBCLASS_EXT_GSTATE 0x0A00 +#define HPDF_OSUBCLASS_EXT_GSTATE_R 0x0B00 /* read only object */ +#define HPDF_OSUBCLASS_NAMEDICT 0x0C00 +#define HPDF_OSUBCLASS_NAMETREE 0x0D00 + + + +/*----------------------------------------------------------------------------*/ +/*------ Values related xref -------------------------------------------------*/ + +#define HPDF_FREE_ENTRY 'f' +#define HPDF_IN_USE_ENTRY 'n' + + +/* + * structure of Object-ID + * + * 1 direct-object + * 2 indirect-object + * 3 reserved + * 4 shadow-object + * 5-8 reserved + * 9-32 object-idi0-8388607j + * + * the real Object-ID is described "obj_id & 0x00FFFFFF" + */ + +typedef struct _HPDF_Obj_Header { + HPDF_UINT32 obj_id; + HPDF_UINT16 gen_no; + HPDF_UINT16 obj_class; +} HPDF_Obj_Header; + + + +HPDF_STATUS +HPDF_Obj_WriteValue (void *obj, + HPDF_Stream stream, + HPDF_Encrypt e); + + +HPDF_STATUS +HPDF_Obj_Write (void *obj, + HPDF_Stream stream, + HPDF_Encrypt e); + + +void +HPDF_Obj_Free (HPDF_MMgr mmgr, + void *obj); + + +void +HPDF_Obj_ForceFree (HPDF_MMgr mmgr, + void *obj); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Null -----------------------------------------------------------*/ + +typedef struct _HPDF_Null_Rec *HPDF_Null; + +typedef struct _HPDF_Null_Rec { + HPDF_Obj_Header header; +} HPDF_Null_Rec; + + + +HPDF_Null +HPDF_Null_New (HPDF_MMgr mmgr); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Boolean --------------------------------------------------------*/ + +typedef struct _HPDF_Boolean_Rec *HPDF_Boolean; + +typedef struct _HPDF_Boolean_Rec { + HPDF_Obj_Header header; + HPDF_BOOL value; +} HPDF_Boolean_Rec; + + + +HPDF_Boolean +HPDF_Boolean_New (HPDF_MMgr mmgr, + HPDF_BOOL value); + + +HPDF_STATUS +HPDF_Boolean_Write (HPDF_Boolean obj, + HPDF_Stream stream); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Number ---------------------------------------------------------*/ + +typedef struct _HPDF_Number_Rec *HPDF_Number; + +typedef struct _HPDF_Number_Rec { + HPDF_Obj_Header header; + HPDF_INT32 value; +} HPDF_Number_Rec; + + + +HPDF_Number +HPDF_Number_New (HPDF_MMgr mmgr, + HPDF_INT32 value); + + +void +HPDF_Number_SetValue (HPDF_Number obj, + HPDF_INT32 value); + + +HPDF_STATUS +HPDF_Number_Write (HPDF_Number obj, + HPDF_Stream stream); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Real -----------------------------------------------------------*/ + +typedef struct _HPDF_Real_Rec *HPDF_Real; + +typedef struct _HPDF_Real_Rec { + HPDF_Obj_Header header; + HPDF_Error error; + HPDF_REAL value; +} HPDF_Real_Rec; + + + +HPDF_Real +HPDF_Real_New (HPDF_MMgr mmgr, + HPDF_REAL value); + + +HPDF_STATUS +HPDF_Real_Write (HPDF_Real obj, + HPDF_Stream stream); + + +HPDF_STATUS +HPDF_Real_SetValue (HPDF_Real obj, + HPDF_REAL value); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Name -----------------------------------------------------------*/ + +typedef struct _HPDF_Name_Rec *HPDF_Name; + +typedef struct _HPDF_Name_Rec { + HPDF_Obj_Header header; + HPDF_Error error; + char value[HPDF_LIMIT_MAX_NAME_LEN + 1]; +} HPDF_Name_Rec; + + + +HPDF_Name +HPDF_Name_New (HPDF_MMgr mmgr, + const char *value); + + +HPDF_STATUS +HPDF_Name_SetValue (HPDF_Name obj, + const char *value); + + +HPDF_STATUS +HPDF_Name_Write (HPDF_Name obj, + HPDF_Stream stream); + +const char* +HPDF_Name_GetValue (HPDF_Name obj); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_String ---------------------------------------------------------*/ + +typedef struct _HPDF_String_Rec *HPDF_String; + +typedef struct _HPDF_String_Rec { + HPDF_Obj_Header header; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_Encoder encoder; + HPDF_BYTE *value; + HPDF_UINT len; +} HPDF_String_Rec; + + + +HPDF_String +HPDF_String_New (HPDF_MMgr mmgr, + const char *value, + HPDF_Encoder encoder); + + +HPDF_STATUS +HPDF_String_SetValue (HPDF_String obj, + const char *value); + + +void +HPDF_String_Free (HPDF_String obj); + + +HPDF_STATUS +HPDF_String_Write (HPDF_String obj, + HPDF_Stream stream, + HPDF_Encrypt e); + +HPDF_INT32 +HPDF_String_Cmp (HPDF_String s1, + HPDF_String s2); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Binary ---------------------------------------------------------*/ + +typedef struct _HPDF_Binary_Rec *HPDF_Binary; + +typedef struct _HPDF_Binary_Rec { + HPDF_Obj_Header header; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_BYTE *value; + HPDF_UINT len; +} HPDF_Binary_Rec; + + + +HPDF_Binary +HPDF_Binary_New (HPDF_MMgr mmgr, + HPDF_BYTE *value, + HPDF_UINT len); + + +HPDF_STATUS +HPDF_Binary_SetValue (HPDF_Binary obj, + HPDF_BYTE *value, + HPDF_UINT len); + + +HPDF_BYTE* +HPDF_Binary_GetValue (HPDF_Binary obj); + + +void +HPDF_Binary_Free (HPDF_Binary obj); + + +HPDF_STATUS +HPDF_Binary_Write (HPDF_Binary obj, + HPDF_Stream stream, + HPDF_Encrypt e); + + +HPDF_UINT +HPDF_Binary_GetLen (HPDF_Binary obj); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Array ----------------------------------------------------------*/ + +typedef struct _HPDF_Array_Rec *HPDF_Array; + +typedef struct _HPDF_Array_Rec { + HPDF_Obj_Header header; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_List list; +} HPDF_Array_Rec; + + +HPDF_Array +HPDF_Array_New (HPDF_MMgr mmgr); + + +HPDF_Array +HPDF_Box_Array_New (HPDF_MMgr mmgr, + HPDF_Box box); + + +void +HPDF_Array_Free (HPDF_Array array); + + +HPDF_STATUS +HPDF_Array_Write (HPDF_Array array, + HPDF_Stream stream, + HPDF_Encrypt e); + + +HPDF_STATUS +HPDF_Array_Add (HPDF_Array array, + void *obj); + + +HPDF_STATUS +HPDF_Array_Insert (HPDF_Array array, + void *target, + void *obj); + + +void* +HPDF_Array_GetItem (HPDF_Array array, + HPDF_UINT index, + HPDF_UINT16 obj_class); + + +HPDF_STATUS +HPDF_Array_AddNumber (HPDF_Array array, + HPDF_INT32 value); + + +HPDF_STATUS +HPDF_Array_AddReal (HPDF_Array array, + HPDF_REAL value); + + +HPDF_STATUS +HPDF_Array_AddName (HPDF_Array array, + const char *value); + +void +HPDF_Array_Clear (HPDF_Array array); + + +HPDF_UINT +HPDF_Array_Items (HPDF_Array array); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Dict -----------------------------------------------------------*/ + +typedef struct _HPDF_Xref_Rec *HPDF_Xref; + +typedef struct _HPDF_Dict_Rec *HPDF_Dict; + +typedef void +(*HPDF_Dict_FreeFunc) (HPDF_Dict obj); + +typedef HPDF_STATUS +(*HPDF_Dict_BeforeWriteFunc) (HPDF_Dict obj); + +typedef HPDF_STATUS +(*HPDF_Dict_AfterWriteFunc) (HPDF_Dict obj); + +typedef HPDF_STATUS +(*HPDF_Dict_OnWriteFunc) (HPDF_Dict obj, + HPDF_Stream stream); + +typedef struct _HPDF_Dict_Rec { + HPDF_Obj_Header header; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_List list; + HPDF_Dict_BeforeWriteFunc before_write_fn; + HPDF_Dict_OnWriteFunc write_fn; + HPDF_Dict_AfterWriteFunc after_write_fn; + HPDF_Dict_FreeFunc free_fn; + HPDF_Stream stream; + HPDF_UINT filter; + HPDF_Dict filterParams; + void *attr; +} HPDF_Dict_Rec; + + +typedef struct _HPDF_DictElement_Rec *HPDF_DictElement; + +typedef struct _HPDF_DictElement_Rec { + char key[HPDF_LIMIT_MAX_NAME_LEN + 1]; + void *value; +} HPDF_DictElement_Rec; + + +HPDF_Dict +HPDF_Dict_New (HPDF_MMgr mmgr); + + +HPDF_Dict +HPDF_DictStream_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + + +void +HPDF_Dict_Free (HPDF_Dict dict); + + +HPDF_STATUS +HPDF_Dict_Write (HPDF_Dict dict, + HPDF_Stream stream, + HPDF_Encrypt e); + + +const char* +HPDF_Dict_GetKeyByObj (HPDF_Dict dict, + void *obj); + + +HPDF_STATUS +HPDF_Dict_Add (HPDF_Dict dict, + const char *key, + void *obj); + + +void* +HPDF_Dict_GetItem (HPDF_Dict dict, + const char *key, + HPDF_UINT16 obj_class); + + +HPDF_STATUS +HPDF_Dict_AddName (HPDF_Dict dict, + const char *key, + const char *value); + + +HPDF_STATUS +HPDF_Dict_AddNumber (HPDF_Dict dict, + const char *key, + HPDF_INT32 value); + + +HPDF_STATUS +HPDF_Dict_AddReal (HPDF_Dict dict, + const char *key, + HPDF_REAL value); + + +HPDF_STATUS +HPDF_Dict_AddBoolean (HPDF_Dict dict, + const char *key, + HPDF_BOOL value); + + +HPDF_STATUS +HPDF_Dict_RemoveElement (HPDF_Dict dict, + const char *key); + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_ProxyObject ----------------------------------------------------*/ + + + +typedef struct _HPDF_Proxy_Rec *HPDF_Proxy; + +typedef struct _HPDF_Proxy_Rec { + HPDF_Obj_Header header; + void *obj; +} HPDF_Proxy_Rec; + + +HPDF_Proxy +HPDF_Proxy_New (HPDF_MMgr mmgr, + void *obj); + + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_Xref -----------------------------------------------------------*/ + +typedef struct _HPDF_XrefEntry_Rec *HPDF_XrefEntry; + +typedef struct _HPDF_XrefEntry_Rec { + char entry_typ; + HPDF_UINT byte_offset; + HPDF_UINT16 gen_no; + void* obj; +} HPDF_XrefEntry_Rec; + + +typedef struct _HPDF_Xref_Rec { + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_UINT32 start_offset; + HPDF_List entries; + HPDF_UINT addr; + HPDF_Xref prev; + HPDF_Dict trailer; +} HPDF_Xref_Rec; + + +HPDF_Xref +HPDF_Xref_New (HPDF_MMgr mmgr, + HPDF_UINT32 offset); + + +void +HPDF_Xref_Free (HPDF_Xref xref); + + +HPDF_STATUS +HPDF_Xref_Add (HPDF_Xref xref, + void *obj); + + +HPDF_XrefEntry +HPDF_Xref_GetEntry (HPDF_Xref xref, + HPDF_UINT index); + + +HPDF_STATUS +HPDF_Xref_WriteToStream (HPDF_Xref xref, + HPDF_Stream stream, + HPDF_Encrypt e); + + +HPDF_XrefEntry +HPDF_Xref_GetEntryByObjectId (HPDF_Xref xref, + HPDF_UINT obj_id); + + + +typedef HPDF_Dict HPDF_EmbeddedFile; +typedef HPDF_Dict HPDF_NameDict; +typedef HPDF_Dict HPDF_NameTree; +typedef HPDF_Dict HPDF_Pages; +typedef HPDF_Dict HPDF_Page; +typedef HPDF_Dict HPDF_Annotation; +typedef HPDF_Dict HPDF_3DMeasure; +typedef HPDF_Dict HPDF_ExData; +typedef HPDF_Dict HPDF_XObject; +typedef HPDF_Dict HPDF_Image; +typedef HPDF_Dict HPDF_Outline; +typedef HPDF_Dict HPDF_EncryptDict; +typedef HPDF_Dict HPDF_Action; +typedef HPDF_Dict HPDF_ExtGState; +typedef HPDF_Array HPDF_Destination; +typedef HPDF_Dict HPDF_U3D; +typedef HPDF_Dict HPDF_OutputIntent; +typedef HPDF_Dict HPDF_JavaScript; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_OBJECTS_H */ + diff --git a/code/libharu/hpdf_outline.h b/code/libharu/hpdf_outline.h new file mode 100644 index 0000000..840f5b0 --- /dev/null +++ b/code/libharu/hpdf_outline.h @@ -0,0 +1,77 @@ +/* + * << Haru Free PDF Library >> -- hpdf_outline.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_OUTLINE_H +#define _HPDF_OUTLINE_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_Outline ---------------------------------------------------------*/ + +HPDF_Outline +HPDF_OutlineRoot_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + + +HPDF_Outline +HPDF_Outline_New (HPDF_MMgr mmgr, + HPDF_Outline parent, + const char *title, + HPDF_Encoder encoder, + HPDF_Xref xref); + + +HPDF_Outline +HPDF_Outline_GetFirst (HPDF_Outline outline); + + +HPDF_Outline +HPDF_Outline_GetLast (HPDF_Outline outline); + + +HPDF_Outline +HPDF_Outline_GetPrev(HPDF_Outline outline); + + +HPDF_Outline +HPDF_Outline_GetNext (HPDF_Outline outline); + + +HPDF_Outline +HPDF_Outline_GetParent (HPDF_Outline outline); + + +HPDF_BOOL +HPDF_Outline_GetOpened (HPDF_Outline outline); + + + +HPDF_BOOL +HPDF_Outline_Validate (HPDF_Outline obj); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_OUTLINE_H */ + diff --git a/code/libharu/hpdf_page_label.h b/code/libharu/hpdf_page_label.h new file mode 100644 index 0000000..077a354 --- /dev/null +++ b/code/libharu/hpdf_page_label.h @@ -0,0 +1,38 @@ +/* + * << Haru Free PDF Library >> -- hpdf_page_label.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_PAGE_LABEL_H +#define _HPDF_PAGE_LABEL_H + +#include "hpdf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HPDF_Dict +HPDF_PageLabel_New (HPDF_Doc pdf, + HPDF_PageNumStyle style, + HPDF_INT first_page, + const char *prefix); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/code/libharu/hpdf_pages.h b/code/libharu/hpdf_pages.h new file mode 100644 index 0000000..dc42062 --- /dev/null +++ b/code/libharu/hpdf_pages.h @@ -0,0 +1,131 @@ +/* + * << Haru Free PDF Library >> -- hpdf_pages.c + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_PAGES_H +#define _HPDF_PAGES_H + +#include "hpdf_gstate.h" +#include "hpdf_ext_gstate.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_Pages -----------------------------------------------------------*/ + +HPDF_Pages +HPDF_Pages_New (HPDF_MMgr mmgr, + HPDF_Pages parent, + HPDF_Xref xref); + + +HPDF_BOOL +HPDF_Pages_Validate (HPDF_Pages pages); + + +HPDF_STATUS +HPDF_Pages_AddKids (HPDF_Pages parent, + HPDF_Dict kid); + + +HPDF_STATUS +HPDF_Page_InsertBefore (HPDF_Page page, + HPDF_Page target); + + +typedef struct _HPDF_PageAttr_Rec *HPDF_PageAttr; + +typedef struct _HPDF_PageAttr_Rec { + HPDF_Pages parent; + HPDF_Dict fonts; + HPDF_Dict xobjects; + HPDF_Dict ext_gstates; + HPDF_GState gstate; + HPDF_Point str_pos; + HPDF_Point cur_pos; + HPDF_Point text_pos; + HPDF_TransMatrix text_matrix; + HPDF_UINT16 gmode; + HPDF_Dict contents; + HPDF_Stream stream; + HPDF_Xref xref; + HPDF_UINT compression_mode; + HPDF_PDFVer *ver; +} HPDF_PageAttr_Rec; + + +/*----------------------------------------------------------------------------*/ +/*----- HPDF_Page ------------------------------------------------------------*/ + +HPDF_BOOL +HPDF_Page_Validate (HPDF_Page page); + + +HPDF_Page +HPDF_Page_New (HPDF_MMgr mmgr, + HPDF_Xref xref); + + +void* +HPDF_Page_GetInheritableItem (HPDF_Page page, + const char *key, + HPDF_UINT16 obj_class); + + +const char* +HPDF_Page_GetXObjectName (HPDF_Page page, + HPDF_XObject xobj); + + +const char* +HPDF_Page_GetLocalFontName (HPDF_Page page, + HPDF_Font font); + + +const char* +HPDF_Page_GetExtGStateName (HPDF_Page page, + HPDF_ExtGState gstate); + + +HPDF_Box +HPDF_Page_GetMediaBox (HPDF_Page page); + + +HPDF_STATUS +HPDF_Page_SetBoxValue (HPDF_Page page, + const char *name, + HPDF_UINT index, + HPDF_REAL value); + + +void +HPDF_Page_SetFilter (HPDF_Page page, + HPDF_UINT filter); + + +HPDF_STATUS +HPDF_Page_CheckState (HPDF_Page page, + HPDF_UINT mode); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_PAGES_H */ + diff --git a/code/libharu/hpdf_pdfa.h b/code/libharu/hpdf_pdfa.h new file mode 100644 index 0000000..e3e5b08 --- /dev/null +++ b/code/libharu/hpdf_pdfa.h @@ -0,0 +1,43 @@ +/* + * << Haru Free PDF Library >> -- hpdf_pdfa.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_PDFA_H +#define _HPDF_PDFA_H + +#include "hpdf_doc.h" +#include "hpdf_objects.h" + + + +#ifdef __cplusplus +extern "C" { +#endif + +HPDF_STATUS +HPDF_PDFA_AppendOutputIntents(HPDF_Doc pdf, const char *iccname, HPDF_Dict iccdict); + +HPDF_STATUS +HPDF_PDFA_SetPDFAConformance (HPDF_Doc pdf, + HPDF_PDFAType pdfatype); + +HPDF_STATUS +HPDF_PDFA_GenerateID(HPDF_Doc); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/libharu/hpdf_streams.h b/code/libharu/hpdf_streams.h new file mode 100644 index 0000000..18336f0 --- /dev/null +++ b/code/libharu/hpdf_streams.h @@ -0,0 +1,280 @@ +/* + * << Haru Free PDF Library >> -- hpdf_streams.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + * 2005.12.20 Created. + * + */ + +#ifndef _HPDF_STREAMS_H +#define _HPDF_STREAMS_H + +#include "hpdf_list.h" +#include "hpdf_encrypt.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define HPDF_STREAM_SIG_BYTES 0x5354524DL + +typedef enum _HPDF_StreamType { + HPDF_STREAM_UNKNOWN = 0, + HPDF_STREAM_CALLBACK, + HPDF_STREAM_FILE, + HPDF_STREAM_MEMORY +} HPDF_StreamType; + +#define HPDF_STREAM_FILTER_NONE 0x0000 +#define HPDF_STREAM_FILTER_ASCIIHEX 0x0100 +#define HPDF_STREAM_FILTER_ASCII85 0x0200 +#define HPDF_STREAM_FILTER_FLATE_DECODE 0x0400 +#define HPDF_STREAM_FILTER_DCT_DECODE 0x0800 +#define HPDF_STREAM_FILTER_CCITT_DECODE 0x1000 + +typedef enum _HPDF_WhenceMode { + HPDF_SEEK_SET = 0, + HPDF_SEEK_CUR, + HPDF_SEEK_END +} HPDF_WhenceMode; + +typedef struct _HPDF_Stream_Rec *HPDF_Stream; + +typedef HPDF_STATUS +(*HPDF_Stream_Write_Func) (HPDF_Stream stream, + const HPDF_BYTE *ptr, + HPDF_UINT siz); + + +typedef HPDF_STATUS +(*HPDF_Stream_Read_Func) (HPDF_Stream stream, + HPDF_BYTE *ptr, + HPDF_UINT *siz); + + +typedef HPDF_STATUS +(*HPDF_Stream_Seek_Func) (HPDF_Stream stream, + HPDF_INT pos, + HPDF_WhenceMode mode); + + +typedef HPDF_INT32 +(*HPDF_Stream_Tell_Func) (HPDF_Stream stream); + + +typedef void +(*HPDF_Stream_Free_Func) (HPDF_Stream stream); + + +typedef HPDF_UINT32 +(*HPDF_Stream_Size_Func) (HPDF_Stream stream); + + +typedef struct _HPDF_MemStreamAttr_Rec *HPDF_MemStreamAttr; + + +typedef struct _HPDF_MemStreamAttr_Rec { + HPDF_List buf; + HPDF_UINT buf_siz; + HPDF_UINT w_pos; + HPDF_BYTE *w_ptr; + HPDF_UINT r_ptr_idx; + HPDF_UINT r_pos; + HPDF_BYTE *r_ptr; +} HPDF_MemStreamAttr_Rec; + + +typedef struct _HPDF_Stream_Rec { + HPDF_UINT32 sig_bytes; + HPDF_StreamType type; + HPDF_MMgr mmgr; + HPDF_Error error; + HPDF_UINT size; + HPDF_Stream_Write_Func write_fn; + HPDF_Stream_Read_Func read_fn; + HPDF_Stream_Seek_Func seek_fn; + HPDF_Stream_Free_Func free_fn; + HPDF_Stream_Tell_Func tell_fn; + HPDF_Stream_Size_Func size_fn; + void* attr; +} HPDF_Stream_Rec; + + + +HPDF_Stream +HPDF_MemStream_New (HPDF_MMgr mmgr, + HPDF_UINT buf_siz); + + +HPDF_BYTE* +HPDF_MemStream_GetBufPtr (HPDF_Stream stream, + HPDF_UINT index, + HPDF_UINT *length); + + +HPDF_UINT +HPDF_MemStream_GetBufSize (HPDF_Stream stream); + + +HPDF_UINT +HPDF_MemStream_GetBufCount (HPDF_Stream stream); + + +HPDF_STATUS +HPDF_MemStream_Rewrite (HPDF_Stream stream, + HPDF_BYTE *buf, + HPDF_UINT size); + + +void +HPDF_MemStream_FreeData (HPDF_Stream stream); + + +HPDF_STATUS +HPDF_Stream_WriteToStream (HPDF_Stream src, + HPDF_Stream dst, + HPDF_UINT filter, + HPDF_Encrypt e); + + +HPDF_Stream +HPDF_FileReader_New (HPDF_MMgr mmgr, + const char *fname); + + +HPDF_Stream +HPDF_FileWriter_New (HPDF_MMgr mmgr, + const char *fname); + + +HPDF_Stream +HPDF_CallbackReader_New (HPDF_MMgr mmgr, + HPDF_Stream_Read_Func read_fn, + HPDF_Stream_Seek_Func seek_fn, + HPDF_Stream_Tell_Func tell_fn, + HPDF_Stream_Size_Func size_fn, + void* data); + + +HPDF_Stream +HPDF_CallbackWriter_New (HPDF_MMgr mmgr, + HPDF_Stream_Write_Func write_fn, + void* data); + + +void +HPDF_Stream_Free (HPDF_Stream stream); + + +HPDF_STATUS +HPDF_Stream_WriteChar (HPDF_Stream stream, + char value); + + +HPDF_STATUS +HPDF_Stream_WriteStr (HPDF_Stream stream, + const char *value); + + +HPDF_STATUS +HPDF_Stream_WriteUChar (HPDF_Stream stream, + HPDF_BYTE value); + + +HPDF_STATUS +HPDF_Stream_WriteInt (HPDF_Stream stream, + HPDF_INT value); + + +HPDF_STATUS +HPDF_Stream_WriteUInt (HPDF_Stream stream, + HPDF_UINT value); + + +HPDF_STATUS +HPDF_Stream_WriteReal (HPDF_Stream stream, + HPDF_REAL value); + + +HPDF_STATUS +HPDF_Stream_Write (HPDF_Stream stream, + const HPDF_BYTE *ptr, + HPDF_UINT size); + + +HPDF_STATUS +HPDF_Stream_Read (HPDF_Stream stream, + HPDF_BYTE *ptr, + HPDF_UINT *size); + +HPDF_STATUS +HPDF_Stream_ReadLn (HPDF_Stream stream, + char *s, + HPDF_UINT *size); + + +HPDF_INT32 +HPDF_Stream_Tell (HPDF_Stream stream); + + +HPDF_STATUS +HPDF_Stream_Seek (HPDF_Stream stream, + HPDF_INT pos, + HPDF_WhenceMode mode); + + +HPDF_BOOL +HPDF_Stream_EOF (HPDF_Stream stream); + + +HPDF_UINT32 +HPDF_Stream_Size (HPDF_Stream stream); + +HPDF_STATUS +HPDF_Stream_Flush (HPDF_Stream stream); + + +HPDF_STATUS +HPDF_Stream_WriteEscapeName (HPDF_Stream stream, + const char *value); + + +HPDF_STATUS +HPDF_Stream_WriteEscapeText2 (HPDF_Stream stream, + const char *text, + HPDF_UINT len); + + +HPDF_STATUS +HPDF_Stream_WriteEscapeText (HPDF_Stream stream, + const char *text); + + +HPDF_STATUS +HPDF_Stream_WriteBinary (HPDF_Stream stream, + const HPDF_BYTE *data, + HPDF_UINT len, + HPDF_Encrypt e); + + +HPDF_STATUS +HPDF_Stream_Validate (HPDF_Stream stream); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_STREAMS_H */ diff --git a/code/libharu/hpdf_types.h b/code/libharu/hpdf_types.h new file mode 100644 index 0000000..b9c4589 --- /dev/null +++ b/code/libharu/hpdf_types.h @@ -0,0 +1,565 @@ +/* + * << Haru Free PDF Library >> -- hpdf_types.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_TYPES_H +#define _HPDF_TYPES_H + +#ifndef HPDF_STDCALL +#ifdef HPDF_DLL_MAKE +#define HPDF_STDCALL __stdcall +#else +#ifdef HPDF_DLL +#define HPDF_STDCALL __stdcall +#else +#define HPDF_STDCALL +#endif +#endif +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------*/ +/*----- type definition ------------------------------------------------------*/ + + +/* native OS integer types */ +typedef signed int HPDF_INT; +typedef unsigned int HPDF_UINT; + + +/* 32bit integer types + */ +typedef signed int HPDF_INT32; +typedef unsigned int HPDF_UINT32; + + +/* 16bit integer types + */ +typedef signed short HPDF_INT16; +typedef unsigned short HPDF_UINT16; + + +/* 8bit integer types + */ +typedef signed char HPDF_INT8; +typedef unsigned char HPDF_UINT8; + + +/* 8bit binary types + */ +typedef unsigned char HPDF_BYTE; + + +/* float type (32bit IEEE754) + */ +typedef float HPDF_REAL; + + +/* double type (64bit IEEE754) + */ +typedef double HPDF_DOUBLE; + + +/* boolean type (0: False, !0: True) + */ +typedef signed int HPDF_BOOL; + + +/* error-no type (32bit unsigned integer) + */ +typedef unsigned long HPDF_STATUS; + + +/* charactor-code type (16bit) + */ +typedef HPDF_UINT16 HPDF_CID; +typedef HPDF_UINT16 HPDF_UNICODE; + + +/* HPDF_Point struct + */ +typedef struct _HPDF_Point { + HPDF_REAL x; + HPDF_REAL y; +} HPDF_Point; + +typedef struct _HPDF_Rect { + HPDF_REAL left; + HPDF_REAL bottom; + HPDF_REAL right; + HPDF_REAL top; +} HPDF_Rect; + +/* HPDF_Point3D struct +*/ +typedef struct _HPDF_Point3D { + HPDF_REAL x; + HPDF_REAL y; + HPDF_REAL z; +} HPDF_Point3D; + +typedef struct _HPDF_Rect HPDF_Box; + +/* HPDF_Date struct + */ +typedef struct _HPDF_Date { + HPDF_INT year; + HPDF_INT month; + HPDF_INT day; + HPDF_INT hour; + HPDF_INT minutes; + HPDF_INT seconds; + char ind; + HPDF_INT off_hour; + HPDF_INT off_minutes; +} HPDF_Date; + + +typedef enum _HPDF_InfoType { + /* date-time type parameters */ + HPDF_INFO_CREATION_DATE = 0, + HPDF_INFO_MOD_DATE, + + /* string type parameters */ + HPDF_INFO_AUTHOR, + HPDF_INFO_CREATOR, + HPDF_INFO_PRODUCER, + HPDF_INFO_TITLE, + HPDF_INFO_SUBJECT, + HPDF_INFO_KEYWORDS, + HPDF_INFO_TRAPPED, + HPDF_INFO_GTS_PDFX, + HPDF_INFO_EOF +} HPDF_InfoType; + +/* PDF-A Types */ + +typedef enum _HPDF_PDFA_TYPE +{ + HPDF_PDFA_1A = 0, + HPDF_PDFA_1B = 1 +} HPDF_PDFAType; + + +typedef enum _HPDF_PdfVer { + HPDF_VER_12 = 0, + HPDF_VER_13, + HPDF_VER_14, + HPDF_VER_15, + HPDF_VER_16, + HPDF_VER_17, + HPDF_VER_EOF +} HPDF_PDFVer; + +typedef enum _HPDF_EncryptMode { + HPDF_ENCRYPT_R2 = 2, + HPDF_ENCRYPT_R3 = 3 +} HPDF_EncryptMode; + + +typedef void +(HPDF_STDCALL *HPDF_Error_Handler) (HPDF_STATUS error_no, + HPDF_STATUS detail_no, + void *user_data); + +typedef void* +(HPDF_STDCALL *HPDF_Alloc_Func) (HPDF_UINT size); + + +typedef void +(HPDF_STDCALL *HPDF_Free_Func) (void *aptr); + + +/*---------------------------------------------------------------------------*/ +/*------ text width struct --------------------------------------------------*/ + +typedef struct _HPDF_TextWidth { + HPDF_UINT numchars; + + /* don't use this value (it may be change in the feature). + use numspace as alternated. */ + HPDF_UINT numwords; + + HPDF_UINT width; + HPDF_UINT numspace; +} HPDF_TextWidth; + + +/*---------------------------------------------------------------------------*/ +/*------ dash mode ----------------------------------------------------------*/ + +typedef struct _HPDF_DashMode { + HPDF_UINT16 ptn[8]; + HPDF_UINT num_ptn; + HPDF_UINT phase; +} HPDF_DashMode; + + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_TransMatrix struct ---------------------------------------------*/ + +typedef struct _HPDF_TransMatrix { + HPDF_REAL a; + HPDF_REAL b; + HPDF_REAL c; + HPDF_REAL d; + HPDF_REAL x; + HPDF_REAL y; +} HPDF_TransMatrix; + + +/*---------------------------------------------------------------------------*/ + +typedef enum _HPDF_ColorSpace { + HPDF_CS_DEVICE_GRAY = 0, + HPDF_CS_DEVICE_RGB, + HPDF_CS_DEVICE_CMYK, + HPDF_CS_CAL_GRAY, + HPDF_CS_CAL_RGB, + HPDF_CS_LAB, + HPDF_CS_ICC_BASED, + HPDF_CS_SEPARATION, + HPDF_CS_DEVICE_N, + HPDF_CS_INDEXED, + HPDF_CS_PATTERN, + HPDF_CS_EOF +} HPDF_ColorSpace; + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_RGBColor struct ------------------------------------------------*/ + +typedef struct _HPDF_RGBColor { + HPDF_REAL r; + HPDF_REAL g; + HPDF_REAL b; +} HPDF_RGBColor; + +/*---------------------------------------------------------------------------*/ +/*----- HPDF_CMYKColor struct -----------------------------------------------*/ + +typedef struct _HPDF_CMYKColor { + HPDF_REAL c; + HPDF_REAL m; + HPDF_REAL y; + HPDF_REAL k; +} HPDF_CMYKColor; + +/*---------------------------------------------------------------------------*/ +/*------ The line cap style -------------------------------------------------*/ + +typedef enum _HPDF_LineCap { + HPDF_BUTT_END = 0, + HPDF_ROUND_END, + HPDF_PROJECTING_SCUARE_END, + HPDF_LINECAP_EOF +} HPDF_LineCap; + +/*----------------------------------------------------------------------------*/ +/*------ The line join style -------------------------------------------------*/ + +typedef enum _HPDF_LineJoin { + HPDF_MITER_JOIN = 0, + HPDF_ROUND_JOIN, + HPDF_BEVEL_JOIN, + HPDF_LINEJOIN_EOF +} HPDF_LineJoin; + +/*----------------------------------------------------------------------------*/ +/*------ The text rendering mode ---------------------------------------------*/ + +typedef enum _HPDF_TextRenderingMode { + HPDF_FILL = 0, + HPDF_STROKE, + HPDF_FILL_THEN_STROKE, + HPDF_INVISIBLE, + HPDF_FILL_CLIPPING, + HPDF_STROKE_CLIPPING, + HPDF_FILL_STROKE_CLIPPING, + HPDF_CLIPPING, + HPDF_RENDERING_MODE_EOF +} HPDF_TextRenderingMode; + + +typedef enum _HPDF_WritingMode { + HPDF_WMODE_HORIZONTAL = 0, + HPDF_WMODE_VERTICAL, + HPDF_WMODE_EOF +} HPDF_WritingMode; + + +typedef enum _HPDF_PageLayout { + HPDF_PAGE_LAYOUT_SINGLE = 0, + HPDF_PAGE_LAYOUT_ONE_COLUMN, + HPDF_PAGE_LAYOUT_TWO_COLUMN_LEFT, + HPDF_PAGE_LAYOUT_TWO_COLUMN_RIGHT, + HPDF_PAGE_LAYOUT_TWO_PAGE_LEFT, + HPDF_PAGE_LAYOUT_TWO_PAGE_RIGHT, + HPDF_PAGE_LAYOUT_EOF +} HPDF_PageLayout; + + +typedef enum _HPDF_PageMode { + HPDF_PAGE_MODE_USE_NONE = 0, + HPDF_PAGE_MODE_USE_OUTLINE, + HPDF_PAGE_MODE_USE_THUMBS, + HPDF_PAGE_MODE_FULL_SCREEN, +/* HPDF_PAGE_MODE_USE_OC, + HPDF_PAGE_MODE_USE_ATTACHMENTS, + */ + HPDF_PAGE_MODE_EOF +} HPDF_PageMode; + + +typedef enum _HPDF_PageNumStyle { + HPDF_PAGE_NUM_STYLE_DECIMAL = 0, + HPDF_PAGE_NUM_STYLE_UPPER_ROMAN, + HPDF_PAGE_NUM_STYLE_LOWER_ROMAN, + HPDF_PAGE_NUM_STYLE_UPPER_LETTERS, + HPDF_PAGE_NUM_STYLE_LOWER_LETTERS, + HPDF_PAGE_NUM_STYLE_EOF +} HPDF_PageNumStyle; + + +typedef enum _HPDF_DestinationType { + HPDF_XYZ = 0, + HPDF_FIT, + HPDF_FIT_H, + HPDF_FIT_V, + HPDF_FIT_R, + HPDF_FIT_B, + HPDF_FIT_BH, + HPDF_FIT_BV, + HPDF_DST_EOF +} HPDF_DestinationType; + + +typedef enum _HPDF_AnnotType { + HPDF_ANNOT_TEXT_NOTES, + HPDF_ANNOT_LINK, + HPDF_ANNOT_SOUND, + HPDF_ANNOT_FREE_TEXT, + HPDF_ANNOT_STAMP, + HPDF_ANNOT_SQUARE, + HPDF_ANNOT_CIRCLE, + HPDF_ANNOT_STRIKE_OUT, + HPDF_ANNOT_HIGHTLIGHT, + HPDF_ANNOT_UNDERLINE, + HPDF_ANNOT_INK, + HPDF_ANNOT_FILE_ATTACHMENT, + HPDF_ANNOT_POPUP, + HPDF_ANNOT_3D, + HPDF_ANNOT_SQUIGGLY, + HPDF_ANNOT_LINE, + HPDF_ANNOT_PROJECTION +} HPDF_AnnotType; + + +typedef enum _HPDF_AnnotFlgs { + HPDF_ANNOT_INVISIBLE, + HPDF_ANNOT_HIDDEN, + HPDF_ANNOT_PRINT, + HPDF_ANNOT_NOZOOM, + HPDF_ANNOT_NOROTATE, + HPDF_ANNOT_NOVIEW, + HPDF_ANNOT_READONLY +} HPDF_AnnotFlgs; + + +typedef enum _HPDF_AnnotHighlightMode { + HPDF_ANNOT_NO_HIGHTLIGHT = 0, + HPDF_ANNOT_INVERT_BOX, + HPDF_ANNOT_INVERT_BORDER, + HPDF_ANNOT_DOWN_APPEARANCE, + HPDF_ANNOT_HIGHTLIGHT_MODE_EOF +} HPDF_AnnotHighlightMode; + + +typedef enum _HPDF_AnnotIcon { + HPDF_ANNOT_ICON_COMMENT = 0, + HPDF_ANNOT_ICON_KEY, + HPDF_ANNOT_ICON_NOTE, + HPDF_ANNOT_ICON_HELP, + HPDF_ANNOT_ICON_NEW_PARAGRAPH, + HPDF_ANNOT_ICON_PARAGRAPH, + HPDF_ANNOT_ICON_INSERT, + HPDF_ANNOT_ICON_EOF +} HPDF_AnnotIcon; + +typedef enum _HPDF_AnnotIntent { + HPDF_ANNOT_INTENT_FREETEXTCALLOUT = 0, + HPDF_ANNOT_INTENT_FREETEXTTYPEWRITER, + HPDF_ANNOT_INTENT_LINEARROW, + HPDF_ANNOT_INTENT_LINEDIMENSION, + HPDF_ANNOT_INTENT_POLYGONCLOUD, + HPDF_ANNOT_INTENT_POLYLINEDIMENSION, + HPDF_ANNOT_INTENT_POLYGONDIMENSION +} HPDF_AnnotIntent; + +typedef enum _HPDF_LineAnnotEndingStyle { + HPDF_LINE_ANNOT_NONE = 0, + HPDF_LINE_ANNOT_SQUARE, + HPDF_LINE_ANNOT_CIRCLE, + HPDF_LINE_ANNOT_DIAMOND, + HPDF_LINE_ANNOT_OPENARROW, + HPDF_LINE_ANNOT_CLOSEDARROW, + HPDF_LINE_ANNOT_BUTT, + HPDF_LINE_ANNOT_ROPENARROW, + HPDF_LINE_ANNOT_RCLOSEDARROW, + HPDF_LINE_ANNOT_SLASH +} HPDF_LineAnnotEndingStyle; + +typedef enum _HPDF_LineAnnotCapPosition{ + HPDF_LINE_ANNOT_CAP_INLINE = 0, + HPDF_LINE_ANNOT_CAP_TOP +} HPDF_LineAnnotCapPosition; + +typedef enum _HPDF_StampAnnotName{ + HPDF_STAMP_ANNOT_APPROVED = 0, + HPDF_STAMP_ANNOT_EXPERIMENTAL, + HPDF_STAMP_ANNOT_NOTAPPROVED, + HPDF_STAMP_ANNOT_ASIS, + HPDF_STAMP_ANNOT_EXPIRED, + HPDF_STAMP_ANNOT_NOTFORPUBLICRELEASE, + HPDF_STAMP_ANNOT_CONFIDENTIAL, + HPDF_STAMP_ANNOT_FINAL, + HPDF_STAMP_ANNOT_SOLD, + HPDF_STAMP_ANNOT_DEPARTMENTAL, + HPDF_STAMP_ANNOT_FORCOMMENT, + HPDF_STAMP_ANNOT_TOPSECRET, + HPDF_STAMP_ANNOT_DRAFT, + HPDF_STAMP_ANNOT_FORPUBLICRELEASE +} HPDF_StampAnnotName; + +/*----------------------------------------------------------------------------*/ +/*------ border stype --------------------------------------------------------*/ + +typedef enum _HPDF_BSSubtype { + HPDF_BS_SOLID, + HPDF_BS_DASHED, + HPDF_BS_BEVELED, + HPDF_BS_INSET, + HPDF_BS_UNDERLINED +} HPDF_BSSubtype; + + +/*----- blend modes ----------------------------------------------------------*/ + +typedef enum _HPDF_BlendMode { + HPDF_BM_NORMAL, + HPDF_BM_MULTIPLY, + HPDF_BM_SCREEN, + HPDF_BM_OVERLAY, + HPDF_BM_DARKEN, + HPDF_BM_LIGHTEN, + HPDF_BM_COLOR_DODGE, + HPDF_BM_COLOR_BUM, + HPDF_BM_HARD_LIGHT, + HPDF_BM_SOFT_LIGHT, + HPDF_BM_DIFFERENCE, + HPDF_BM_EXCLUSHON, + HPDF_BM_EOF +} HPDF_BlendMode; + +/*----- slide show -----------------------------------------------------------*/ + +typedef enum _HPDF_TransitionStyle { + HPDF_TS_WIPE_RIGHT = 0, + HPDF_TS_WIPE_UP, + HPDF_TS_WIPE_LEFT, + HPDF_TS_WIPE_DOWN, + HPDF_TS_BARN_DOORS_HORIZONTAL_OUT, + HPDF_TS_BARN_DOORS_HORIZONTAL_IN, + HPDF_TS_BARN_DOORS_VERTICAL_OUT, + HPDF_TS_BARN_DOORS_VERTICAL_IN, + HPDF_TS_BOX_OUT, + HPDF_TS_BOX_IN, + HPDF_TS_BLINDS_HORIZONTAL, + HPDF_TS_BLINDS_VERTICAL, + HPDF_TS_DISSOLVE, + HPDF_TS_GLITTER_RIGHT, + HPDF_TS_GLITTER_DOWN, + HPDF_TS_GLITTER_TOP_LEFT_TO_BOTTOM_RIGHT, + HPDF_TS_REPLACE, + HPDF_TS_EOF +} HPDF_TransitionStyle; + +/*----------------------------------------------------------------------------*/ + +typedef enum _HPDF_PageSizes { + HPDF_PAGE_SIZE_LETTER = 0, + HPDF_PAGE_SIZE_LEGAL, + HPDF_PAGE_SIZE_A3, + HPDF_PAGE_SIZE_A4, + HPDF_PAGE_SIZE_A5, + HPDF_PAGE_SIZE_B4, + HPDF_PAGE_SIZE_B5, + HPDF_PAGE_SIZE_EXECUTIVE, + HPDF_PAGE_SIZE_US4x6, + HPDF_PAGE_SIZE_US4x8, + HPDF_PAGE_SIZE_US5x7, + HPDF_PAGE_SIZE_COMM10, + HPDF_PAGE_SIZE_EOF +} HPDF_PageSizes; + + +typedef enum _HPDF_PageDirection { + HPDF_PAGE_PORTRAIT = 0, + HPDF_PAGE_LANDSCAPE +} HPDF_PageDirection; + + +typedef enum _HPDF_EncoderType { + HPDF_ENCODER_TYPE_SINGLE_BYTE, + HPDF_ENCODER_TYPE_DOUBLE_BYTE, + HPDF_ENCODER_TYPE_UNINITIALIZED, + HPDF_ENCODER_UNKNOWN +} HPDF_EncoderType; + + +typedef enum _HPDF_ByteType { + HPDF_BYTE_TYPE_SINGLE = 0, + HPDF_BYTE_TYPE_LEAD, + HPDF_BYTE_TYPE_TRIAL, + HPDF_BYTE_TYPE_UNKNOWN +} HPDF_ByteType; + + +typedef enum _HPDF_TextAlignment { + HPDF_TALIGN_LEFT = 0, + HPDF_TALIGN_RIGHT, + HPDF_TALIGN_CENTER, + HPDF_TALIGN_JUSTIFY +} HPDF_TextAlignment; + +/*----------------------------------------------------------------------------*/ + +/* Name Dictionary values -- see PDF reference section 7.7.4 */ +typedef enum _HPDF_NameDictKey { + HPDF_NAME_EMBEDDED_FILES = 0, /* TODO the rest */ + HPDF_NAME_EOF +} HPDF_NameDictKey; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_TYPES_H */ + diff --git a/code/libharu/hpdf_u3d.h b/code/libharu/hpdf_u3d.h new file mode 100644 index 0000000..bc1420b --- /dev/null +++ b/code/libharu/hpdf_u3d.h @@ -0,0 +1,52 @@ +/* + * << Haru Free PDF Library >> -- hpdf_u3d.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_U3D_H +#define _HPDF_U3D_H + +#include "hpdf_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +HPDF_EXPORT(HPDF_JavaScript) HPDF_CreateJavaScript(HPDF_Doc pdf, const char *code); + + +HPDF_EXPORT(HPDF_U3D) HPDF_LoadU3DFromFile (HPDF_Doc pdf, const char *filename); +HPDF_EXPORT(HPDF_Dict) HPDF_Create3DView (HPDF_MMgr mmgr, const char *name); +HPDF_EXPORT(HPDF_STATUS) HPDF_U3D_Add3DView(HPDF_U3D u3d, HPDF_Dict view); +HPDF_EXPORT(HPDF_STATUS) HPDF_U3D_SetDefault3DView(HPDF_U3D u3d, const char *name); +HPDF_EXPORT(HPDF_STATUS) HPDF_U3D_AddOnInstanciate(HPDF_U3D u3d, HPDF_JavaScript javaScript); +HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_AddNode(HPDF_Dict view, const char *name, HPDF_REAL opacity, HPDF_BOOL visible); +HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetLighting(HPDF_Dict view, const char *scheme); +HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetBackgroundColor(HPDF_Dict view, HPDF_REAL r, HPDF_REAL g, HPDF_REAL b); +HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetPerspectiveProjection(HPDF_Dict view, HPDF_REAL fov); +HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetOrthogonalProjection(HPDF_Dict view, HPDF_REAL mag); +HPDF_EXPORT(HPDF_STATUS) HPDF_3DView_SetCamera(HPDF_Dict view, HPDF_REAL coox, HPDF_REAL cooy, HPDF_REAL cooz, HPDF_REAL c2cx, HPDF_REAL c2cy, HPDF_REAL c2cz, HPDF_REAL roo, HPDF_REAL roll); + +HPDF_Dict +HPDF_3DView_New ( HPDF_MMgr mmgr, + HPDF_Xref xref, + HPDF_U3D u3d, + const char *name); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _HPDF_U3D_H */ + diff --git a/code/libharu/hpdf_utils.h b/code/libharu/hpdf_utils.h new file mode 100644 index 0000000..690ed6c --- /dev/null +++ b/code/libharu/hpdf_utils.h @@ -0,0 +1,165 @@ +/* + * << Haru Free PDF Library >> -- fpdf_utils.h + * + * URL: http://libharu.org + * + * Copyright (c) 1999-2006 Takeshi Kanno + * Copyright (c) 2007-2009 Antony Dovgal + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * It is provided "as is" without express or implied warranty. + * + */ + +#ifndef _HPDF_UTILS_H +#define _HPDF_UTILS_H + +#include "hpdf_config.h" +#include "hpdf_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +HPDF_INT +HPDF_AToI (const char* s); + + +HPDF_DOUBLE +HPDF_AToF (const char* s); + + +char* +HPDF_IToA (char* s, + HPDF_INT32 val, + char* eptr); + + +char* +HPDF_IToA2 (char *s, + HPDF_UINT32 val, + HPDF_UINT len); + + +char* +HPDF_FToA (char *s, + HPDF_REAL val, + char *eptr); + + +HPDF_BYTE* +HPDF_MemCpy (HPDF_BYTE* out, + const HPDF_BYTE* in, + HPDF_UINT n); + + +HPDF_BYTE* +HPDF_StrCpy (char* out, + const char* in, + char* eptr); + + +HPDF_INT +HPDF_MemCmp (const HPDF_BYTE* s1, + const HPDF_BYTE* s2, + HPDF_UINT n); + + +HPDF_INT +HPDF_StrCmp (const char* s1, + const char* s2); + + +const char* +HPDF_StrStr (const char *s1, + const char *s2, + HPDF_UINT maxlen); + + +void* +HPDF_MemSet (void* s, + HPDF_BYTE c, + HPDF_UINT n); + + +HPDF_UINT +HPDF_StrLen (const char* s, + HPDF_INT maxlen); + + +HPDF_Box +HPDF_ToBox (HPDF_INT16 left, + HPDF_INT16 bottom, + HPDF_INT16 right, + HPDF_INT16 top); + + +HPDF_Point +HPDF_ToPoint (HPDF_INT16 x, + HPDF_INT16 y); + + +HPDF_Rect +HPDF_ToRect (HPDF_REAL left, + HPDF_REAL bottom, + HPDF_REAL right, + HPDF_REAL top); + + +void +HPDF_UInt16Swap (HPDF_UINT16 *value); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define HPDF_NEEDS_ESCAPE(c) (c < 0x20 || \ + c > 0x7e || \ + c == '\\' || \ + c == '%' || \ + c == '#' || \ + c == '/' || \ + c == '(' || \ + c == ')' || \ + c == '<' || \ + c == '>' || \ + c == '[' || \ + c == ']' || \ + c == '{' || \ + c == '}' ) \ + +#define HPDF_IS_WHITE_SPACE(c) (c == 0x00 || \ + c == 0x09 || \ + c == 0x0A || \ + c == 0x0C || \ + c == 0x0D || \ + c == 0x20 ) \ + +/*----------------------------------------------------------------------------*/ +/*----- macros for debug -----------------------------------------------------*/ + +#ifdef LIBHPDF_DEBUG_TRACE +#ifndef HPDF_PTRACE_ON +#define HPDF_PTRACE_ON +#endif /* HPDF_PTRACE_ON */ +#endif /* LIBHPDF_DEBUG_TRACE */ + +#ifdef HPDF_PTRACE_ON +#define HPDF_PTRACE(ARGS) HPDF_PRINTF ARGS +#else +#define HPDF_PTRACE(ARGS) /* do nothing */ +#endif /* HPDF_PTRACE */ + +#ifdef LIBHPDF_DEBUG +#define HPDF_PRINT_BINARY(BUF, LEN, CAPTION) HPDF_PrintBinary(BUF, LEN, CAPTION) +#else +#define HPDF_PRINT_BINARY(BUF, LEN, CAPTION) /* do nothing */ +#endif + +#endif /* _HPDF_UTILS_H */ + diff --git a/code/libharu/hpdf_version.h b/code/libharu/hpdf_version.h new file mode 100644 index 0000000..b7906e7 --- /dev/null +++ b/code/libharu/hpdf_version.h @@ -0,0 +1,8 @@ +/* automatically generated by configure */ +/* edit configure.in to change version number */ +#define HPDF_MAJOR_VERSION 2 +#define HPDF_MINOR_VERSION 3 +#define HPDF_BUGFIX_VERSION 0 +#define HPDF_EXTRA_VERSION "RC2" +#define HPDF_VERSION_TEXT "2.3.0RC2" +#define HPDF_VERSION_ID 20300 diff --git a/code/license.txt b/code/license.txt new file mode 100644 index 0000000..e6589a1 --- /dev/null +++ b/code/license.txt @@ -0,0 +1,688 @@ +This product is made available subject to the terms of GNU General Public License Version 3. A copy of the GPL license can be found at http://www.melin.nu/meos/license.html + +------------------------------------ +Third Party Code. Additional copyright notices and license terms applicable to portions of the Software are set forth in the thirdpartylicense.txt file. + +------------------------------------ +All trademarks and registered trademarks mentioned herein are the property of their respective owners. + +------------------------------------ +Copyright 2007-2013 Melin Software HB. + +------------------------------------ + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 of the License, 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/code/listeditor.cpp b/code/listeditor.cpp new file mode 100644 index 0000000..934717d --- /dev/null +++ b/code/listeditor.cpp @@ -0,0 +1,1201 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include + +#include "listeditor.h" +#include "metalist.h" +#include "gdioutput.h" +#include "meosexception.h" +#include "gdistructures.h" +#include "meos_util.h" +#include "localizer.h" +#include "gdifonts.h" +#include "oEvent.h" +#include "tabbase.h" +#include "CommDlg.h" + +ListEditor::ListEditor(oEvent *oe_) { + oe = oe_; + currentList = 0; + currentIndex = -1; + dirtyExt = false; + dirtyInt = false; + lastSaved = NotSaved; + oe->loadGeneralResults(false); +} + +ListEditor::~ListEditor() { + setCurrentList(0); +} + +void ListEditor::setCurrentList(MetaList *lst) { + delete currentList; + currentList = lst; +} +/* +void ListEditor::load(MetaList *list) { + currentList = list; + currentIndex = -1; + dirtyInt = true; + dirtyExt = true; +}*/ + +void ListEditor::load(const MetaListContainer &mlc, int index) { + const MetaList &mc = mlc.getList(index); + setCurrentList(new MetaList()); + *currentList = mc; + + if (mlc.isInternal(index)) { + currentIndex = -1; + currentList->clearTag(); + } + else + currentIndex = index; + + dirtyExt = true; + dirtyInt = false; + savedFileName.clear(); +} + +void ListEditor::show(gdioutput &gdi) { + + gdi.setRestorePoint("BeginListEdit"); + + gdi.pushX(); + gdi.setCX(gdi.getCX() + gdi.scaleLength(6)); + + int bx = gdi.getCX(); + int by = gdi.getCY(); + + if (currentList) + gdi.addString("", boldLarge, MakeDash("Listredigerare - X#") + currentList->getListName()); + else + gdi.addString("", boldLarge, "Listredigerare"); + + gdi.setOnClearCb(editListCB); + gdi.setData("ListEditorClz", this); + gdi.dropLine(0.5); + gdi.fillRight(); + + gdi.addButton("EditList", "Egenskaper", editListCB); + gdi.setCX(gdi.getCX() + gdi.scaleLength(32)); + gdi.addButton("OpenFile", "Öppna fil", editListCB); + gdi.addButton("OpenInside", "Öppna från aktuell tävling", editListCB); + + if (savedFileName.empty()) + gdi.addButton("SaveFile", "Spara som fil", editListCB); + else { + gdi.addButton("SaveFile", "Spara fil", editListCB, "#" + savedFileName); + gdi.addButton("SaveFileCopy", "Spara som...", editListCB); + } + + gdi.addButton("SaveInside", "Spara i aktuell tävling", editListCB); + gdi.addButton("NewList", "Ny lista", editListCB); + gdi.addButton("RemoveInside", "Radera", editListCB, "Radera listan från aktuell tävling"); + gdi.setInputStatus("RemoveInside", currentIndex != -1); + gdi.addButton("Close", "Stäng", editListCB); + + gdi.dropLine(2); + + int dx = gdi.getCX(); + int dy = gdi.getCY(); + + RECT rc; + int off = gdi.scaleLength(6); + rc.left = bx - 2 * off; + rc.right = dx + 2 * off; + + rc.top = by - off; + rc.bottom = dy + off; + + gdi.addRectangle(rc, colorWindowBar); + + gdi.dropLine(); + gdi.popX(); + + + makeDirty(gdi, NoTouch, NoTouch); + if (!currentList) { + gdi.disableInput("EditList"); + gdi.disableInput("SaveFile"); + gdi.disableInput("SaveFileCopy", true); + gdi.disableInput("SaveInside"); + gdi.refresh(); + return; + } + + MetaList &list = *currentList; + + const vector< vector > &head = list.getHead(); + gdi.fillDown(); + gdi.addString("", 1, "Rubrik"); + gdi.pushX(); + gdi.fillRight(); + const double buttonDrop = 2.2; + int lineIx = 100; + for (size_t k = 0; k < head.size(); k++) { + showLine(gdi, head[k], lineIx++); + gdi.popX(); + gdi.dropLine(buttonDrop); + } + gdi.fillDown(); + gdi.addButton("AddLine0", "Lägg till rad", editListCB); + + gdi.dropLine(0.5); + gdi.addString("", 1, "Underrubrik"); + gdi.pushX(); + gdi.fillRight(); + const vector< vector > &subHead = list.getSubHead(); + lineIx = 200; + for (size_t k = 0; k < subHead.size(); k++) { + showLine(gdi, subHead[k], lineIx++); + gdi.popX(); + gdi.dropLine(buttonDrop); + } + gdi.fillDown(); + gdi.addButton("AddLine1", "Lägg till rad", editListCB); + + gdi.dropLine(0.5); + gdi.addString("", 1, "Huvudlista"); + gdi.pushX(); + gdi.fillRight(); + const vector< vector > &mainList = list.getList(); + lineIx = 300; + for (size_t k = 0; k < mainList.size(); k++) { + showLine(gdi, mainList[k], lineIx++); + gdi.popX(); + gdi.dropLine(buttonDrop); + } + gdi.fillDown(); + gdi.addButton("AddLine2", "Lägg till rad", editListCB); + + gdi.dropLine(0.5); + gdi.addString("", 1, "Underlista"); + gdi.pushX(); + gdi.fillRight(); + const vector< vector > &subList = list.getSubList(); + lineIx = 400; + for (size_t k = 0; k < subList.size(); k++) { + showLine(gdi, subList[k], lineIx++); + gdi.popX(); + gdi.dropLine(buttonDrop); + } + gdi.fillDown(); + gdi.addButton("AddLine3", "Lägg till rad", editListCB); + + gdi.setRestorePoint("EditList"); + + gdi.dropLine(2); + + oListInfo li; + oListParam par; + par.pageBreak = false; + par.splitAnalysis = true; + par.setLegNumberCoded(-1); + par.inputNumber = 0; + gdi.fillDown(); + + try { + currentList->interpret(oe, gdi, par, gdi.getLineHeight(), li); + rc.left = gdi.getCX(); + rc.right = gdi.getCX() + gdi.getWidth() - 20; + rc.top = gdi.getCY(); + rc.bottom = rc.top + 4; + + gdi.addRectangle(rc, colorDarkGreen, false, false); + gdi.dropLine(); + + oe->generateList(gdi, false, li, true); + } + catch (std::exception &ex) { + gdi.addString("", 1, "Listan kan inte visas").setColor(colorRed); + gdi.addString("", 0, ex.what()); + } + + gdi.refresh(); +} + +int editListCB(gdioutput *gdi, int type, void *data) +{ + void *clz = gdi->getData("ListEditorClz"); + ListEditor *le = (ListEditor *)clz; + BaseInfo *bi = (BaseInfo *)data; + if (le) + return le->editList(*gdi, type, *bi); + + throw meosException("Unexpected error"); +} + +void ListEditor::showLine(gdioutput &gdi, const vector &line, int ix) const { + for (size_t k = 0; k < line.size(); k++) { + addButton(gdi, line[k], gdi.getCX(), gdi.getCY(), ix, k); + } + + gdi.addButton("AddPost" + itos(ix), "Lägg till ny", editListCB); +} + +ButtonInfo &ListEditor::addButton(gdioutput &gdi, const MetaListPost &mlp, int x, int y, int lineIx, int ix) const { + string cap; + if (mlp.getType() == "String") { + cap = "Text: X#" + mlp.getText(); + } + else { + const string &text = mlp.getText(); + if (text.length() > 0) { + if (text[0] == '@') { + vector part; + split(text.substr(1), ";", part); + unsplit(part, "|", cap); + } + else + cap = text + "#" + lang.tl(mlp.getType()); + } + else { + cap = mlp.getType(); + } + } + + ButtonInfo &bi = gdi.addButton(x, y, "EditPost" + itos(lineIx * 100 + ix), cap, editListCB); + return bi; +} + +static void getPosFromId(int id, int &groupIx, int &lineIx, int &ix) { + lineIx = id / 100; + ix = id % 100; + groupIx = (lineIx / 100) - 1; + lineIx = lineIx % 100; +} + +int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) { + int lineIx, groupIx, ix; + if (type == GUI_BUTTON) { + ButtonInfo bi = dynamic_cast(data); + ButtonInfo &biSrc = dynamic_cast(data); + + if (bi.id == "Color") { + CHOOSECOLOR cc; + memset(&cc, 0, sizeof(cc)); + cc.lStructSize = sizeof(cc); + cc.hwndOwner = gdi.getHWND(); + cc.rgbResult = COLORREF(bi.getExtra()); + if (GDICOLOR((int)bi.getExtra()) != colorDefault) + cc.Flags |= CC_RGBINIT; + + COLORREF staticColor[16]; + memset(staticColor, 0, 16*sizeof(COLORREF)); + + const string &c = oe->getPropertyString("Colors", ""); + const char *end = c.c_str() + c.length(); + const char * pEnd = c.c_str(); + int pix = 0; + while(pEnd < end && pix < 16) { + staticColor[pix++] = strtol(pEnd,(char **)&pEnd,16); + } + + //vector splitvector; + //split(c, ";", splitvector); + cc.lpCustColors = staticColor; + if (ChooseColor(&cc)) { + data.setExtra((int)cc.rgbResult); + + string co; + for (ix = 0; ix < 16; ix++) { + char bf[16]; + sprintf_s(bf, "%x ", staticColor[ix]); + co += bf; + } + oe->setProperty("Colors", co); + } + } + if ( bi.id.substr(0, 8) == "EditPost" ) { + int id = atoi(bi.id.substr(8).c_str()); + getPosFromId(id, groupIx, lineIx, ix); + MetaListPost &mlp = currentList->getMLP(groupIx, lineIx, ix); + editListPost(gdi, mlp, id); + } + else if ( bi.id.substr(0, 7) == "AddPost" ) { + checkUnsaved(gdi); + gdi.restore("EditList", true); + gdi.pushX(); + lineIx = atoi(bi.id.substr(7).c_str()); + groupIx = (lineIx / 100) - 1; + int ixOutput = 0; + MetaListPost &mlp = currentList->addNew(groupIx, lineIx % 100, ixOutput); + int xp = bi.xp; + int yp = bi.yp; + ButtonInfo &nb = addButton(gdi, mlp, xp, yp, lineIx, ixOutput); + //gdi.addButton(xp, yp, string("Foo"), string("FoooBar"), 0); + int w, h; + nb.getDimension(gdi, w, h); + biSrc.moveButton(gdi, xp+w, yp); + gdi.popX(); + gdi.setRestorePoint("EditList"); + makeDirty(gdi, MakeDirty, MakeDirty); + gdi.sendCtrlMessage(nb.id); + } + else if ( bi.id.substr(0, 7) == "AddLine" ) { + checkUnsaved(gdi); + groupIx = atoi(bi.id.substr(7).c_str()); + int ixOutput = 0; + currentList->addNew(groupIx, -1, ixOutput); + + gdi.restore("BeginListEdit", false); + makeDirty(gdi, MakeDirty, MakeDirty); + show(gdi); + } + else if ( bi.id == "Remove" ) { + DWORD id; + gdi.getData("CurrentId", id); + getPosFromId(id, groupIx, lineIx, ix); + currentList->removeMLP(groupIx, lineIx, ix); + gdi.restore("BeginListEdit", false); + makeDirty(gdi, MakeDirty, MakeDirty); + show(gdi); + } + else if (bi.id == "UseLeg") { + gdi.setInputStatus("Leg", gdi.isChecked(bi.id)); + } + else if (bi.id == "Cancel") { + gdi.restore("EditList"); + gdi.enableInput("EditList"); + } + else if (bi.id == "CancelNew") { + gdi.clearPage(false); + currentList = 0; + show(gdi); + } + else if (bi.id == "Apply" || bi.id == "MoveLeft" || bi.id == "MoveRight") { + DWORD id; + gdi.getData("CurrentId", id); + getPosFromId(id, groupIx, lineIx, ix); + + if (bi.id == "MoveLeft") + currentList->moveOnRow(groupIx, lineIx, ix, -1); + else if (bi.id == "MoveRight") + currentList->moveOnRow(groupIx, lineIx, ix, 1); + + MetaListPost &mlp = currentList->getMLP(groupIx, lineIx, ix); + + ListBoxInfo lbi; + bool force = false; + gdi.getSelectedItem("Type", lbi); + + EPostType ptype = EPostType(lbi.data); + + string str = gdi.getText("Text"); + if (ptype != lString) { + if (!str.empty() && str.find_first_of('X') == string::npos && str[0]!='@') { + throw meosException("Texten ska innehålla tecknet X, som byts ut mot tävlingsspecifik data"); + } + } + + string t1 = mlp.getType(); + EPostType newType = EPostType(lbi.data); + mlp.setType(newType); + if (t1 != mlp.getType()) + force = true; + mlp.setText(str); + + gdi.getSelectedItem("AlignType", lbi); + mlp.align(EPostType(lbi.data), gdi.isChecked("BlockAlign")); + mlp.alignText(gdi.getText("AlignText")); + mlp.mergePrevious(gdi.isChecked("MergeText")); + + gdi.getSelectedItem("TextAdjust", lbi); + mlp.setTextAdjust(lbi.data); + + mlp.setColor(GDICOLOR(gdi.getExtraInt("Color"))); + + if (gdi.isChecked("UseLeg")) { + int leg = gdi.getTextNo("Leg"); + if (newType == lResultModuleNumber || newType == lResultModuleTime || + newType == lResultModuleNumberTeam || newType == lResultModuleTimeTeam) { + if (leg < 0 || leg > 1000) + throw meosException("X är inget giltigt index#" + itos(leg)); + mlp.setLeg(leg); + } + else { + if (leg < 1 || leg > 1000) + throw meosException("X är inget giltigt sträcknummer#" + itos(leg)); + mlp.setLeg(leg - 1); + } + } + else + mlp.setLeg(-1); + + if (gdi.hasField("UseResultModule") && gdi.isChecked("UseResultModule")) + mlp.setResultModule(currentList->getResultModule()); + else + mlp.setResultModule(""); + + mlp.setBlock(gdi.getTextNo("BlockSize")); + mlp.indent(gdi.getTextNo("MinIndeent")); + + gdi.getSelectedItem("Fonts", lbi); + mlp.setFont(gdiFonts(lbi.data)); + makeDirty(gdi, MakeDirty, MakeDirty); + if (!gdi.hasData("NoRedraw") || force) { + gdi.restore("BeginListEdit", false); + show(gdi); + } + } + else if (bi.id == "ApplyListProp") { + string name = gdi.getText("Name"); + + if (name.empty()) + throw meosException("Namnet kan inte vara tomt"); + + MetaList &list = *currentList; + list.setListName(name); + ListBoxInfo lbi; + + if (gdi.getSelectedItem("SortOrder", lbi)) + list.setSortOrder(SortOrder(lbi.data)); + + if (gdi.getSelectedItem("BaseType", lbi)) + list.setListType(oListInfo::EBaseType(lbi.data)); + + if (gdi.getSelectedItem("ResultType", lbi)) + list.setResultModule(*oe, lbi.data); + + if (gdi.getSelectedItem("SubType", lbi)) + list.setSubListType(oListInfo::EBaseType(lbi.data)); + + vector< pair > filtersIn; + vector< bool > filtersOut; + list.getFilters(filtersIn); + for (size_t k = 0; k < filtersIn.size(); k++) + filtersOut.push_back(gdi.isChecked("filter" + itos(k))); + + list.setFilters(filtersOut); + + vector< pair > subFiltersIn; + vector< bool > subFiltersOut; + list.getSubFilters(subFiltersIn); + for (size_t k = 0; k < subFiltersIn.size(); k++) + subFiltersOut.push_back(gdi.isChecked("subfilter" + itos(k))); + + list.setSubFilters(subFiltersOut); + + + for (int k = 0; k < 4; k++) { + list.setFontFace(k, gdi.getText("Font" + itos(k)), + gdi.getTextNo("FontFactor" + itos(k))); + + int f = gdi.getTextNo("ExtraSpace" + itos(k)); + list.setExtraSpace(k, f); + } + + list.setSupportFromTo(gdi.isChecked("SupportFrom"), gdi.isChecked("SupportTo")); + + makeDirty(gdi, MakeDirty, MakeDirty); + + if (!gdi.hasData("NoRedraw")) { + gdi.clearPage(false); + show(gdi); + } + } + else if (bi.id == "EditList") { + editListProp(gdi, false); + } + else if (bi.id == "NewList") { + if (!checkSave(gdi)) + return 0; + gdi.clearPage(false); + gdi.setData("ListEditorClz", this); + gdi.addString("", boldLarge, "Ny lista"); + + setCurrentList(new MetaList()); + currentIndex = -1; + lastSaved = NotSaved; + makeDirty(gdi, ClearDirty, ClearDirty); + + editListProp(gdi, true); + } + else if (bi.id == "MakeNewList") { + /* + currentList->setListName(lang.tl("Ny lista")); + currentIndex = -1; + + lastSaved = NotSaved; + makeDirty(gdi, ClearDirty, ClearDirty); + + gdi.clearPage(false); + show(gdi);*/ + } + else if (bi.id == "SaveFile" || bi.id == "SaveFileCopy") { + if (!currentList) + return 0; + + bool copy = bi.id == "SaveFileCopy"; + + string fileName = copy ? "" : savedFileName; + + if (fileName.empty()) { + int ix = 0; + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.xml")); + fileName = gdi.browseForSave(ext, "xml", ix); + if (fileName.empty()) + return 0; + } + + currentList->save(fileName, oe); + + lastSaved = SavedFile; + makeDirty(gdi, NoTouch, ClearDirty); + savedFileName = fileName; + return 1; + } + else if (bi.id == "OpenFile") { + if (!checkSave(gdi)) + return 0; + + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.xml")); + string fileName = gdi.browseForOpen(ext, "xml"); + if (fileName.empty()) + return 0; + + MetaList *tmp = new MetaList(); + try { + tmp->setListName(lang.tl("Ny lista")); + tmp->load(fileName); + } + catch(...) { + delete tmp; + throw; + } + + setCurrentList(tmp); + currentIndex = -1; + gdi.clearPage(false); + lastSaved = SavedFile; + + savedFileName = fileName; + oe->loadGeneralResults(true); + makeDirty(gdi, ClearDirty, ClearDirty); + show(gdi); + } + else if (bi.id == "OpenInside") { + if (!checkSave(gdi)) + return 0; + + savedFileName.clear(); + gdi.clearPage(true); + gdi.setOnClearCb(editListCB); + gdi.setData("ListEditorClz", this); + + gdi.pushX(); + vector< pair > lists; + oe->getListContainer().getLists(lists, true, false, false); + reverse(lists.begin(), lists.end()); + + gdi.fillRight(); + gdi.addSelection("OpenList", 250, 400, editListCB, "Välj lista:"); + gdi.addItem("OpenList", lists); + gdi.selectFirstItem("OpenList"); + + + gdi.dropLine(); + gdi.addButton("DoOpen", "Öppna", editListCB); + gdi.addButton("DoOpenCopy", "Open a Copy", editListCB); + enableOpen(gdi); + + gdi.addButton("CancelReload", "Avbryt", editListCB).setCancel(); + gdi.dropLine(4); + gdi.popX(); + } + else if (bi.id == "DoOpen" || bi.id == "DoOpenCopy" ) { + ListBoxInfo lbi; + if (gdi.getSelectedItem("OpenList", lbi)) { + load(oe->getListContainer(), lbi.data); + } + + if (bi.id == "DoOpenCopy") { + currentIndex = -1; + currentList->clearTag(); + lastSaved = NotSaved; + makeDirty(gdi, MakeDirty, MakeDirty); + } + else { + lastSaved = SavedInside; + makeDirty(gdi, ClearDirty, ClearDirty); + } + gdi.clearPage(false); + show(gdi); + } + else if (bi.id == "CancelReload") { + gdi.clearPage(false); + show(gdi); + } + else if (bi.id == "SaveInside") { + if (currentList == 0) + return 0; + savedFileName.clear(); + oe->synchronize(false); + + if (currentIndex != -1) { + oe->getListContainer().saveList(currentIndex, *currentList); + } + else { + oe->getListContainer().addExternal(*currentList); + currentIndex = oe->getListContainer().getNumLists() - 1; + oe->getListContainer().saveList(currentIndex, *currentList); + } + + oe->synchronize(true); + lastSaved = SavedInside; + makeDirty(gdi, ClearDirty, ClearDirty); + } + else if (bi.id == "RemoveInside") { + if (currentIndex != -1) { + oe->getListContainer().removeList(currentIndex); + currentIndex = -1; + savedFileName.clear(); + if (lastSaved == SavedInside) + lastSaved = NotSaved; + + gdi.alert("Listan togs bort från tävlingen."); + makeDirty(gdi, MakeDirty, NoTouch); + gdi.setInputStatus("RemoveInside", false); + } + } + else if (bi.id == "Close") { + if (!checkSave(gdi)) + return 0; + + setCurrentList(0); + makeDirty(gdi, ClearDirty, ClearDirty); + currentIndex = -1; + savedFileName.clear(); + gdi.getTabs().get(TListTab)->loadPage(gdi); + return 0; + } + /*else if (bi.id == "BrowseFont") { + InitCommonControls(); + CHOOSEFONT cf; + memset(&cf, 0, sizeof(cf)); + cf.lStructSize = sizeof(cf); + cf.hwndOwner = gdi.getHWND(); + ChooseFont(&cf); + EnumFontFamilies( + }*/ + } + else if (type == GUI_LISTBOX) { + ListBoxInfo &lbi = dynamic_cast(data); + + if (lbi.id == "AlignType") { + gdi.setInputStatus("AlignText", lbi.data == lString); + if (lbi.data == lString) { + int ix = lbi.text.find_first_of(":"); + if (ix != lbi.text.npos) + gdi.setText("AlignText", lbi.text.substr(ix+1)); + } + else + gdi.setText("AlignText", ""); + } + else if (lbi.id == "Type") { + EPostType type = EPostType(lbi.data); + gdi.setTextTranslate("TUseLeg", getIndexDescription(type), true); + if (type == lResultModuleNumber || type == lResultModuleTime || + type == lResultModuleNumberTeam || type == lResultModuleTimeTeam) { + gdi.check("UseLeg", true); + gdi.check("UseResultModule", true); + gdi.disableInput("UseResultModule"); + gdi.disableInput("UseLeg"); + gdi.enableInput("Leg"); + if (gdi.getText("Leg").empty()) + gdi.setText("Leg", "0"); + } + else { + gdi.enableInput("UseLeg"); + if (gdi.getTextNo("Leg") == 0) { + gdi.setText("Leg", ""); + gdi.enableInput("UseLeg"); + gdi.enableInput("UseResultModule", true); + gdi.check("UseLeg", false); + gdi.disableInput("Leg"); + } + } + } + else if (lbi.id == "SubType") { + oListInfo::EBaseType subType = oListInfo::EBaseType(lbi.data); + vector< pair > subfilters; + currentList->getSubFilters(subfilters); + for (size_t k = 0; k < subfilters.size(); k++) { + gdi.setInputStatus("subfilter" + itos(k), subType != oListInfo::EBaseTypeNone); + } + } + else if (lbi.id == "ResultType") { + vector< pair > types; + int currentType = 0; + currentList->getSortOrder(lbi.data != 0, types, currentType); + if (lbi.data == 0) { + ListBoxInfo mlbi; + gdi.getSelectedItem("SortOrder", mlbi); + currentType = mlbi.data; + } + gdi.addItem("SortOrder", types); + gdi.selectItemByData("SortOrder", currentType); + } + else if (lbi.id == "OpenList") { + enableOpen(gdi); + } + } + else if (type==GUI_CLEAR) { + return checkSave(gdi); + } + + return 0; +} + +void ListEditor::checkUnsaved(gdioutput &gdi) { + if (gdi.hasData("IsEditing")) { + if (gdi.isInputChanged("")) { + gdi.setData("NoRedraw", 1); + gdi.sendCtrlMessage("Apply"); + } + } + if (gdi.hasData("IsEditingList")) { + if (gdi.isInputChanged("")) { + gdi.setData("NoRedraw", 1); + gdi.sendCtrlMessage("ApplyListProp"); + } + } +} + +void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) { + checkUnsaved(gdi); + gdi.restore("EditList", false); + gdi.dropLine(); + + gdi.enableInput("EditList"); + int groupIx, lineIx, ix; + getPosFromId(id, groupIx, lineIx, ix); + const bool hasResultModule = currentList && !currentList->getResultModule().empty(); + int x1 = gdi.getCX(); + int y1 = gdi.getCY(); + int margin = gdi.scaleLength(10); + gdi.setCX(x1+margin); + + gdi.dropLine(); + gdi.pushX(); + gdi.fillRight(); + gdi.addString("", boldLarge, "Listpost").setColor(colorDarkGrey); + gdi.setCX(gdi.getCX() + gdi.scaleLength(20)); + + gdi.addButton("MoveLeft", "<< Flytta vänster", editListCB); + gdi.addButton("MoveRight", "Flytta höger >>", editListCB); + + gdi.dropLine(3); + gdi.popX(); + vector< pair > types; + int currentType; + mlp.getTypes(types, currentType); + EPostType storedType = EPostType(currentType); + + if (!hasResultModule) { + for (size_t k = 0; k < types.size(); k++) { + if ( (storedType != lResultModuleNumber && types[k].second == lResultModuleNumber) || + (storedType != lResultModuleTime && types[k].second == lResultModuleTime) || + (storedType != lResultModuleNumberTeam && types[k].second == lResultModuleNumberTeam) || + (storedType != lResultModuleTimeTeam && types[k].second == lResultModuleTimeTeam)) { + swap(types[k], types.back()); + types.pop_back(); + k--; + } + } + } + + sort(types.begin(), types.end()); + gdi.pushX(); + gdi.fillRight(); + int boxY = gdi.getCY(); + gdi.addSelection("Type", 290, 500, editListCB, "Typ:"); + gdi.addItem("Type", types); + gdi.selectItemByData("Type", currentType); + gdi.addInput("Text", mlp.getText(), 16, 0, "Egen text:", "Använd symbolen X där MeOS ska fylla i typens data."); + int boxX = gdi.getCX(); + gdi.popX(); + gdi.fillRight(); + gdi.dropLine(3); + currentList->getAlignTypes(mlp, types, currentType); + sort(types.begin(), types.end()); + gdi.addSelection("AlignType", 290, 500, editListCB, "Justera mot:"); + gdi.addItem("AlignType", types); + gdi.selectItemByData("AlignType", currentType); + + gdi.addInput("AlignText", mlp.getAlignText(), 16, 0, "Text:"); + if (currentType != lString) + gdi.disableInput("AlignText"); + gdi.popX(); + gdi.dropLine(3); + gdi.fillRight(); + gdi.addCheckbox("BlockAlign", "Justera blockvis:", 0, mlp.getAlignBlock()); + gdi.dropLine(-0.2); + gdi.addInput("BlockSize", itos(mlp.getBlockWidth()), 5, 0, "", "Blockbredd"); + gdi.dropLine(2.1); + gdi.popX(); + gdi.fillRight(); + + if (hasResultModule) { + gdi.addCheckbox("UseResultModule", "Data from result module (X)#" + currentList->getResultModule(), 0, !mlp.getResultModule().empty()); + gdi.dropLine(1.5); + gdi.popX(); + } + + int leg = mlp.getLeg(); + gdi.addCheckbox("UseLeg", getIndexDescription(storedType), editListCB, leg != -1); + gdi.dropLine(-0.2); + gdi.setCX(gdi.getCX() + gdi.getLineHeight() * 5); + if (storedType == lResultModuleNumber || storedType == lResultModuleTime || storedType == lResultModuleTimeTeam || storedType == lResultModuleNumberTeam) + gdi.addInput("Leg", leg>=0 ? itos(leg) : "0", 4); + else + gdi.addInput("Leg", leg>=0 ? itos(leg + 1) : "", 4); + + if (storedType == lResultModuleNumber || storedType == lResultModuleTime || storedType == lResultModuleTimeTeam || storedType == lResultModuleNumberTeam) { + gdi.check("UseLeg", true); + gdi.check("UseResultModule", true); + gdi.disableInput("UseResultModule"); + gdi.disableInput("UseLeg"); + } + + gdi.dropLine(2); + if (ix>0) { + gdi.popX(); + gdi.addCheckbox("MergeText", "Slå ihop text med föregående", 0, mlp.isMergePrevious()); + gdi.dropLine(2); + } + int maxY = gdi.getCY(); + gdi.popX(); + gdi.fillDown(); + gdi.setCX(boxX + gdi.scaleLength(24)); + gdi.setCY(boxY); + gdi.pushX(); + gdi.addString("", 1, "Formateringsregler"); + gdi.dropLine(0.5); + gdi.fillRight(); + gdi.addInput("MinIndeent", itos(mlp.getMinimalIndent()), 7, 0, "Minsta intabbning:"); + + vector< pair > fonts; + int currentFont; + mlp.getFonts(fonts, currentFont); + + gdi.addSelection("Fonts", 150, 500, 0, "Format:"); + gdi.addItem("Fonts", fonts); + gdi.selectItemByData("Fonts", currentFont); + int maxX = gdi.getCX(); + + gdi.popX(); + gdi.dropLine(3); + + gdi.addSelection("TextAdjust", 150, 100, 0, "Textjustering:"); + gdi.addItem("TextAdjust", lang.tl("Vänster"), 0); + gdi.addItem("TextAdjust", lang.tl("Höger"), textRight); + gdi.addItem("TextAdjust", lang.tl("Centrera"), textCenter); + gdi.selectItemByData("TextAdjust", mlp.getTextAdjustNum()); + + //gdi.popX(); + //gdi.dropLine(2); + gdi.dropLine(); + gdi.addButton("Color", "Färg...", editListCB).setExtra(mlp.getColorValue()); + + + maxX = max(maxX, gdi.getCX()); + gdi.popX(); + gdi.dropLine(3); + + gdi.setData("CurrentId", id); + gdi.addButton("Remove", "Radera", editListCB, "Ta bort listposten"); + gdi.addButton("Cancel", "Avbryt", editListCB).setCancel(); + + gdi.updatePos(gdi.getCX(), gdi.getCY(), gdi.scaleLength(20), 0); + gdi.addButton("Apply", "OK", editListCB).setDefault(); + + gdi.dropLine(3); + maxY = max(maxY, gdi.getCY()); + maxX = max(gdi.getCX(), maxX); + + gdi.fillDown(); + gdi.popX(); + gdi.setData("IsEditing", 1); + + RECT rc; + rc.top = y1; + rc.left = x1; + rc.right = maxX + gdi.scaleLength(6); + rc.bottom = maxY + gdi.scaleLength(6); + + gdi.addRectangle(rc, colorLightBlue, true); + + gdi.scrollToBottom(); + gdi.refresh(); +} + +const char *ListEditor::getIndexDescription(EPostType type) { + if (type == lResultModuleTime || type == lResultModuleTimeTeam) + return "Index in X[index]#OutputTimes"; + else if (type == lResultModuleNumber || type == lResultModuleNumberTeam) + return "Index in X[index]#OutputNumbers"; + else + return "Applicera för specifik sträcka:"; +} + +void ListEditor::editListProp(gdioutput &gdi, bool newList) { + checkUnsaved(gdi); + + if (!currentList) + return; + + MetaList &list = *currentList; + + if (!newList) { + gdi.restore("EditList", false); + gdi.disableInput("EditList"); + } + + gdi.dropLine(0.8); + + int x1 = gdi.getCX(); + int y1 = gdi.getCY(); + int margin = gdi.scaleLength(10); + gdi.setCX(x1+margin); + + if (!newList) { + gdi.dropLine(); + gdi.fillDown(); + gdi.addString("", boldLarge, "Listegenskaper").setColor(colorDarkGrey); + gdi.dropLine(); + } + + gdi.fillRight(); + gdi.pushX(); + + gdi.addInput("Name", list.getListName(), 20, 0, "Listnamn:"); + + if (newList) { + gdi.dropLine(3.5); + gdi.popX(); + } + + vector< pair > types; + int currentType = 0; + + int maxX = gdi.getCX(); + + list.getBaseType(types, currentType); + gdi.addSelection("BaseType", 150, 400, 0, "Listtyp:"); + gdi.addItem("BaseType", types); + gdi.selectItemByData("BaseType", currentType); + gdi.autoGrow("BaseType"); + + list.getResultModule(*oe, types, currentType); + gdi.addSelection("ResultType", 150, 400, editListCB, "Resultatuträkning:"); + gdi.addItem("ResultType", types); + gdi.autoGrow("ResultType"); + gdi.selectItemByData("ResultType", currentType); + + list.getSortOrder(false, types, currentType); + gdi.addSelection("SortOrder", 170, 400, 0, "Global sorteringsordning:"); + gdi.addItem("SortOrder", types); + gdi.autoGrow("SortOrder"); + + gdi.selectItemByData("SortOrder", currentType); + + list.getSubType(types, currentType); + gdi.addSelection("SubType", 150, 400, editListCB, "Sekundär typ:"); + gdi.addItem("SubType", types); + gdi.selectItemByData("SubType", currentType); + oListInfo::EBaseType subType = oListInfo::EBaseType(currentType); + + maxX = max(maxX, gdi.getCX()); + gdi.popX(); + gdi.dropLine(3); + + gdi.fillRight(); + gdi.addCheckbox("SupportFrom", "Support time from control", 0, list.supportFrom()); + gdi.addCheckbox("SupportTo", "Support time to control", 0, list.supportTo()); + gdi.dropLine(2); + gdi.popX(); + + gdi.fillDown(); + gdi.addString("", 1, "Filter"); + gdi.dropLine(0.5); + vector< pair > filters; + list.getFilters(filters); + gdi.fillRight(); + int xp = gdi.getCX(); + int yp = gdi.getCY(); + //const int w = gdi.scaleLength(130); + for (size_t k = 0; k < filters.size(); k++) { + gdi.addCheckbox(xp, yp, "filter" + itos(k), filters[k].first, 0, filters[k].second); + xp = gdi.getCX(); + maxX = max(maxX, xp); + if (k % 10 == 9) { + xp = x1 + margin; + gdi.setCX(xp); + yp += int(1.3 * gdi.getLineHeight()); + } + } + + gdi.popX(); + gdi.dropLine(2); + gdi.fillDown(); + gdi.addString("", 1, "Underfilter"); + gdi.dropLine(0.5); + vector< pair > subfilters; + list.getSubFilters(subfilters); + gdi.fillRight(); + xp = gdi.getCX(); + yp = gdi.getCY(); + for (size_t k = 0; k < subfilters.size(); k++) { + gdi.addCheckbox(xp, yp, "subfilter" + itos(k), subfilters[k].first, 0, subfilters[k].second); + if (subType == oListInfo::EBaseTypeNone) + gdi.disableInput(("subfilter" + itos(k)).c_str()); + //xp += w; + xp = gdi.getCX(); + maxX = max(maxX, xp); + if (k % 10 == 9) { + xp = x1 + margin; + gdi.setCX(xp); + yp += int(1.3 * gdi.getLineHeight()); + } + } + + gdi.popX(); + gdi.dropLine(2); + + gdi.fillDown(); + gdi.addString("", 1, "Typsnitt"); + gdi.dropLine(0.5); + gdi.fillRight(); + const char *expl[4] = {"Rubrik", "Underrubrik", "Lista", "Underlista"}; + vector< pair > fonts; + gdi.getEnumeratedFonts(fonts); + sort(fonts.begin(), fonts.end()); + + for (int k = 0; k < 4; k++) { + string id("Font" + itos(k)); + gdi.addCombo(id, 200, 300, 0, expl[k]); + gdi.addItem(id, fonts); + + gdi.setText(id, list.getFontFace(k)); + gdi.setCX(gdi.getCX()+20); + int f = list.getFontFaceFactor(k); + string ff = f == 0 ? "100 %" : itos(f) + " %"; + gdi.addInput("FontFactor" + itos(k), ff, 4, 0, "Skalfaktor", "Relativ skalfaktor för typsnittets storlek i procent"); + f = list.getExtraSpace(k); + gdi.addInput("ExtraSpace" + itos(k), itos(f), 4, 0, "Avstånd", "Extra avstånd ovanför textblock"); + if (k == 1) { + gdi.dropLine(3); + gdi.popX(); + } + } + + if (!newList) { + gdi.dropLine(0.8); + gdi.setCX(gdi.getCX()+20); + gdi.addButton("ApplyListProp", "OK", editListCB); + gdi.addButton("Cancel", "Avbryt", editListCB); + } + else { + gdi.setCX(x1); + gdi.setCY(gdi.getHeight()); + gdi.dropLine(); + gdi.addButton("ApplyListProp", "Skapa", editListCB); + gdi.addButton("CancelNew", "Avbryt", editListCB); + } + + gdi.dropLine(3); + int maxY = gdi.getCY(); + + gdi.fillDown(); + gdi.popX(); + gdi.setData("IsEditingList", 1); + + RECT rc; + rc.top = y1; + rc.left = x1; + rc.right = maxX + gdi.scaleLength(6); + rc.bottom = maxY; + + if (!newList) { + gdi.addRectangle(rc, colorLightBlue, true); + } + + gdi.scrollToBottom(); + gdi.refresh(); + gdi.setInputFocus("Name"); +} + +void ListEditor::makeDirty(gdioutput &gdi, DirtyFlag inside, DirtyFlag outside) { + if (inside == MakeDirty) + dirtyInt = true; + else if (inside == ClearDirty) + dirtyInt = false; + + if (outside == MakeDirty) + dirtyExt = true; + else if (outside == ClearDirty) + dirtyExt = false; + + if (gdi.hasField("SaveInside")) { + gdi.setInputStatus("SaveInside", dirtyInt || lastSaved != SavedInside); + } + + if (gdi.hasField("SaveFile")) { + gdi.setInputStatus("SaveFile", dirtyExt || lastSaved != SavedFile); + } +} + +bool ListEditor::checkSave(gdioutput &gdi) { + if (dirtyInt || dirtyExt) { + gdioutput::AskAnswer answer = gdi.askCancel("Vill du spara ändringar?"); + if (answer == gdioutput::AnswerCancel) + return false; + + if (answer == gdioutput::AnswerYes) { + if (currentIndex >= 0) + gdi.sendCtrlMessage("SaveInside"); + else if (gdi.sendCtrlMessage("SaveFile") == 0) + return false; + } + makeDirty(gdi, ClearDirty, ClearDirty); + } + + return true; +} + +void ListEditor::enableOpen(gdioutput &gdi) { + ListBoxInfo lbi; + bool enabled = true; + if (gdi.getSelectedItem("OpenList", lbi)) { + if (oe->getListContainer().isInternal(lbi.data)) + enabled = false; + } + + gdi.setInputStatus("DoOpen", enabled); +} + diff --git a/code/listeditor.h b/code/listeditor.h new file mode 100644 index 0000000..598f70a --- /dev/null +++ b/code/listeditor.h @@ -0,0 +1,82 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class MetaList; +class MetaListPost; +class MetaListContainer; +class gdioutput; +class BaseInfo; +class ButtonInfo; +class oEvent; +enum EPostType; +#include + +class ListEditor { +private: + enum SaveType {NotSaved, SavedInside, SavedFile}; + oEvent *oe; + MetaList *currentList; + void setCurrentList(MetaList *lst); + int currentIndex; + string savedFileName; + bool dirtyExt; + bool dirtyInt; + SaveType lastSaved; + const char *getIndexDescription(EPostType type); + + void showLine(gdioutput &gdi, const vector &line, int ix) const; + int editList(gdioutput &gdi, int type, BaseInfo &data); + ButtonInfo &addButton(gdioutput &gdi, const MetaListPost &mlp, int x, int y, + int lineIx, int ix) const; + + void editListPost(gdioutput &gdi, const MetaListPost &mlp, int id); + void editListProp(gdioutput &gdi, bool newList); + + enum DirtyFlag {MakeDirty, ClearDirty, NoTouch}; + + /// Check (and autosave) if there are unsaved changes in a dialog box + void checkUnsaved(gdioutput &gdi); + + /// Check and ask if there are changes to save + bool checkSave(gdioutput &gdi); + + // Enable or disable open button + void enableOpen(gdioutput &gdi); + + void makeDirty(gdioutput &gdi, DirtyFlag inside, DirtyFlag outside); +public: + ListEditor(oEvent *oe); + virtual ~ListEditor(); + + //void load(MetaList *list); + void load(const MetaListContainer &mlc, int index); + + void show(gdioutput &gdi); + + MetaList *getCurrentList() const {return currentList;}; + + + friend int editListCB(gdioutput*, int, void *); + +}; diff --git a/code/liveresult.cpp b/code/liveresult.cpp new file mode 100644 index 0000000..7da621d --- /dev/null +++ b/code/liveresult.cpp @@ -0,0 +1,435 @@ +/********************i**************************************************** + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "oEvent.h" +#include "gdioutput.h" +#include "meos_util.h" +#include +#include "Localizer.h" +#include +#include "gdifonts.h" +#include "meosexception.h" +#include "liveresult.h" + +LiveResult::LiveResult(oEvent *oe) : oe(oe), active(false), lastTime(0), rToWatch(0) { + baseFont = oe->getPropertyString("LiveResultFont", "Consolas"); + showResultList = -1; + timerScale = 1.0; +} + + +string LiveResult::getFont(const gdioutput &gdi, double relScale) const { + int h,w; + gdi.getTargetDimension(w, h); + if (!gdi.isFullScreen()) + w -= gdi.scaleLength(160); + + double fact = min(h/180.0, w/300.0); + + double size = relScale * fact; + char ss[32]; + sprintf_s(ss, "%f", size); + string font = baseFont + ";" + ss; + return font; +} + +void LiveResult::showDefaultView(gdioutput &gdi) { + int h,w; + gdi.getTargetDimension(w, h); + if (!gdi.isFullScreen()) + w -= gdi.scaleLength(160); + + RECT rc; + rc.top = h-24; + rc.left = 20; + rc.right = w - 30; + rc.bottom = h - 22; + + string font = getFont(gdi, 1.0); + gdi.addRectangle(rc, colorLightYellow, true); + gdi.addString("timing", 50, w / 2, textCenter|boldHuge, "MeOS Timing", 0, 0, font.c_str()); + + TextInfo &ti = gdi.addString("measure", 0, 0, boldHuge, "55:55:55", 0, 0, font.c_str()); + int tw = ti.textRect.right - ti.textRect.left; + timerScale = double(w) * 0.8 / double(tw); + gdi.removeString("measure"); +} + +void LiveResult::showTimer(gdioutput &gdi, const oListInfo &liIn) { + li = liIn; + active = true; + + int h,w; + gdi.getTargetDimension(w, h); + gdi.clearPage(false); + showDefaultView(gdi); + + gdi.registerEvent("DataUpdate", 0).setHandler(this); + gdi.setData("DataSync", 1); + gdi.setData("PunchSync", 1); + gdi.setRestorePoint("LiveResult"); + + lastTime = 0; + vector pp; + oe->synchronizeList(oLRunnerId, true, false); + oe->synchronizeList(oLPunchId, false, true); + + oe->getLatestPunches(lastTime, pp); + processedPunches.clear(); + + map, vector > > storedPunches; + int fromPunch = li.getParam().useControlIdResultFrom; + int toPunch = li.getParam().useControlIdResultTo; + if (fromPunch == 0) + fromPunch = oPunch::PunchStart; + if (toPunch == 0) + toPunch = oPunch::PunchFinish; + + for (size_t k = 0; k < pp.size(); k++) { + lastTime = max(pp[k]->getModificationTime(), lastTime); + pRunner r = pp[k]->getTiedRunner(); + if (r) { + pair key = make_pair(r->getId(), pp[k]->getControlId()); + processedPunches[key] = max(processedPunches[key], pp[k]->getAdjustedTime()); + + if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId())) + continue; // Filter class + + if (pp[k]->getTypeCode() == fromPunch) { + storedPunches[r->getId()].first.push_back(k); + } + else if (pp[k]->getTypeCode() == toPunch) { + storedPunches[r->getId()].second.push_back(k); + } + } + } + startFinishTime.clear(); + results.clear(); + for (map, vector > >::iterator it = storedPunches.begin(); + it != storedPunches.end(); ++it) { + vector &froms = it->second.first; + vector &tos = it->second.second; + pRunner r = oe->getRunner(it->first, 0); + for (size_t j = 0; j < tos.size(); j++) { + int fin = pp[tos[j]]->getAdjustedTime(); + int time = 100000000; + int sta = 0; + for (size_t k = 0; k < froms.size(); k++) { + int t = fin - pp[froms[k]]->getAdjustedTime(); + if (t > 0 && t < time) { + time = t; + sta = pp[froms[k]]->getAdjustedTime(); + } + } + if (time < 100000000 && r->getStatus() <= StatusOK) { +// results.push_back(Result()); +// results.back().r = r; +// results.back().time = time; + startFinishTime[r->getId()].first = sta; + startFinishTime[r->getId()].second = fin; + + } + } + } + + resYPos = h/3; + + calculateResults(); + showResultList = 0; + gdi.addTimeoutMilli(1000, "res", 0).setHandler(this); + gdi.refreshFast(); +} + + +void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) { + if (type == GUI_EVENT) { + vector pp; + oe->getLatestPunches(lastTime, pp); + + int fromPunch = li.getParam().useControlIdResultFrom; + int toPunch = li.getParam().useControlIdResultTo; + if (fromPunch == 0) + fromPunch = oPunch::PunchStart; + if (toPunch == 0) + toPunch = oPunch::PunchFinish; + + bool hasCheckedOld = false; + vector< pair > enter, exit, backExit; + + for (size_t k = 0; k < pp.size(); k++) { + lastTime = max(pp[k]->getModificationTime(), lastTime); + pRunner r = pp[k]->getTiedRunner(); + if (!r) + continue; + + if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId())) + continue; // Filter class + + pair key = make_pair(r->getId(), pp[k]->getControlId()); + + bool accept = !processedPunches.count(key) || abs(processedPunches[key] - pp[k]->getAdjustedTime()) > 5; + + if (accept && !hasCheckedOld && pp[k]->getTypeCode() == fromPunch) { + hasCheckedOld = true; + while (rToWatch.size() > 1) { + watchedR.push_back(rToWatch.front()); + rToWatch.erase(rToWatch.begin()); // TODO: Better algorithm for forgetting? + } + } + + processedPunches[key] = pp[k]->getAdjustedTime(); + + if (accept) { + if (pp[k]->getTypeCode() == fromPunch) { + enter.push_back(make_pair(pp[k]->getAdjustedTime(), pp[k])); + } + else if (pp[k]->getTypeCode() == toPunch) { + if (count(rToWatch.begin(), rToWatch.end(), r->getId()) > 0) { + exit.push_back(make_pair(pp[k]->getAdjustedTime(), pp[k])); + } + else if (count(watchedR.begin(), watchedR.end(), r->getId()) > 0) { + backExit.push_back(make_pair(pp[k]->getAdjustedTime(), pp[k])); + } + } + } + } + + sort(enter.begin(), enter.end()); + sort(exit.begin(), exit.end()); + + int h,w; + gdi.getTargetDimension(w, h); + bool doRefresh = false; + + for (size_t k = 0; k < enter.size(); k++) { + showResultList = -1; + const oFreePunch *fp = enter[k].second; + pRunner newRToWatch = fp->getTiedRunner(); + + if (count(rToWatch.begin(), rToWatch.end(), newRToWatch->getId())) + continue; + + rToWatch.push_back(newRToWatch->getId()); + gdi.restore("LiveResult", false); + startFinishTime[newRToWatch->getId()].first = fp->getAdjustedTime(); + isDuel = false; + if (rToWatch.size() == 1) { + string font = getFont(gdi, timerScale); + BaseInfo *bi = gdi.setText("timing", newRToWatch->getName(), false); + dynamic_cast(*bi).changeFont(getFont(gdi, 0.7)); + gdi.addTimer(h/2, w/2, boldHuge|textCenter|timeWithTenth, 0, 0, 0, NOTIMEOUT, font.c_str()); + screenSize = 1; + } + else if (rToWatch.size() == 2) { + string font = getFont(gdi, timerScale * 0.6); + + pRunner r0 = oe->getRunner(rToWatch[0], 0); + pRunner r1 = oe->getRunner(rToWatch[1], 0); + + string n = (r0 ? r0->getName(): "-") + " / " + (r1 ? r1->getName() : "-"); + bool duel = r0 && r1 && fromPunch == oPunch::PunchStart && + r0->getTeam() != 0 && + r0->getTeam() == r1->getTeam(); + isDuel = duel; + if (n.length() < 30) { + BaseInfo *bi = gdi.setText("timing", n, false); + TextInfo &ti = dynamic_cast(*bi); + ti.changeFont(getFont(gdi, 0.5)); + } + else { + BaseInfo *bi = gdi.setText("timing", "", false); + TextInfo &ti = dynamic_cast(*bi); + string sfont = getFont(gdi, 0.5); + TextInfo &ti2 = gdi.addString("n1", ti.yp, gdi.scaleLength(20), boldHuge, + "#" + (r0 ? r0->getName() : string("")), 0, 0, sfont.c_str()); + gdi.addString("n2", ti.yp + ti2.getHeight() + 4, gdi.getWidth(), boldHuge | textRight, + "#" + (r1 ? r1->getName() : string("")), 0, 0, sfont.c_str()); + } + int id1 = rToWatch[0]; + int id2 = rToWatch[1]; + + int t1 = startFinishTime[id1].first; + int diff = abs(fp->getAdjustedTime() - t1); + runner2ScreenPos[id1] = 1; + runner2ScreenPos[id2] = 2; + screenSize = 2; + int startTimeR2 = 0; + if (duel) { + // Ensure same start time + int t2 = startFinishTime[id2].first; + int st = min(t1,t2); + startFinishTime[id1].first = st; + startFinishTime[id2].first = st; + + for (size_t i = 0; i < rToWatch.size(); i++) { + pRunner r = oe->getRunner(rToWatch[i], 0); + if (r) { + r->synchronize(); + r->setStartTime(st, true, false, true); + r->synchronize(false); + } + } + startTimeR2 = diff; + } + + gdi.addTimer(h/2, w/2-w/4, boldHuge|textCenter|timeWithTenth, diff, 0, 0, NOTIMEOUT, font.c_str()).id = "timer1"; + gdi.addTimer(h/2, w/2+w/4, boldHuge|textCenter|timeWithTenth, startTimeR2, 0, 0, NOTIMEOUT, font.c_str()).id = "timer2"; + } + + doRefresh = true; + } + + for (size_t k = 0; k < exit.size(); k++) { + const oFreePunch *fp = exit[k].second; + pRunner rToFinish = fp->getTiedRunner(); + + if (count(rToWatch.begin(), rToWatch.end(), rToFinish->getId()) > 0) { + showResultList = -1; + pair &se = startFinishTime[rToFinish->getId()]; + se.second = fp->getAdjustedTime(); + int rt = se.second - se.first; + size_t ix = find(rToWatch.begin(), rToWatch.end(), rToFinish->getId()) - rToWatch.begin(); + + if (screenSize == 1) { + gdi.restore("LiveResult", false); + string font = getFont(gdi, timerScale); + gdi.addString("", h/2, w/2, boldHuge|textCenter, formatTime(rt), 0, 0, font.c_str()).setColor(colorGreen); + gdi.addTimeout(5, 0).setHandler(this); + } + else if (screenSize == 2) { + string id = "timer" + itos(runner2ScreenPos[rToFinish->getId()]); + BaseInfo *bi = gdi.setText(id, formatTime(rt), false); + string font = getFont(gdi, timerScale * 0.6); + + if (bi) { + TextInfo &ti = dynamic_cast(*bi); + ti.format = boldHuge|textCenter; + ti.hasTimer = false; + + if (rToWatch.size() == 2 || !isDuel) + ti.setColor(colorGreen); + } + + if (rToWatch.size() == 1) { + gdi.addTimeout(5, 0).setHandler(this); + } + } + + rToWatch.erase(rToWatch.begin() + ix); + doRefresh = true; + } + } + + for (size_t k = 0; k < backExit.size(); k++) { + const oFreePunch *fp = backExit[k].second; + pRunner rToFinish = fp->getTiedRunner(); + if (count(watchedR.begin(), watchedR.end(), rToFinish->getId()) > 0) { + pair &se = startFinishTime[rToFinish->getId()]; + se.second = fp->getAdjustedTime(); + size_t ix = find(watchedR.begin(), watchedR.end(), rToFinish->getId()) - watchedR.begin(); + watchedR.erase(watchedR.begin() + ix); + } + } + + if (doRefresh) + gdi.refreshFast(); + } + else if (type == GUI_TIMEOUT) { + gdi.restore("LiveResult", false); + int h,w; + gdi.getTargetDimension(w, h); + gdi.fillDown(); + BaseInfo *bi = gdi.setTextTranslate("timing", "MeOS Timing", false); + TextInfo &ti = dynamic_cast(*bi); + ti.changeFont(getFont(gdi, 0.7)); + gdi.refreshFast(); + resYPos = ti.textRect.bottom + gdi.scaleLength(20); + calculateResults(); + showResultList = 0; + gdi.addTimeoutMilli(300, "res", 0).setHandler(this); + } + else if (type == GUI_TIMER) { + if (size_t(showResultList) >= results.size()) + return; + Result &res = results[showResultList]; + string font = getFont(gdi, 0.7); + int y = resYPos; + pRunner r = oe->getRunner(res.runnerId, 0); + if (!r) { + showResultList++; + gdi.addTimeoutMilli(10, "res" + itos(showResultList), 0).setHandler(this); + } + else if (res.place > 0) { + int h,w; + gdi.getTargetDimension(w, h); + + gdi.takeShownStringsSnapshot(); + TextInfo &ti = gdi.addStringUT(y, 30, fontLarge, itos(res.place) + ".", 0, 0, font.c_str()); + int ht = ti.textRect.bottom - ti.textRect.top; + gdi.addStringUT(y, 30 + ht * 2 , fontLarge, r->getName(), 0, 0, font.c_str()); + //int w = gdi.getWidth(); + gdi.addStringUT(y, w - 4 * ht, fontLarge, formatTime(res.time), 0, 0, font.c_str()); + gdi.refreshSmartFromSnapshot(false); + resYPos += int (ht * 1.1); + showResultList++; + + int limit = h - ht * 2; + //OutputDebugString(("w:" + itos(resYPos) + " " + itos(limit) + "\n").c_str()); + if ( resYPos < limit ) + gdi.addTimeoutMilli(300, "res" + itos(showResultList), 0).setHandler(this); + } + } +} + +void LiveResult::calculateResults() { + rToWatch.clear(); + results.clear(); + results.reserve(startFinishTime.size()); + const int highTime = 10000000; + for (map >::iterator it = startFinishTime.begin(); + it != startFinishTime.end(); ++it) { + pRunner r = oe->getRunner(it->first, 0); + if (!r) + continue; + results.push_back(Result()); + results.back().runnerId = it->first; + results.back().time = it->second.second - it->second.first; + if (results.back().time <= 0 || r->getStatus() > StatusOK) + results.back().time = highTime; + } + + sort(results.begin(), results.end()); + + int place = 1; + for (size_t k = 0; k< results.size(); k++) { + if (results[k].time < highTime) { + if (k>0 && results[k-1].time < results[k].time) + place = k + 1; + + results[k].place = place; + } + else { + results[k].place = 0; + } + } +} diff --git a/code/liveresult.h b/code/liveresult.h new file mode 100644 index 0000000..0baf095 --- /dev/null +++ b/code/liveresult.h @@ -0,0 +1,68 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "oListInfo.h" +#include "guihandler.h" + +class gdioutput; + +class LiveResult : public GuiHandler { + oEvent *oe; + oListInfo li; + bool active; + unsigned int lastTime; + map< pair, int > processedPunches; + vector rToWatch; + vector watchedR;// Backlog + + map runner2ScreenPos; + int screenSize; + bool isDuel; + + string baseFont; + void showDefaultView(gdioutput &gdi); + map > startFinishTime; + int showResultList; + int resYPos; + string getFont(const gdioutput &gdi, double relScale) const; + double timerScale; + struct Result { + int place; + int runnerId; + int time; + bool operator<(const Result &b) const { + return time < b.time; + } + }; + + vector< Result > results; + + void calculateResults(); + +public: + LiveResult(oEvent *oe); + ~LiveResult() {} + + void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type); + + void showTimer(gdioutput &gdi, const oListInfo &li); +}; diff --git a/code/localizer.cpp b/code/localizer.cpp new file mode 100644 index 0000000..da1ecc7 --- /dev/null +++ b/code/localizer.cpp @@ -0,0 +1,460 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "localizer.h" +#include +#include +#include "meos_util.h" +#include "random.h" +#include "oFreeImport.h" + +class LocalizerImpl +{ + string language; + map table; + map unknown; + void loadTable(const vector &raw, const string &language); + mutable oWordList *givenNames; + +public: + + const oWordList &getGivenNames() const; + + void translateAll(const LocalizerImpl &all); + + const string &translate(const string &str, bool &found); + + void saveUnknown(const string &file); + void saveTable(const string &file); + void loadTable(const string &file, const string &language); + void loadTable(int resource, const string &language); + + void clear(); + LocalizerImpl(void); + ~LocalizerImpl(void); +}; + +Localizer::LocalizerInternal::LocalizerInternal(void) +{ + impl = new LocalizerImpl(); + implBase = 0; + owning = true; + user = 0; +} + +Localizer::LocalizerInternal::~LocalizerInternal(void) +{ + if (user) { + user->owning = true; + impl = 0; + implBase = 0; + } + else { + delete impl; + delete implBase; + } +} + +void Localizer::LocalizerInternal::set(Localizer &lio) { + Localizer::LocalizerInternal &li = *lio.linternal; + if (li.user || user) + throw std::exception("Runtime error"); + + if (owning) { + delete impl; + delete implBase; + } + + implBase = li.implBase; + impl = li.impl; + li.user = this; +} + +vector Localizer::LocalizerInternal::getLangResource() const { + vector v; + for (map::const_iterator it = langResource.begin(); it !=langResource.end(); ++it) + v.push_back(it->first); + + return v; +} + +const oWordList &Localizer::LocalizerInternal::getGivenNames() const { + return impl->getGivenNames(); +} + +LocalizerImpl::LocalizerImpl(void) +{ + givenNames = 0; +} + +LocalizerImpl::~LocalizerImpl(void) +{ + if (givenNames) + delete givenNames; +} + +const string &Localizer::LocalizerInternal::tl(const string &str) const { + bool found; + const string *ret = &impl->translate(str, found); + if (found || !implBase) + return *ret; + + ret = &implBase->translate(str, found); + return *ret; +} + +const string &LocalizerImpl::translate(const string &str, bool &found) +{ + found = false; + static int i = 0; + const int bsize = 17; + static string value[bsize]; + int len = str.length(); + + if (len==0) + return str; + + if (str[0]=='#') { + i = (i + 1)%bsize; + value[i] = str.substr(1); + found = true; + return value[i]; + } + + if (str[0]==',' || str[0]==' ' || str[0]=='.' + || str[0]==':' || str[0]==';' || str[0]=='<' || str[0]=='>' || str[0]=='-' || str[0]==0x96) { + unsigned k=1; + while(str[k] && (str[k]==' ' || str[k]=='.' || str[k]==':' || str[k]=='<' || str[k]=='>' + || str[k]=='-' || str[k]==0x96)) + k++; + + if (k::const_iterator it = table.find(str); + if (it != table.end()) { + found = true; + return it->second; + } + + int subst = str.find_first_of('#'); + if (subst != str.npos) { + string s = translate(str.substr(0, subst), found); + vector split_vec; + split(str.substr(subst+1), "#", split_vec); + split_vec.push_back(""); + const char *subsymb = "XYZW"; + size_t subpos = 0; + string ret; + size_t lastpos = 0; + for (size_t k = 0; k=split_vec.size() || subpos>=4) + break; + if (s[k] == subsymb[subpos]) { + if (k>0 && isalnum(s[k-1])) + continue; + if (k+1 < s.size() && isalnum(s[k+1])) + continue; + ret += s.substr(lastpos, k-lastpos); + ret += split_vec[subpos]; + lastpos = k+1; + subpos++; + } + } + if (lastpos1) + unknown[str] = ""; +#endif + found = false; + i = (i + 1)%bsize; + value[i] = str; + return value[i]; + } + + string suffix; + int pos = str.find_last_not_of(last); + + while(pos>0) { + char last = str[pos]; + if (last != ':' && last != ' ' && last != ',' && last != '.' && + last != ';' && last != '<' && last != '>' && last != '-' && last != 0x96) + break; + + pos = str.find_last_not_of(last, pos); + } + + suffix = str.substr(pos+1); + + string key = str.substr(0, str.length()-suffix.length()); + it = table.find(key); + if (it != table.end()) { + i = (i + 1)%bsize; + value[i] = it->second + suffix; + found = true; + return value[i]; + } +#ifdef _DEBUG + if (key.length() > 1) + unknown[key] = ""; +#endif + + found = false; + i = (i + 1)%bsize; + value[i] = str; + return value[i]; +} +const string newline = "\n"; + +void LocalizerImpl::saveUnknown(const string &file) +{ + if (!unknown.empty()) { + ofstream fout(file.c_str(), ios::trunc|ios::out); + for (map::iterator it = unknown.begin(); it!=unknown.end(); ++it) { + string value = it->second; + string key = it->first; + if (value.empty()) { + value = key; + + int nl = value.find(newline); + int n2 = value.find("."); + + if (nl!=string::npos || n2!=string::npos) { + while (nl!=string::npos) { + value.replace(nl, newline.length(), "\\n"); + nl = value.find(newline); + } + key = "help:" + itos(value.length()) + itos(value.find_first_of(".")); + } + } + fout << key << " = " << value << endl; + } + } +} + + +const oWordList &LocalizerImpl::getGivenNames() const { + if (givenNames == 0) { + char bf[260]; + getUserFile(bf, "given.mwd"); + givenNames = new oWordList(); + try { + givenNames->load(bf); + } catch(std::exception &) {} + } + return *givenNames; +} + +#ifndef MEOSDB + +void Localizer::LocalizerInternal::loadLangResource(const string &name) { + map::iterator it = langResource.find(name); + if (it == langResource.end()) + throw std::exception("Unknown language"); + + string &res = it->second; + + int i = atoi(res.c_str()); + if (i > 0) + impl->loadTable(i, name); + else + impl->loadTable(res, name); +} + +void Localizer::LocalizerInternal::addLangResource(const string &name, const string &resource) { + langResource[name] = resource; + if (implBase == 0) { + implBase = new LocalizerImpl(); + implBase->loadTable(atoi(resource.c_str()), name); + } +} + +void Localizer::LocalizerInternal::debugDump(const string &untranslated, const string &translated) const { + if (implBase) { + impl->translateAll(*implBase); + } + impl->saveUnknown(untranslated); + impl->saveTable(translated); +} + +void LocalizerImpl::translateAll(const LocalizerImpl &all) { + map::const_iterator it; + bool f; + for (it = all.table.begin(); it != all.table.end(); ++it) { + translate(it->first, f); + if (!f) { + unknown[it->first] = it->second; + } + } +} + +void LocalizerImpl::saveTable(const string &file) +{ + ofstream fout((language+"_"+file).c_str(), ios::trunc|ios::out); + for (map::iterator it = table.begin(); it!=table.end(); ++it) { + string value = it->second; + int nl = value.find(newline); + while (nl!=string::npos) { + value.replace(nl, newline.length(), "\\n"); + nl = value.find(newline); + } + fout << it->first << " = " << value << endl; + } +} + +void LocalizerImpl::loadTable(int id, const string &language) +{ + string sname = "#"+itos(id); + const char *name = sname.c_str(); + HRSRC hResInfo = FindResource(0, name, "#300"); + HGLOBAL hGlobal = LoadResource(0, hResInfo); + + if (hGlobal==0) + throw std::exception("Resource not found"); + + int size = SizeofResource(0, hResInfo); + + const char *lang_src = (char *)LockResource(hGlobal); + char *lang = new char[size]; + memcpy(lang, lang_src, size); + char *bf; + vector raw; + int pos = 0; + while (pos < size) { + bf = &lang[pos]; + while(pos0 && bf[0] != '#') + raw.push_back(bf); + pos++; + if (pos raw; + raw.reserve(line); + while (!fin.eof()) { + bf[0] = 0; + fin.getline(bf, 8*1024); + if (bf[0]!=0 && bf[0]!='#') + raw.push_back(bf); + } + + loadTable(raw, language); +} + + +void LocalizerImpl::loadTable(const vector &raw, const string &language) +{ + vector order(raw.size()); + for (size_t k = 0; klanguage = language; + for (size_t k=0;k0 && s[spos-1]==' ') + spos--; + + while (unsigned(epos). + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include +#include +#include +#include + +class LocalizerImpl; +class oWordList; + +class Localizer { + class LocalizerInternal { + private: + map langResource; + LocalizerImpl *impl; + LocalizerImpl *implBase; + + bool owning; + LocalizerInternal *user; + + public: + + void debugDump(const string &untranslated, const string &translated) const; + + vector getLangResource() const; + void loadLangResource(const string &name); + void addLangResource(const string &name, const string &resource); + + /** Translate string */ + const string &tl(const string &str) const; + + void set(Localizer &li); + + /** Get database with given names */ + const oWordList &getGivenNames() const; + + LocalizerInternal(); + ~LocalizerInternal(); + }; +private: + LocalizerInternal *linternal; + +public: + bool capitalizeWords() const; + + LocalizerInternal &get() {return *linternal;} + const string &tl(const string &str) const {return linternal->tl(str);}; + + void init() {linternal = new LocalizerInternal();} + void unload() {delete linternal; linternal = 0;} + + Localizer() : linternal(0) {} + ~Localizer() {unload();} +}; + +extern Localizer lang; diff --git a/code/meos.cpp b/code/meos.cpp new file mode 100644 index 0000000..aab0ff4 --- /dev/null +++ b/code/meos.cpp @@ -0,0 +1,1745 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// meos.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "resource.h" +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include "recorder.h" + +#include "gdioutput.h" +#include "commctrl.h" +#include "SportIdent.h" +#include "TabBase.h" +#include "TabCompetition.h" +#include "TabAuto.h" +#include "TabClass.h" +#include "TabCourse.h" +#include "TabControl.h" +#include "TabSI.h" +#include "TabList.h" +#include "TabTeam.h" +#include "TabSpeaker.h" +#include "TabMulti.h" +#include "TabRunner.h" +#include "TabClub.h" +#include "progress.h" +#include "inthashmap.h" +#include +#include "localizer.h" +#include "intkeymap.hpp" +#include "intkeymapimpl.hpp" +#include "download.h" +#include "meos_util.h" +#include +#include "random.h" +#include "metalist.h" +#include "gdiconstants.h" +#include "socket.h" +#include "autotask.h" +#include "meosexception.h" +#include "parser.h" + +gdioutput *gdi_main=0; +oEvent *gEvent=0; +SportIdent *gSI=0; +Localizer lang; +AutoTask *autoTask = 0; +#ifdef _DEBUG + bool enableTests = true; +#else + bool enableTests = false; +#endif + +vector gdi_extra; +void initMySQLCriticalSection(bool init); + +HWND hWndMain; +HWND hWndWorkspace; + +#define MAX_LOADSTRING 100 + +#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +void removeTempFiles(); +void Setup(bool overwrite, bool overwriteAll); + +// Global Variables: +HINSTANCE hInst; // current instance +CHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text +TCHAR szWorkSpaceClass[MAX_LOADSTRING]; // The title bar text + +// Foward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK WorkSpaceWndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam); +void registerToolbar(HINSTANCE hInstance); +extern const char *szToolClass; + +HHOOK g_hhk; //- handle to the hook procedure. + +HWND hMainTab=NULL; + +list *tabList=0; +void scrollVertical(gdioutput *gdi, int yInc, HWND hWnd); +static int currentFocusIx = 0; + +void resetSaveTimer() { + if (autoTask) + autoTask->resetSaveTimer(); +} + +void LoadPage(const string &name) +{ + list::iterator it; + + for (it=tabList->begin(); it!=tabList->end(); ++it) { + if (it->name==name) + it->loadPage(*gdi_main); + } +} + +void LoadClassPage(gdioutput &gdi) +{ + LoadPage("Klasser"); +} + +void dumpLeaks() { + _CrtDumpMemoryLeaks(); +} + +void LoadPage(gdioutput &gdi, TabType type) { + gdi.setWaitCursor(true); + TabBase *t = gdi.getTabs().get(type); + if (t) + t->loadPage(gdi); + gdi.setWaitCursor(false); +} + +// Path to settings file +static char settings[260]; +// Startup path +static char programPath[MAX_PATH]; + +void mainMessageLoop(HACCEL hAccelTable, DWORD time) { + MSG msg; + BOOL bRet; + + if (time > 0) { + time += GetTickCount(); + } + // Main message loop: + while ( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0 ) { + if (bRet == -1) + return; + + if (hAccelTable == 0 || !TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (time != 0) { + if (GetTickCount() > time) + return; + } + } +} + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + atexit(dumpLeaks); // + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); + + if (strstr(lpCmdLine, "-s") != 0) { + Setup(true, false); + exit(0); + } + else if (strstr(lpCmdLine, "-test") != 0) { + enableTests = true; + } + + + for (int k = 0; k < 100; k++) { + RunnerStatusOrderMap[k] = 0; + } + RunnerStatusOrderMap[StatusOK] = 0; + RunnerStatusOrderMap[StatusMAX] = 1; + RunnerStatusOrderMap[StatusMP] = 2; + RunnerStatusOrderMap[StatusDNF] = 3; + RunnerStatusOrderMap[StatusDQ] = 4; + RunnerStatusOrderMap[StatusDNS] = 5; + RunnerStatusOrderMap[StatusUnknown] = 6; + RunnerStatusOrderMap[StatusNotCompetiting] = 7; + + lang.init(); + StringCache::getInstance().init(); + + GetCurrentDirectory(MAX_PATH, programPath); + + getUserFile(settings, "meospref.xml"); + + Parser::test(); + + int rInit = (GetTickCount() / 100); + InitRanom(rInit, rInit/379); + + tabList=new list; + + HACCEL hAccelTable; + + gdi_main = new gdioutput("main", 1.0, ANSI); + gdi_extra.push_back(gdi_main); + + try { + gEvent = new oEvent(*gdi_main); + } + catch (std::exception &ex) { + gdi_main->alert(string("Failed to create base event: ") + ex.what()); + return 0; + } + + gEvent->loadProperties(settings); + + lang.get().addLangResource("English", "104"); + lang.get().addLangResource("Svenska", "103"); + lang.get().addLangResource("Deutsch", "105"); + lang.get().addLangResource("Dansk", "106"); + lang.get().addLangResource("Français", "110"); + lang.get().addLangResource("Russian (ISO 8859-5)", "107"); + lang.get().addLangResource("English (ISO 8859-2)", "108"); + lang.get().addLangResource("English (ISO 8859-8)", "109"); + + if (fileExist("extra.lng")) { + lang.get().addLangResource("Extraspråk", "extra.lng"); + } + else { + char lpath[260]; + getUserFile(lpath, "extra.lng"); + if (fileExist(lpath)) + lang.get().addLangResource("Extraspråk", lpath); + } + + string defLang = gEvent->getPropertyString("Language", "Svenska"); + + // Backward compatibility + if (defLang=="103") + defLang = "Svenska"; + else if (defLang=="104") + defLang = "English"; + + gEvent->setProperty("Language", defLang); + + try { + lang.get().loadLangResource(defLang); + } + catch (std::exception &) { + lang.get().loadLangResource("Svenska"); + } + + try { + char listpath[MAX_PATH]; + getUserFile(listpath, ""); + vector res; + expandDirectory(listpath, "*.lxml", res); + expandDirectory(listpath, "*.listdef", res); +# +#ifdef _DEBUG + expandDirectory(".\\Lists\\", "*.lxml", res); + expandDirectory(".\\Lists\\", "*.listdef", res); +#endif + string err; + + for (size_t k = 0; kgetListContainer().load(MetaListContainer::InternalList, xlist, true); + } + catch (std::exception &ex) { + string errLoc = "Kunde inte ladda X\n\n(Y)#" + string(listpath) + "#" + lang.tl(ex.what()); + if (err.empty()) + err = lang.tl(errLoc); + else + err += "\n" + lang.tl(errLoc); + } + } + if (!err.empty()) + gdi_main->alert(err); + } + catch (std::exception &ex) { + gdi_main->alert(ex.what()); + //exit(1); + } + + gEvent->openRunnerDatabase("database"); + strcpy_s(szTitle, "MeOS"); + strcpy_s(szWindowClass, "MeosMainClass"); + strcpy_s(szWorkSpaceClass, "MeosWorkSpace"); + MyRegisterClass(hInstance); + registerToolbar(hInstance); + + string encoding = lang.tl("encoding"); + gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0), + gEvent->getPropertyString("TextFont", "Arial"), interpetEncoding(encoding)); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) { + return FALSE; + } + + RECT rc; + GetClientRect(hWndMain, &rc); + SendMessage(hWndMain, WM_SIZE, 0, MAKELONG(rc.right, rc.bottom)); + + gdi_main->init(hWndWorkspace, hWndMain, hMainTab); + gdi_main->getTabs().get(TCmpTab)->loadPage(*gdi_main); + + autoTask = new AutoTask(hWndMain, *gEvent, *gdi_main); + + autoTask->setTimers(); + + // Install a hook procedure to monitor the message stream for mouse + // messages intended for the controls in the dialog box. + g_hhk = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, + (HINSTANCE) NULL, GetCurrentThreadId()); + + hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS); + + initMySQLCriticalSection(true); + // Main message loop: + mainMessageLoop(hAccelTable, 0); + /*while (GetMessage(&msg, NULL, 0, 0)) { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + */ + tabAutoRegister(0); + tabList->clear(); + delete tabList; + tabList=0; + + delete autoTask; + autoTask = 0; + + for (size_t k = 0; kgetHWND()); + if (k < gdi_extra.size()) { + delete gdi_extra[k]; + gdi_extra[k] = 0; + } + } + } + + gdi_extra.clear(); + + if (gEvent) + gEvent->saveProperties(settings); + + delete gEvent; + gEvent = 0; + + initMySQLCriticalSection(false); + + removeTempFiles(); + + #ifdef _DEBUG + lang.get().debugDump("untranslated.txt", "translated.txt"); + #endif + + StringCache::getInstance().clear(); + lang.unload(); + + return 0; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage is only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this function +// so that the application will get 'well formed' small icons associated +// with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MEOS); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = 0;//(LPCSTR)IDC_MEOS; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + RegisterClassEx(&wcex); + + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wcex.lpfnWndProc = (WNDPROC)WorkSpaceWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MEOS); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = 0; + wcex.lpszMenuName = 0; + wcex.lpszClassName = szWorkSpaceClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + RegisterClassEx(&wcex); + + return true; +} + + +// GetMsgProc - monitors the message stream for mouse messages intended +// for a control window in the dialog box. +// Returns a message-dependent value. +// nCode - hook code. +// wParam - message flag (not used). +// lParam - address of an MSG structure. +LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + MSG *lpmsg; + + lpmsg = (MSG *) lParam; + if (nCode < 0 || !(IsChild(hWndWorkspace, lpmsg->hwnd))) + return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); + + switch (lpmsg->message) { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + if (gdi_main->getToolTip() != NULL) { + MSG msg; + + msg.lParam = lpmsg->lParam; + msg.wParam = lpmsg->wParam; + msg.message = lpmsg->message; + msg.hwnd = lpmsg->hwnd; + SendMessage(gdi_main->getToolTip(), TTM_RELAYEVENT, 0, + (LPARAM) (LPMSG) &msg); + } + break; + default: + break; + } + return (CallNextHookEx(g_hhk, nCode, wParam, lParam)); +} + +void flushEvent(const string &id, const string &origin, DWORD data, int extraData) +{ + for (size_t k = 0; kmakeEvent(id, origin, data, extraData, false); + } + } +} + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) +{ + if (code<0) + return CallNextHookEx(0, code, wParam, lParam); + + gdioutput *gdi = 0; + + if (size_t(currentFocusIx) < gdi_extra.size()) + gdi = gdi_extra[currentFocusIx]; + + if (!gdi) + gdi = gdi_main; + + + HWND hWnd = gdi ? gdi->getHWND() : 0; + + bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; + bool shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; + + //if (code<0) return CallNextHookEx( + if (wParam==VK_TAB) { + if ( (lParam& (1<<31))) { + SHORT state=GetKeyState(VK_SHIFT); + if (gdi) { + if (state&(1<<16)) + gdi->TabFocus(-1); + else + gdi->TabFocus(1); + } + } + return 1; + } + else if (wParam==VK_RETURN && (lParam & (1<<31))) { + if (gdi) + gdi->Enter(); + } + else if (wParam==VK_UP) { + bool c = false; + if (gdi && (lParam & (1<<31))) + c = gdi->UpDown(1); + + if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) + SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0); + } + else if (wParam == VK_NEXT && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) { + SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0); + } + else if (wParam == VK_PRIOR && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) { + SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0); + } + else if (wParam==VK_DOWN) { + bool c = false; + if (gdi && (lParam & (1<<31))) + c = gdi->UpDown(-1); + + if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown)) + SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); + } + else if (wParam==VK_LEFT && !(lParam & (1<<31))) { + if (!gdi || !gdi->hasEditControl()) + SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEUP, 0), 0); + } + else if (wParam==VK_RIGHT && !(lParam & (1<<31))) { + if (!gdi || !gdi->hasEditControl()) + SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); + } + else if (wParam==VK_ESCAPE && (lParam & (1<<31))) { + if (gdi) + gdi->Escape(); + } + else if (wParam==VK_F2) { + ProgressWindow pw(hWnd); + + pw.init(); + for (int k=0;k<=20;k++) { + pw.setProgress(k*50); + Sleep(100); + } + //pw.draw(); + } + else if (ctrlPressed && (wParam == VK_ADD || wParam == VK_SUBTRACT || + wParam == VK_F5 || wParam == VK_F6)) { + if (gdi) { + if (wParam == VK_ADD || wParam == VK_F5) + gdi->scaleSize(1.1); + else + gdi->scaleSize(1.0/1.1); + } + } + else if (wParam == 'C' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_COPY); + } + else if (wParam == 'V' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_PASTE); + } + else if (wParam == 'F' && ctrlPressed) { + if (gdi) { + if (!shiftPressed) + gdi->keyCommand(KC_FIND); + else + gdi->keyCommand(KC_FINDBACK); + } + } + else if (wParam == VK_DELETE) { + if (gdi) + gdi->keyCommand(KC_DELETE); + } + else if (wParam == 'I' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_INSERT); + } + else if (wParam == 'P' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_PRINT); + } + else if (wParam == VK_F5 && !ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_REFRESH); + } + else if (wParam == 'M' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_SPEEDUP); + } + else if (wParam == 'N' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_SLOWDOWN); + } + else if (wParam == ' ' && ctrlPressed) { + if (gdi) + gdi->keyCommand(KC_AUTOCOMPLETE); + } + + return 0; +} +// +// FUNCTION: InitInstance(HANDLE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + //WS_EX_CONTROLPARENT + HWND hDskTop=GetDesktopWindow(); + RECT rc; + GetClientRect(hDskTop, &rc); + + int xp = gEvent->getPropertyInt("xpos", 50); + int yp = gEvent->getPropertyInt("ypos", 20); + + int xs = gEvent->getPropertyInt("xsize", max(850, min(int(rc.right)-yp, 1124))); + int ys = gEvent->getPropertyInt("ysize", max(650, min(int(rc.bottom)-yp-40, 800))); + + gEvent->setProperty("ypos", yp + 16); + gEvent->setProperty("xpos", xp + 32); + gEvent->saveProperties(settings); // For other instance starting while running + gEvent->setProperty("ypos", yp); + gEvent->setProperty("xpos", xp); + + hWnd = CreateWindowEx(0, szWindowClass, szTitle, + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, + xp, yp, max(min(int(rc.right)-yp, xs), 200), + max(min(int(rc.bottom)-yp-40, ys), 100), + NULL, NULL, hInstance, NULL); + + if (!hWnd) + return FALSE; + + hWndMain = hWnd; + + SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, 0, GetCurrentThreadId()); + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + hWnd = CreateWindowEx(0, szWorkSpaceClass, "WorkSpace", WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, + 50, 200, 200, 100, hWndMain, NULL, hInstance, NULL); + + if (!hWnd) + return FALSE; + + hWndWorkspace=hWnd; + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + +void destroyExtraWindows() { + for (size_t k = 1; kgetHWND()); + } + } +} + +string uniqueTag(const char *base) { + int j = 0; + string b = base; + while(true) { + string tag = b + itos(j++); + if (getExtraWindow(tag, false) == 0) + return tag; + } +} + +gdioutput *getExtraWindow(const string &tag, bool toForeGround) { + for (size_t k = 0; khasTag(tag)) { + if (toForeGround) + SetForegroundWindow(gdi_extra[k]->getHWND()); + return gdi_extra[k]; + } + } + return 0; +} + +gdioutput *createExtraWindow(const string &tag, const string &title, int max_x, int max_y) { + if (getExtraWindow(tag, false) != 0) + throw meosException("Window already exists"); + + HWND hWnd; + + + HWND hDskTop=GetDesktopWindow(); + RECT rc; + GetClientRect(hDskTop, &rc); + + int xp = gEvent->getPropertyInt("xpos", 50) + 16; + int yp = gEvent->getPropertyInt("ypos", 20) + 32; + + for (size_t k = 0; kgetHWND(); + RECT rc; + if (GetWindowRect(hWnd, &rc)) { + xp = max(rc.left + 16, xp); + yp = max(rc.top + 32, yp); + } + } + } + + int xs = gEvent->getPropertyInt("xsize", max(850, min(int(rc.right)-yp, 1124))); + int ys = gEvent->getPropertyInt("ysize", max(650, min(int(rc.bottom)-yp-40, 800))); + + if (max_x>0) + xs = min(max_x, xs); + if (max_y>0) + ys = min(max_y, ys); + + hWnd = CreateWindowEx(0, szWorkSpaceClass, title.c_str(), + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, + xp, yp, max(xs, 200), max(ys, 100), 0, NULL, hInst, NULL); + + if (!hWnd) + return 0; + + ShowWindow(hWnd, SW_SHOWNORMAL); + UpdateWindow(hWnd); + gdioutput *gdi = new gdioutput(tag, 1.0, gdi_main->getEncoding()); + gdi->setFont(gEvent->getPropertyInt("TextSize", 0), + gEvent->getPropertyString("TextFont", "Arial"), gdi_main->getEncoding()); + + gdi->init(hWnd, hWnd, 0); + gdi->isTestMode = gdi_main->isTestMode; + if (gdi->isTestMode) { + if (!gdi_main->cmdAnswers.empty()) { + gdi->dbPushDialogAnswer(gdi_main->cmdAnswers.front()); + gdi_main->cmdAnswers.pop_front(); + } + } + SetWindowLong(hWnd, GWL_USERDATA, gdi_extra.size()); + currentFocusIx = gdi_extra.size(); + gdi_extra.push_back(gdi); + + return gdi; +} + +/** Returns the tag of the last extra window. */ +const string &getLastExtraWindow() { + if (gdi_extra.empty()) + throw meosException("Empty"); + else + return gdi_extra.back()->getTag(); +} +// +// FUNCTION: WndProc(HWND, unsigned, WORD, LONG) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +/* +void CallBack(gdioutput *gdi, int type, void *data) +{ + ButtonInfo bi=*(ButtonInfo* )data; + + string t=gdi->getText("input"); + gdi->ClearPage(); + + gdi->addButton(bi.text+" *"+t, bi.xp+5, bi.yp+30, "", CallBack); +} + +void CallBackLB(gdioutput *gdi, int type, void *data) +{ + ListBoxInfo lbi=*(ListBoxInfo* )data; + + gdi->setText("input", lbi.text); +} + +void CallBackINPUT(gdioutput *gdi, int type, void *data) +{ + InputInfo lbi=*(InputInfo* )data; + + MessageBox(NULL, "MB_OK", 0, MB_OK); + //gdi->setText("input", lbi.text); +}*/ + +void InsertSICard(gdioutput &gdi, SICard &sic); + +#define TabCtrl_InsertItemW(hwnd, iItem, pitem) \ + (int)SNDMSG((hwnd), TCM_INSERTITEMW, (WPARAM)(int)(iItem), (LPARAM)(const TC_ITEM *)(pitem)) + +//static int xPos=0, yPos=0; +void createTabs(bool force, bool onlyMain, bool skipTeam, bool skipSpeaker, + bool skipEconomy, bool skipLists, bool skipRunners, bool skipControls) +{ + static bool onlyMainP = false; + static bool skipTeamP = false; + static bool skipSpeakerP = false; + static bool skipEconomyP = false; + static bool skipListsP = false; + static bool skipRunnersP = false; + static bool skipControlsP = false; + + if (!force && onlyMain==onlyMainP && skipTeam==skipTeamP && skipSpeaker==skipSpeakerP && + skipEconomy==skipEconomyP && skipLists==skipListsP && + skipRunners==skipRunnersP && skipControls==skipControlsP) + return; + + onlyMainP = onlyMain; + skipTeamP = skipTeam; + skipSpeakerP = skipSpeaker; + skipEconomyP = skipEconomy; + skipListsP = skipLists; + skipRunnersP = skipRunners; + skipControlsP = skipControls; + + int oldid=TabCtrl_GetCurSel(hMainTab); + TabObject *to = 0; + for (list::iterator it=tabList->begin();it!=tabList->end();++it) { + if (it->id==oldid) { + to = &*it; + } + } + + SendMessage(hMainTab, WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0); + int id=0; + TabCtrl_DeleteAllItems(hMainTab); + for (list::iterator it=tabList->begin();it!=tabList->end();++it) { + it->setId(-1); + + if (onlyMain && it->getType() != typeid(TabCompetition) && it->getType() != typeid(TabSI)) + continue; + + if (skipTeam && it->getType() == typeid(TabTeam)) + continue; + + if (skipSpeaker && it->getType() == typeid(TabSpeaker)) + continue; + + if (skipEconomy && it->getType() == typeid(TabClub)) + continue; + + if (skipRunners && it->getType() == typeid(TabRunner)) + continue; + + if (skipControls && it->getType() == typeid(TabControl)) + continue; + + if (skipLists && (it->getType() == typeid(TabList) || it->getType() == typeid(TabAuto))) + continue; + + TCITEMW ti; + //char bf[256]; + //strcpy_s(bf, lang.tl(it->name).c_str()); + ti.pszText=(LPWSTR)gdi_main->toWide(lang.tl(it->name)).c_str(); + ti.mask=TCIF_TEXT; + it->setId(id++); + + TabCtrl_InsertItemW(hMainTab, it->id, &ti); + } + + if (to && (to->id)>=0) + TabCtrl_SetCurSel(hMainTab, to->id); +} + +void hideTabs() +{ + TabCtrl_DeleteAllItems(hMainTab); +} + + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + + switch (message) + { + case WM_CREATE: + + tabList->push_back(TabObject(gdi_main->getTabs().get(TCmpTab), "Tävling")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TRunnerTab), "Deltagare")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TTeamTab), "Lag(flera)")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TListTab), "Listor")); + { + TabAuto *ta = (TabAuto *)gdi_main->getTabs().get(TAutoTab); + tabList->push_back(TabObject(ta, "Automater")); + tabAutoRegister(ta); + } + tabList->push_back(TabObject(gdi_main->getTabs().get(TSpeakerTab), "Speaker")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TClassTab), "Klasser")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TCourseTab), "Banor")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TControlTab), "Kontroller")); + tabList->push_back(TabObject(gdi_main->getTabs().get(TClubTab), "Klubbar")); + + tabList->push_back(TabObject(gdi_main->getTabs().get(TSITab), "SportIdent")); + + INITCOMMONCONTROLSEX ic; + + ic.dwSize=sizeof(ic); + ic.dwICC=ICC_TAB_CLASSES ; + InitCommonControlsEx(&ic); + hMainTab=CreateWindowEx(0, WC_TABCONTROL, "tabs", WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 300, 20, hWnd, 0, hInst, 0); + createTabs(true, true, false, false, false, false, false, false); + + SetTimer(hWnd, 4, 10000, 0); //Connection check + break; + + case WM_MOUSEWHEEL: { + int dz = GET_WHEEL_DELTA_WPARAM(wParam); + scrollVertical(gdi_main, -dz, hWndWorkspace); + } + break; + + case WM_SIZE: + MoveWindow(hMainTab, 0,0, LOWORD(lParam), 30, 1); + MoveWindow(hWndWorkspace, 0, 30, LOWORD(lParam), HIWORD(lParam)-30, 1); + + RECT rc; + GetClientRect(hWndWorkspace, &rc); + PostMessage(hWndWorkspace, WM_SIZE, wParam, MAKELONG(rc.right, rc.bottom)); + break; + + case WM_WINDOWPOSCHANGED: + if (gEvent) { + LPWINDOWPOS wp = (LPWINDOWPOS) lParam; // points to size and position data + + if (wp->x>=0 && wp->y>=0 && wp->cx>300 && wp->cy>200) { + gEvent->setProperty("xpos", wp->x); + gEvent->setProperty("ypos", wp->y); + gEvent->setProperty("xsize", wp->cx); + gEvent->setProperty("ysize", wp->cy); + } + else { + Sleep(0); + } + } + return DefWindowProc(hWnd, message, wParam, lParam); + case WM_TIMER: + + if (!gdi_main) return 0; + + if (wParam==1) { + if (autoTask) + autoTask->autoSave(); + } + else if (wParam==2) { + // Interface timeouts (no synch) + if (autoTask) + autoTask->interfaceTimeout(gdi_extra); + } + else if (wParam==3) { + if (autoTask) + autoTask->synchronize(gdi_extra); + } + else if (wParam==4) { + // Verify database link + if (gEvent) + gEvent->verifyConnection(); + //OutputDebugString("Verify link\n"); + //Sleep(0); + if (gdi_main) { + if (gEvent->hasClientChanged()) { + gdi_main->makeEvent("Connections", "verify_connection", 0, 0, false); + gEvent->validateClients(); + } + } + } + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_INACTIVE) + currentFocusIx = 0; + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_NCACTIVATE: + if (gdi_main && gdi_main->hasToolbar()) + gdi_main->activateToolbar(wParam != 0); + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_NOTIFY: + { + LPNMHDR pnmh = (LPNMHDR) lParam; + + if (pnmh->hwndFrom==hMainTab && gdi_main && gEvent) + { + if (pnmh->code==TCN_SELCHANGE) + { + int id=TabCtrl_GetCurSel(hMainTab); + + for (list::iterator it=tabList->begin();it!=tabList->end();++it) { + if (it->id==id) { + try { + gdi_main->setWaitCursor(true); + string cmd = "showTab("+ string(it->getTab().getTypeStr()) + "); //" + it->name; + it->loadPage(*gdi_main); + gdi_main->getRecorder().record(cmd); + } + catch(std::exception &ex) { + gdi_main->alert(ex.what()); + } + gdi_main->setWaitCursor(false); + } + } + } + else if (pnmh->code==TCN_SELCHANGING) { + if (gdi_main == 0) { + MessageBeep(-1); + return true; + } + else { + if (!gdi_main->canClear()) + return true; + + return false; + } + } + } + break; + } + + case WM_USER: + //The card has been read and posted to a synchronized + //queue by different thread. Read and process this card. + { + SICard sic; + while (gSI && gSI->GetCard(sic)) + InsertSICard(*gdi_main, sic); + break; + } + case WM_USER+1: + MessageBox(hWnd, "Kommunikationen med en SI-enhet avbröts.", "SportIdent", MB_OK); + break; + + case WM_USER + 3: + //OutputDebugString("Get punch from queue\n"); + if (autoTask) + autoTask->advancePunchInformation(gdi_extra); + break; + + case WM_USER + 4: + if (autoTask) + autoTask->synchronize(gdi_extra); + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) { + case IDM_EXIT: + //DestroyWindow(hWnd); + PostMessage(hWnd, WM_CLOSE, 0,0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code here... + + + EndPaint(hWnd, &ps); + break; + + case WM_CLOSE: + if (!gEvent || gEvent->empty() || gdi_main->ask("Vill du verkligen stänga MeOS?")) + DestroyWindow(hWnd); + break; + + case WM_DESTROY: + delete gSI; + gSI=0; + + if (gEvent) { + try { + gEvent->save(); + } + catch(std::exception &ex) { + MessageBox(hWnd, lang.tl(ex.what()).c_str(), "Fel när tävlingen skulle sparas", MB_OK); + } + + try { + gEvent->saveRunnerDatabase("database", true); + } + catch(std::exception &ex) { + MessageBox(hWnd, lang.tl(ex.what()).c_str(), "Fel när löpardatabas skulle sparas", MB_OK); + } + + if (gEvent) + gEvent->saveProperties(settings); + + delete gEvent; + gEvent=0; + } + + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +void scrollVertical(gdioutput *gdi, int yInc, HWND hWnd) { + SCROLLINFO si; + si.cbSize=sizeof(si); + si.fMask=SIF_ALL; + GetScrollInfo(hWnd, SB_VERT, &si); + if (si.nPage==0) + yInc = 0; + + int yPos=gdi->GetOffsetY(); + int a=si.nMax-signed(si.nPage-1) - yPos; + + if ( (yInc = max( -yPos, min(yInc, a)))!=0 ) { + yPos += yInc; + RECT ScrollArea, ClipArea; + GetClientRect(hWnd, &ScrollArea); + ClipArea=ScrollArea; + + ScrollArea.top=-gdi->getHeight()-100; + ScrollArea.bottom+=gdi->getHeight(); + ScrollArea.right=gdi->getWidth()-gdi->GetOffsetX()+15; + ScrollArea.left = -2000; + gdi->SetOffsetY(yPos); + + bool inv = true; //Inv = false works only for lists etc. where there are not controls in the scroll area. + + RECT invalidArea; + ScrollWindowEx (hWnd, 0, -yInc, + &ScrollArea, &ClipArea, + (HRGN) NULL, &invalidArea, SW_SCROLLCHILDREN | (inv ? SW_INVALIDATE : 0)); + + // gdi->UpdateObjectPositions(); + + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = yPos; + + SetScrollInfo(hWnd, SB_VERT, &si, TRUE); + + if (inv) + UpdateWindow(hWnd); + else { + HDC hDC = GetDC(hWnd); + IntersectClipRect(hDC, invalidArea.left, invalidArea.top, invalidArea.right, invalidArea.bottom); + gdi->draw(hDC, ScrollArea, invalidArea); + ReleaseDC(hWnd, hDC); + } + } +} + +void updateScrollInfo(HWND hWnd, gdioutput &gdi, int nHeight, int nWidth) { + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_RANGE; + + int maxx, maxy; + gdi.clipOffset(nWidth, nHeight, maxx, maxy); + + si.nMin=0; + + if (maxy>0) { + si.nMax=maxy+nHeight; + si.nPos=gdi.GetOffsetY(); + si.nPage=nHeight; + } + else { + si.nMax=0; + si.nPos=0; + si.nPage=0; + } + SetScrollInfo(hWnd, SB_VERT, &si, true); + + si.nMin=0; + if (maxx>0) { + si.nMax=maxx+nWidth; + si.nPos=gdi.GetOffsetX(); + si.nPage=nWidth; + } + else { + si.nMax=0; + si.nPos=0; + si.nPage=0; + } + + SetScrollInfo(hWnd, SB_HORZ, &si, true); +} + +LRESULT CALLBACK WorkSpaceWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + + LONG ix = GetWindowLong(hWnd, GWL_USERDATA); + gdioutput *gdi = 0; + if (ix < LONG(gdi_extra.size())) + gdi = gdi_extra[ix]; + + if (gdi) { + LRESULT res = gdi->ProcessMsg(message, lParam, wParam); + if (res) + return res; + } + switch (message) + { + case WM_CREATE: + break; + + case WM_SIZE: + //SCROLLINFO si; + //si.cbSize=sizeof(si); + //si.fMask=SIF_PAGE|SIF_RANGE; + + int nHeight; + nHeight = HIWORD(lParam); + int nWidth; + nWidth = LOWORD(lParam); + updateScrollInfo(hWnd, *gdi, nHeight, nWidth); + /* + + int maxx, maxy; + gdi->clipOffset(nWidth, nHeight, maxx, maxy); + + si.nMin=0; + + if (maxy>0) { + si.nMax=maxy+nHeight; + si.nPos=gdi->GetOffsetY(); + si.nPage=nHeight; + } + else { + si.nMax=0; + si.nPos=0; + si.nPage=0; + } + SetScrollInfo(hWnd, SB_VERT, &si, true); + + si.nMin=0; + if (maxx>0) { + si.nMax=maxx+nWidth; + si.nPos=gdi->GetOffsetX(); + si.nPage=nWidth; + } + else { + si.nMax=0; + si.nPos=0; + si.nPage=0; + } + SetScrollInfo(hWnd, SB_HORZ, &si, true); + */ + InvalidateRect(hWnd, NULL, true); + break; + case WM_KEYDOWN: + //gdi->keyCommand(; + break; + + case WM_VSCROLL: + { + int nScrollCode = (int) LOWORD(wParam); // scroll bar value + //int hwndScrollBar = (HWND) lParam; // handle to scroll bar + + int yInc; + int yPos=gdi->GetOffsetY(); + RECT rc; + GetClientRect(hWnd, &rc); + int pagestep = max(50, int(0.9*rc.bottom)); + + switch(nScrollCode) + { + // User clicked shaft left of the scroll box. + case SB_PAGEUP: + yInc = -pagestep; + break; + + // User clicked shaft right of the scroll box. + case SB_PAGEDOWN: + yInc = pagestep; + break; + + // User clicked the left arrow. + case SB_LINEUP: + yInc = -10; + break; + + // User clicked the right arrow. + case SB_LINEDOWN: + yInc = 10; + break; + + // User dragged the scroll box. + case SB_THUMBTRACK: { + // Initialize SCROLLINFO structure + SCROLLINFO si; + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + + if (!GetScrollInfo(hWnd, SB_VERT, &si) ) + return 1; // GetScrollInfo failed + + yInc = si.nTrackPos - yPos; + break; + } + + default: + yInc = 0; + } + + scrollVertical(gdi, yInc, hWnd); + gdi->storeAutoPos(gdi->GetOffsetY()); + break; + } + + case WM_HSCROLL: + { + int nScrollCode = (int) LOWORD(wParam); // scroll bar value + //int hwndScrollBar = (HWND) lParam; // handle to scroll bar + + int xInc; + int xPos=gdi->GetOffsetX(); + + switch(nScrollCode) + { + // User clicked shaft left of the scroll box. + case SB_PAGEUP: + xInc = -80; + break; + + // User clicked shaft right of the scroll box. + case SB_PAGEDOWN: + xInc = 80; + break; + + // User clicked the left arrow. + case SB_LINEUP: + xInc = -10; + break; + + // User clicked the right arrow. + case SB_LINEDOWN: + xInc = 10; + break; + + // User dragged the scroll box. + case SB_THUMBTRACK: { + // Initialize SCROLLINFO structure + SCROLLINFO si; + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + + if (!GetScrollInfo(hWnd, SB_HORZ, &si) ) + return 1; // GetScrollInfo failed + + xInc = si.nTrackPos - xPos; + break; + } + //xInc = HIWORD(wParam) - xPos; + //break; + default: + xInc = 0; + } + + SCROLLINFO si; + si.cbSize=sizeof(si); + si.fMask=SIF_ALL; + GetScrollInfo(hWnd, SB_HORZ, &si); + + if (si.nPage==0) + xInc = 0; + + int a=si.nMax-signed(si.nPage-1) - xPos; + + if ((xInc = max( -xPos, min(xInc, a)))!=0) { + xPos += xInc; + RECT ScrollArea, ClipArea; + GetClientRect(hWnd, &ScrollArea); + ClipArea=ScrollArea; + + gdi->SetOffsetX(xPos); + + ScrollWindowEx (hWnd, -xInc, 0, + 0, &ClipArea, + (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE|SW_SCROLLCHILDREN); + + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = xPos; + + SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); + UpdateWindow (hWnd); + } + break; + } + + case WM_MOUSEWHEEL: { + int dz = GET_WHEEL_DELTA_WPARAM(wParam); + scrollVertical(gdi, -dz, hWnd); + gdi->storeAutoPos(gdi->GetOffsetY()); + } + break; + + case WM_TIMER: + if (wParam == 1001) { + double autoScroll, pos; + gdi->getAutoScroll(autoScroll, pos); + + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + + GetScrollInfo(hWnd, SB_VERT, &si); + int dir = gdi->getAutoScrollDir(); + int dy = 0; + if ((dir<0 && si.nPos <= si.nMin) || + (dir>0 && (si.nPos + int(si.nPage)) >= si.nMax)) { + autoScroll = -autoScroll; + gdi->setAutoScroll(-1); // Mirror + + double nextPos = pos + autoScroll; + dy = int(nextPos - si.nPos); + gdi->storeAutoPos(nextPos); + + //gdi->setData("AutoScroll", -int(data)); + } + else { + double nextPos = pos + autoScroll; + dy = int(nextPos - si.nPos); + gdi->storeAutoPos(nextPos); + //gdi->setData("Discrete", DWORD(nextPos*1e3)); + } + + scrollVertical(gdi, dy, hWnd); + } + else + MessageBox(hWnd, "Runtime exception", 0, MB_OK); + break; + + case WM_ACTIVATE: { + int fActive = LOWORD(wParam); + if (fActive != WA_INACTIVE) + currentFocusIx = ix; + + return DefWindowProc(hWnd, message, wParam, lParam); + } + + case WM_USER + 2: + if (gdi) + LoadPage(*gdi, TabType(wParam)); + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case 0: break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + RECT rt; + GetClientRect(hWnd, &rt); + + if (gdi && (ps.rcPaint.right|ps.rcPaint.left|ps.rcPaint.top|ps.rcPaint.bottom) != 0 ) + gdi->draw(hdc, rt, ps.rcPaint); + /*{ + HANDLE icon = LoadImage(hInst, (LPCTSTR)IDI_MEOS, IMAGE_ICON, 64, 64, LR_SHARED); + DrawIconEx(hdc, 0,0, (HICON)icon, 64, 64, 0, NULL, DI_NORMAL | DI_COMPAT); + }*/ + EndPaint(hWnd, &ps); + break; + + case WM_ERASEBKGND: + return 0; + break; + + case WM_DESTROY: + if (ix > 0) { + gdi->makeEvent("CloseWindow", "meos", 0, 0, false); + gdi_extra[ix] = 0; + delete gdi; + + while(!gdi_extra.empty() && gdi_extra.back() == 0) + gdi_extra.pop_back(); + } + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +// Message handler for about box. +LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + return FALSE; +} + + +namespace setup { +const int nFiles=7; +const char *fileList[nFiles]={"baseclass.xml", + "family.mwd", + "given.mwd", + "club.mwd", + "class.mwd", + "database.clubs", + "database.persons"}; +} + +void Setup(bool overwrite, bool overwriteAll) +{ + static bool isSetup=false; + if (isSetup && overwrite==false) + return; + isSetup=true; //Run at most once. + + vector > toInstall; + for(int k=0;k dyn; + expandDirectory(dir, "*.lxml", dyn); + expandDirectory(dir, "*.listdef", dyn); + expandDirectory(dir, "*.meos", dyn); + for (size_t k = 0; k < dyn.size(); k++) + toInstall.push_back(make_pair(dyn[k], true)); + + char bf[260]; + for(size_t k=0; k tempFiles; +static string tempPath; + +string getTempPath() { + char tempFile[MAX_PATH]; + if (tempPath.empty()) { + char path[MAX_PATH]; + GetTempPath(MAX_PATH, path); + GetTempFileName(path, "meos", 0, tempFile); + DeleteFile(tempFile); + if (CreateDirectory(tempFile, NULL)) + tempPath = tempFile; + else + throw std::exception("Failed to create temporary file."); + } + return tempPath; +} + +void registerTempFile(const string &tempFile) { + tempFiles.insert(tempFile); +} + +string getTempFile() { + getTempPath(); + + char tempFile[MAX_PATH]; + if (GetTempFileName(tempPath.c_str(), "ix", 0, tempFile)) { + tempFiles.insert(tempFile); + return tempFile; + } + else + throw std::exception("Failed to create temporary file."); +} + +void removeTempFile(const string &file) { + DeleteFile(file.c_str()); + tempFiles.erase(file); +} + +void removeTempFiles() { + vector dir; + for (set::iterator it = tempFiles.begin(); it!= tempFiles.end(); ++it) { + char c = *it->rbegin(); + if (c == '/' || c=='\\') + dir.push_back(*it); + else + DeleteFile(it->c_str()); + } + tempFiles.clear(); + bool removed = true; + while (removed) { + removed = false; + for (size_t k = 0; k +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=meos - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "meos.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "meos.mak" CFG="meos - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "meos - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "meos - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "meos - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x41d /d "NDEBUG" +# ADD RSC /l 0x41d /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 Msimg32.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "meos - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x41d /d "_DEBUG" +# ADD RSC /l 0x41d /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Msimg32.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "meos - Win32 Release" +# Name "meos - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\csvparser.cpp +# End Source File +# Begin Source File + +SOURCE=.\gdioutput.cpp +# End Source File +# Begin Source File + +SOURCE=.\meos.cpp +# End Source File +# Begin Source File + +SOURCE=.\meos.rc +# End Source File +# Begin Source File + +SOURCE=.\oBase.cpp +# End Source File +# Begin Source File + +SOURCE=.\oCard.cpp +# End Source File +# Begin Source File + +SOURCE=.\oClass.cpp +# End Source File +# Begin Source File + +SOURCE=.\oClub.cpp +# End Source File +# Begin Source File + +SOURCE=.\oControl.cpp +# End Source File +# Begin Source File + +SOURCE=.\oCourse.cpp +# End Source File +# Begin Source File + +SOURCE=.\oEvent.cpp +# End Source File +# Begin Source File + +SOURCE=.\oPunch.cpp +# End Source File +# Begin Source File + +SOURCE=.\oRunner.cpp +# End Source File +# Begin Source File + +SOURCE=.\pages.cpp +# End Source File +# Begin Source File + +SOURCE=.\pages_classes.cpp +# End Source File +# Begin Source File + +SOURCE=.\pages_competition.cpp +# End Source File +# Begin Source File + +SOURCE=.\pages_course.cpp +# End Source File +# Begin Source File + +SOURCE=.\pages_lists.cpp +# End Source File +# Begin Source File + +SOURCE=.\pages_si.cpp +# End Source File +# Begin Source File + +SOURCE=.\random.cpp +# End Source File +# Begin Source File + +SOURCE=.\SportIdent.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\TimeStamp.cpp +# End Source File +# Begin Source File + +SOURCE=.\xmlparser.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\csvparser.h +# End Source File +# Begin Source File + +SOURCE=.\gdioutput.h +# End Source File +# Begin Source File + +SOURCE=.\meos.h +# End Source File +# Begin Source File + +SOURCE=.\oBase.h +# End Source File +# Begin Source File + +SOURCE=.\oCard.h +# End Source File +# Begin Source File + +SOURCE=.\oClass.h +# End Source File +# Begin Source File + +SOURCE=.\oClub.h +# End Source File +# Begin Source File + +SOURCE=.\oControl.h +# End Source File +# Begin Source File + +SOURCE=.\oCourse.h +# End Source File +# Begin Source File + +SOURCE=.\oEvent.h +# End Source File +# Begin Source File + +SOURCE=.\oPunch.h +# End Source File +# Begin Source File + +SOURCE=.\oRunner.h +# End Source File +# Begin Source File + +SOURCE=.\random.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\SportIdent.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\TimeStamp.h +# End Source File +# Begin Source File + +SOURCE=.\xmlparser.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\meos.ico +# End Source File +# Begin Source File + +SOURCE=.\small.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project +# Section meos : {4E2984B5-19E9-4743-8ED4-A0D97FA48101} +# 2:21:DefaultSinkHeaderFile:_sicomm.h +# 2:16:DefaultSinkClass:C_SiComm +# End Section +# Section meos : {D2F56B3B-02FC-415B-843E-AFBA48C5F2B2} +# 2:5:Class:C_SiComm +# 2:10:HeaderFile:_sicomm.h +# 2:8:ImplFile:_sicomm.cpp +# End Section diff --git a/code/meos.h b/code/meos.h new file mode 100644 index 0000000..2a26408 --- /dev/null +++ b/code/meos.h @@ -0,0 +1,11 @@ +#if !defined(AFX_MEOS_H__7F8E5F23_ADD4_45AB_9626_7378FEA38D49__INCLUDED_) +#define AFX_MEOS_H__7F8E5F23_ADD4_45AB_9626_7378FEA38D49__INCLUDED_ + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "resource.h" + +#endif // !defined(AFX_MEOS_H__7F8E5F23_ADD4_45AB_9626_7378FEA38D49__INCLUDED_) diff --git a/code/meos.ico b/code/meos.ico new file mode 100644 index 0000000000000000000000000000000000000000..cb86299df9ac15b4971e42983f69e1e6c7ba5d33 GIT binary patch literal 35670 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 H2H^hyT<@?n literal 0 HcmV?d00001 diff --git a/code/meos.rc b/code/meos.rc new file mode 100644 index 0000000..803ca73 --- /dev/null +++ b/code/meos.rc @@ -0,0 +1,177 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +BMP_TEST BITMAP "bitmap1.bmp" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MEOS ICON "meos.ICO" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_MEOS MENU +BEGIN + POPUP "&Arkiv" + BEGIN + MENUITEM "&Avsluta", IDM_EXIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_MEOS ACCELERATORS +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Swedish (Sweden) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE) +LANGUAGE LANG_SWEDISH, SUBLANG_SWEDISH +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 3,1,0,1 + PRODUCTVERSION 3,1,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041d04b0" + BEGIN + VALUE "CompanyName", " " + VALUE "FileDescription", "meos" + VALUE "FileVersion", "3.3.0.1" + VALUE "InternalName", "meos" + VALUE "LegalCopyright", "Copyright © 2007-2017" + VALUE "OriginalFilename", "meos.exe" + VALUE "ProductName", " meos" + VALUE "ProductVersion", "3.4.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x41d, 1200 + END +END + +#endif // Swedish (Sweden) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/code/meos.sln b/code/meos.sln new file mode 100644 index 0000000..539e574 --- /dev/null +++ b/code/meos.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "meos", "meos.vcproj", "{B854EF2A-2BB7-4D62-B08B-96BD64B347E8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|Win64 = Debug|Win64 + Release|Win32 = Release|Win32 + Release|Win64 = Release|Win64 + test|Win32 = test|Win32 + test|Win64 = test|Win64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|Win32.ActiveCfg = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|Win32.Build.0 = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|Win64.ActiveCfg = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|Win32.ActiveCfg = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|Win32.Build.0 = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|Win64.ActiveCfg = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|Win32.ActiveCfg = test|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|Win32.Build.0 = test|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|Win64.ActiveCfg = test|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/code/meos.vcproj b/code/meos.vcproj new file mode 100644 index 0000000..eedefe6 --- /dev/null +++ b/code/meos.vcproj @@ -0,0 +1,1360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/meos.vcxproj b/code/meos.vcxproj new file mode 100644 index 0000000..4e0d46d --- /dev/null +++ b/code/meos.vcxproj @@ -0,0 +1,470 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + test + Win32 + + + + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8} + meos + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + true + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Release\ + .\Release\ + false + .\Debug\ + .\Debug\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/meos.tlb + + + + + MaxSpeed + AnySuitable + Speed + meosdb/mysql++;meosdb/mysql50;libharu;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Use + stdafx.h + .\Release/meos.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x041d + + + Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat.lib;mysqlpp.lib;libhpdf.lib;%(AdditionalDependencies) + .\Release/meos.exe + true + ./lib;%(AdditionalLibraryDirectories) + .\Release/meos.pdb + Windows + false + + + MachineX86 + true + + + true + .\Release/meos.bsc + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/meos.tlb + + + + + Disabled + meosdb/mysql++;libharu;meosdb/mysql50;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + NotSet + Use + stdafx.h + .\Debug/meos.pch + .\Debug/ + .\Debug/ + .\Debug/ + true + Level4 + true + EditAndContinue + 4996;4100;4244;4245;4702;4389;4127;4201;%(DisableSpecificWarnings) + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat.lib;mysqlpp.lib;libhpdf.lib;%(AdditionalDependencies) + .\Debug/meos.exe + true + ./lib_db;%(AdditionalLibraryDirectories) + true + .\Debug/meos.pdb + Windows + false + + + MachineX86 + + + true + .\Debug/meos.bsc + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/meos.tlb + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + stdafx.h + .\Debug/meos.pch + .\Debug/ + .\Debug/ + .\Debug/ + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies) + .\Debug/meos.exe + true + true + .\Debug/meos.pdb + Windows + false + + + MachineX86 + + + true + .\Debug/meos.bsc + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + Create + %(PreprocessorDefinitions) + Create + %(PreprocessorDefinitions) + Create + + + + + + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + \ No newline at end of file diff --git a/code/meos_util.cpp b/code/meos_util.cpp new file mode 100644 index 0000000..d49d412 --- /dev/null +++ b/code/meos_util.cpp @@ -0,0 +1,1857 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include +#include +#include "meos_util.h" +#include "localizer.h" +#include "oFreeImport.h" +#include "meosexception.h" + +StringCache globalStringCache; + +namespace MeOSUtil { + int useHourFormat = true; +} + +DWORD mainThreadId = -1; +StringCache &StringCache::getInstance() { + DWORD id = GetCurrentThreadId(); + if (mainThreadId == -1) + mainThreadId = id; + else if (mainThreadId != id) + throw std::exception("Thread access error"); + return globalStringCache; +} + +string getLocalTime() +{ + SYSTEMTIME st; + GetLocalTime(&st); + return convertSystemTime(st); +} + +string getLocalDate() +{ + SYSTEMTIME st; + GetLocalTime(&st); + return convertSystemDate(st); +} + + +int getThisYear() { + static int thisYear = 0; + if (thisYear == 0) { + SYSTEMTIME st; + GetLocalTime(&st); + thisYear = st.wYear; + } + return thisYear; +} + + +/** Extend a year from 03 -> 2003, 97 -> 1997 etc */ +int extendYear(int year) { + if (year<0) + return year; + + if (year>=100) + return year; + + int thisYear = getThisYear(); + + int cLast = thisYear%100; + + if (cLast == 0 && year == 0) + return thisYear; + + if (year > thisYear%100) + return (thisYear - cLast) - 100 + year; + else + return (thisYear - cLast) + year; +} + +string getLocalTimeFileName() +{ + SYSTEMTIME st; + GetLocalTime(&st); + + char bf[32]; + sprintf_s(bf, "%d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond); + + return bf; +} + + +string getLocalTimeOnly() +{ + SYSTEMTIME st; + GetLocalTime(&st); + return convertSystemTimeOnly(st); +} + + +int getRelativeDay() { + SYSTEMTIME st; + GetLocalTime(&st); + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + + ULARGE_INTEGER u; + u.HighPart = ft.dwHighDateTime; + u.LowPart = ft.dwLowDateTime; + __int64 qp = u.QuadPart; + qp /= __int64(10) * 1000 * 1000 * 3600 * 24; + qp -= 400*365; + return int(qp); +} + +__int64 SystemTimeToInt64Second(const SYSTEMTIME &st) { + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + + ULARGE_INTEGER u; + u.HighPart = ft.dwHighDateTime; + u.LowPart = ft.dwLowDateTime; + __int64 qp = u.QuadPart; + qp /= __int64(10) * 1000 * 1000; + return qp; +} + +SYSTEMTIME Int64SecondToSystemTime(__int64 time) { + SYSTEMTIME st; + FILETIME ft; + + ULARGE_INTEGER u; + u.QuadPart = time * __int64(10) * 1000 * 1000; + ft.dwHighDateTime = u.HighPart; + ft.dwLowDateTime = u.LowPart; + + FileTimeToSystemTime(&ft, &st); + + return st; +} +//2014-11-03 07:02:00 +string convertSystemTime(const SYSTEMTIME &st) +{ + char bf[32]; + sprintf_s(bf, "%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond); + + return bf; +} + + +string convertSystemTimeOnly(const SYSTEMTIME &st) +{ + char bf[32]; + sprintf_s(bf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); + + return bf; +} + + +string convertSystemDate(const SYSTEMTIME &st) +{ + char bf[32]; + sprintf_s(bf, "%d-%02d-%02d", st.wYear, st.wMonth, st.wDay); + + return bf; +} + +string formatDate(int m, bool useIsoFormat) { + char bf[24]; + if (m > 0 && m < 30000101) { + sprintf_s(bf, 24, "%d-%02d-%02d", m/(100*100), (m/100)%100, m%100); + } + else { + bf[0] = '-'; + bf[1] = 0; + } + return bf; +} + +//Absolute time string to SYSTEM TIME +int convertDateYMS(const string &m, SYSTEMTIME &st, bool checkValid) { + memset(&st, 0, sizeof(st)); + + if (m.length()==0) + return -1; + + int len=m.length(); + for (int k=0;k='0' && b<='9')) ) + return -1; + } + + int year=atoi(m.c_str()); + if (year<1900 || year>3000) + return -1; + + int month=0; + int day=0; + int kp=m.find_first_of('-'); + + if (kp!=string::npos) { + string mtext=m.substr(kp+1); + month=atoi(mtext.c_str()); + + if (month<1 || month>12) { + if (checkValid) + return -1; + month = 1; + } + + kp=mtext.find_last_of('-'); + + if (kp!=string::npos) { + day=atoi(mtext.substr(kp+1).c_str()); + if (day<1 || day>31) { + if (checkValid) + return -1; + day = 1; + } + } + } + st.wYear = year; + st.wMonth = month; + st.wDay = day; + + + int t = year*100*100+month*100+day; + if (t<0) return -1; + + return t; +} + +//Absolute time string to absolute time int +int convertDateYMS(const string &m, bool checkValid) +{ + SYSTEMTIME st; + return convertDateYMS(m, st, checkValid); +} + + +bool myIsSpace(BYTE b) { + return isspace(b) || BYTE(b)==BYTE(160); +} + +//Absolute time string to absolute time int +int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) { + int len = m.length(); + + if (len==0 || m[0]=='-') + return -1; + + // Support for notation 2D 14:30:00 or 2T14:30:00 for several days + int tix = -1; + for (size_t k = 0; k < m.length(); k++) { + int c = m[k]; + if (c =='D' || c =='d' || c =='T' || c =='t') { + tix = k; + break; + } + } + if (tix != -1) { + if (daysZeroTime < 0) + return -1; // Not supported + int tpart = convertAbsoluteTimeHMS(m.substr(tix+1), -1); + if (tpart != -1) { + int days = atoi(m.c_str()); + if (days <= 0) + return -1; + if (tpart < daysZeroTime) + days--; + return days * 3600 * 24 + tpart; + } + return -1; + } + + int plusIndex = -1; + for (int k=0;k='0' && b<='9')) ) { + if (b=='+' && plusIndex ==-1 && k>0) + plusIndex = k; + else + return -1; + } + } + + if (plusIndex>0) { + int t = convertAbsoluteTimeHMS(m.substr(plusIndex+1), -1); + int d = atoi(m.c_str()); + + if (d>0 && t>=0) + return d*24*3600 + t; + else + return -1; + } + + int hour=atoi(m.c_str()); + + if (hour<0 || hour>23) + return -1; + + int minute=0; + int second=0; + int kp=m.find_first_of(':'); + + if (kp!=string::npos) { + string mtext=m.substr(kp+1); + minute=atoi(mtext.c_str()); + + if (minute<0 || minute>60) + minute=0; + + kp=mtext.find_last_of(':'); + + if (kp!=string::npos) { + second=atoi(mtext.substr(kp+1).c_str()); + if (second<0 || second>60) + second=0; + } + } + int t=hour*3600+minute*60+second; + if (t<0) return 0; + + return t; +} + + +//Absolute time string to absolute time int +int convertAbsoluteTimeISO(const string &m) +{ + int len = m.length(); + + if (len==0 || m[0]=='-') + return -1; + + string hStr, mStr, sStr; + + string tmp = trim(m); + + if (tmp.length() < 3) + return -1; + + hStr = tmp.substr(0, 2); + if (!(tmp[2] >= '0' && tmp[2]<='9')) + tmp = tmp.substr(3); + else + tmp = tmp.substr(2); + + if (tmp.length() < 3) + return -1; + + mStr = tmp.substr(0, 2); + + if (!(tmp[2] >= '0' && tmp[2]<='9')) + tmp = tmp.substr(3); + else + tmp = tmp.substr(2); + + if (tmp.length() < 2) + return -1; + + sStr = tmp.substr(0, 2); + + int hour = atoi(hStr.c_str()); + if (hour<0 || hour>23) + return -1; + + int minute = atoi(mStr.c_str()); + + if (minute<0 || minute>60) + return -1; + + int second = atoi(sStr.c_str()); + + if (second<0 || second>60) + return -1; + + int t = hour*3600 + minute*60 + second; + + return t; +} + + +// Parse +-MM:SS or +-HH:MM:SS +int convertAbsoluteTimeMS(const string &m) +{ + if (m.length()==0) + return NOTIME; + + int minute=0; + int second=0; + + int signpos=m.find_first_of('-'); + string mtext; + + int sign=1; + + if (signpos!=string::npos) { + sign=-1; + mtext=m.substr(signpos+1); + } + else + mtext=m; + + minute=atoi(mtext.c_str()); + + if (minute<0 || minute>60*24) + minute=0; + + int kp=mtext.find_first_of(':'); + + if (kp!=string::npos) { + mtext = mtext.substr(kp+1); + second = atoi(mtext.c_str()); + if (second<0 || second>60) + second=0; + } + + int t=minute*60+second; + + kp=mtext.find_first_of(':'); + if (kp!=string::npos) { + //Allow also for format +-HH:MM:SS + mtext = mtext.substr(kp+1); + second=atoi(mtext.c_str()); + if (second<0 || second>60) + second=0; + else + t = t*60 + second; + } + return sign*t; +} + +//Generate +-MM:SS or +-HH:MM:SS +const string &getTimeMS(int m) { + char bf[32]; + int am = abs(m); + if (am < 3600 || !MeOSUtil::useHourFormat) + sprintf_s(bf, "-%02d:%02d", am/60, am%60); + else if (am < 3600*48) + sprintf_s(bf, "-%02d:%02d:%02d", am/3600, (am/60)%60, am%60); + else { + m = 0; + bf[0] = BYTE(0x96); + bf[1] = 0; + } + string &res = StringCache::getInstance().get(); + if (m<0) + res = bf; // with minus + else + res = bf + 1; + + return res; +} + +const string &formatTime(int rt) { + string &res = StringCache::getInstance().get(); + if (rt>0 && rt<3600*999) { + char bf[16]; + if (rt>=3600 && MeOSUtil::useHourFormat) + sprintf_s(bf, 16, "%d:%02d:%02d", rt/3600,(rt/60)%60, rt%60); + else + sprintf_s(bf, 16, "%d:%02d", (rt/60), rt%60); + + res = bf; + return res; + } + char ret[2] = {BYTE(0x96), 0}; + res = ret; + return res; +} + +const string &formatTimeHMS(int rt) { + + string &res = StringCache::getInstance().get(); + if (rt>=0) { + char bf[32]; + sprintf_s(bf, 16, "%02d:%02d:%02d", rt/3600,(rt/60)%60, rt%60); + + res = bf; + return res; + } + char ret[2] = {BYTE(0x96), 0}; + res = ret; + return res; +} + +string formatTimeIOF(int rt, int zeroTime) +{ + if (rt>0 && rt<(3600*48)) { + rt+=zeroTime; + char bf[16]; + sprintf_s(bf, 16, "%02d:%02d:%02d", rt/3600,(rt/60)%60, rt%60); + + return bf; + } + return "--:--:--"; +} + +size_t find(const string &str, const string &separator, size_t startpos) +{ + size_t seplen = separator.length(); + + for (size_t m = startpos; m & split(const string &line, const string &separators, vector &split_vector) { + split_vector.clear(); + + if (line.empty()) + return split_vector; + + size_t startpos=0; + size_t nextp=find(line, separators, startpos); + split_vector.push_back(line.substr(startpos, nextp-startpos)); + + while(nextp!=line.npos) { + startpos=nextp+1; + nextp=find(line, separators, startpos); + split_vector.push_back(line.substr(startpos, nextp-startpos)); + } + + return split_vector; +} + +const string &unsplit(const vector &split_vector, const string &separators, string &line) { + size_t s = split_vector.size() * separators.size(); + for (size_t k = 0; k < split_vector.size(); k++) { + s += split_vector[k].size(); + } + + line.clear(); + line.reserve(s); + for (size_t k = 0; k < split_vector.size(); k++) { + if (k != 0) + line += separators; + line += split_vector[k]; + } + return line; +} + + +const string &MakeDash(const string &t) { + return MakeDash(t.c_str()); +} + +const string &MakeDash(const char *t) { + string &out = StringCache::getInstance().get(); + out = t; + for (size_t i=0;i=0 && (isspace(BYTE(ptr[k])) || BYTE(ptr[i])==BYTE(160))) k--; + + if (i == 0 && k == len-1) + return s; + else if (k>=i && i') | (bf[k]=='<') | (bf[k]=='"') | (bf[k]==0) | (bf[k]=='\n') | (bf[k]=='\r'); + + if (!needEncode) + return in; + out.clear(); + for (int k=0;k') + out+=">"; + else if (bf[k]=='"') + out+="""; + else if (bf[k]=='\n') + out+=" "; + else if (bf[k]=='\r') + out+=" "; + else if (bf[k] == 0) + out+=' '; + else + out+=bf[k]; + } + return out; +} + +const string &decodeXML(const string &in) +{ + const char *bf = in.c_str(); + int len = in.length(); + bool needDecode = false; + for (int k=0;k', k+=3; + else if ( memcmp(&bf[k], """, 6)==0 ) + str << '\"', k+=5; + else if ( memcmp(&bf[k], " ", 6)==0 ) + str << ' ', k+=5; + else if ( memcmp(&bf[k], " ", 5)==0 ) + str << '\n', k+=4; + else if ( memcmp(&bf[k], " ", 5)==0 ) + str << '\r', k+=4; + else + str << bf[k]; + } + else + str << bf[k]; + } + out = str.str(); + } + return out; +} + +void inplaceDecodeXML(char *in) +{ + char *bf = in; + int outp = 0; + + for (int k=0;bf[k] ;k++) { + if (bf[k] != '&') + bf[outp++] = bf[k]; + else { + if ( memcmp(&bf[k], "&", 5)==0 ) + bf[outp++] = '&', k+=4; + else if ( memcmp(&bf[k], "<", 4)==0 ) + bf[outp++] = '<', k+=3; + else if ( memcmp(&bf[k], ">", 4)==0 ) + bf[outp++] = '>', k+=3; + else if ( memcmp(&bf[k], """, 6)==0 ) + bf[outp++] = '"', k+=5; + else if ( memcmp(&bf[k], " ", 5)==0 ) + bf[outp++] = '\n', k+=4; + else if ( memcmp(&bf[k], " ", 5)==0 ) + bf[outp++] = '\r', k+=4; + else + bf[outp++] = bf[k]; + } + } + bf[outp] = 0; +} + +const char *decodeXML(const char *in) +{ + const char *bf = in; + bool needDecode = false; + for (int k=0; bf[k] ;k++) + needDecode |= (bf[k]=='&'); + + if (!needDecode) + return in; + + static string out; + out.clear(); + for (int k=0;bf[k] ;k++) { + if (bf[k]=='&') { + if ( memcmp(&bf[k], "&", 5)==0 ) + out+="&", k+=4; + else if ( memcmp(&bf[k], "<", 4)==0 ) + out+="<", k+=3; + else if ( memcmp(&bf[k], ">", 4)==0 ) + out+=">", k+=3; + else if ( memcmp(&bf[k], """, 6)==0 ) + out+="\"", k+=5; + else if ( memcmp(&bf[k], " ", 5)==0 ) + out+="\n", k+=4; + else if ( memcmp(&bf[k], " ", 5)==0 ) + out+="\r", k+=4; + else + out+=bf[k]; + } + else + out+=bf[k]; + } + + return out.c_str(); +} + +void static setChar(unsigned char *map, unsigned char pos, unsigned char value) +{ + map[pos] = value; +} + +int toLowerStripped(int c) { + const unsigned cc = c&0xFF; + if (cc>='A' && cc<='Z') + return cc + ('a' - 'A'); + else if (cc<128) + return cc; + + static unsigned char map[256] = {0, 0}; + if (map[1] == 0) { + for (unsigned i = 0; i < 256; i++) + map[i] = unsigned char(i); + + setChar(map, 'Å', 'å'); + setChar(map, 'Ä', 'ä'); + setChar(map, 'Ö', 'ö'); + + setChar(map, 'É', 'e'); + setChar(map, 'é', 'e'); + setChar(map, 'è', 'e'); + setChar(map, 'È', 'e'); + setChar(map, 'ë', 'e'); + setChar(map, 'Ë', 'e'); + setChar(map, 'ê', 'e'); + setChar(map, 'Ê', 'e'); + + setChar(map, 'û', 'u'); + setChar(map, 'Û', 'u'); + setChar(map, 'ü', 'u'); + setChar(map, 'Ü', 'u'); + setChar(map, 'ú', 'u'); + setChar(map, 'Ú', 'u'); + setChar(map, 'ù', 'u'); + setChar(map, 'Ù', 'u'); + + setChar(map, 'ñ', 'n'); + setChar(map, 'Ñ', 'n'); + + setChar(map, 'á', 'a'); + setChar(map, 'Á', 'a'); + setChar(map, 'à', 'a'); + setChar(map, 'À', 'a'); + setChar(map, 'â', 'a'); + setChar(map, 'Â', 'a'); + setChar(map, 'ã', 'a'); + setChar(map, 'Ã', 'a'); + + setChar(map, 'ï', 'i'); + setChar(map, 'Ï', 'i'); + setChar(map, 'î', 'i'); + setChar(map, 'Î', 'i'); + setChar(map, 'í', 'i'); + setChar(map, 'Í', 'i'); + setChar(map, 'ì', 'i'); + setChar(map, 'Ì', 'i'); + + setChar(map, 'ó', 'o'); + setChar(map, 'Ó', 'o'); + setChar(map, 'ò', 'o'); + setChar(map, 'Ò', 'o'); + setChar(map, 'õ', 'o'); + setChar(map, 'Õ', 'o'); + setChar(map, 'ô', 'o'); + setChar(map, 'Ô', 'o'); + + setChar(map, 'ý', 'y'); + setChar(map, 'Ý', 'Y'); + setChar(map, 'ÿ', 'y'); + + setChar(map, 'Æ', 'ä'); + setChar(map, 'æ', 'ä'); + + setChar(map, 'Ø', 'ö'); + setChar(map, 'ø', 'ö'); + + setChar(map, 'Ç', 'c'); + setChar(map, 'ç', 'c'); + } + int a = map[cc]; + return a; +} + +const char *canonizeName(const char *name) +{ + static char out[70]; + static char tbf[70]; + + for (int i = 0; i<63 && name[i]; i++) { + if (name[i] == ',') { + int tout = 0; + for (int j = i+1; j < 63 && name[j]; j++) { + tbf[tout++] = name[j]; + } + tbf[tout++] = ' '; + for (int j = 0; j < i; j++) { + tbf[tout++] = name[j]; + } + tbf[tout] = 0; + name = tbf; + break; + } + } + + int outp = 0; + int k = 0; + for (k=0; k<63 && name[k]; k++) { + if (name[k] != ' ') + break; + } + + bool first = true; + while (k<63 && name[k]) { + if (!first) + out[outp++] = ' '; + + while(name[k]!= ' ' && k<63 && name[k]) { + if (name[k] == '-') + out[outp++] = ' '; + else + out[outp++] = toLowerStripped(name[k]); + k++; + } + + first = false; + while(name[k] == ' ' && k<64) + k++; + } + + out[outp] = 0; + return out; +} + +const int notFound = 1000000; + +int charDist(const char *b, int len, int origin, char c) +{ + int i; + int bound = max(1, min(len/2, 4)); + for (int k = 0;k0 && b[i] == c) + return -k; + i = origin + k; + if (imin(3, max(1, al/3))) + return 1; + + double mfactor = double(missing*0.8); + double center = double(avg)/double(ndiff); + + double dist = 0; + for (int k=0; k(fabs(d1[k] - center), abs(d1[k])); + dist += ld*ld; + } + + + return (sqrt(dist)+mfactor*mfactor)/double(al); +} + +double stringDistance(const char *a, const char *b) +{ + int al = strlen(a); + int bl = strlen(b); + + double d1 = stringDistance(a, al, b, bl); + if (d1 >= 1) + return 1.0; + + double d2 = stringDistance(b, bl, a, al); + if (d2 >= 1) + return 1.0; + + return (max(d1, d2) + d1 + d2)/3.0; +} + +int getNumberSuffix(const string &str) +{ + int pos = str.length(); + + while (pos>1 && (str[pos-1] & (~127)) == 0 && (isspace(str[pos-1]) || isdigit(str[pos-1]))) { + pos--; + } + + if (pos == str.length()) + return 0; + return atoi(str.c_str() + pos); +} + +int extractAnyNumber(const string &str, string &prefix, string &suffix) +{ + const unsigned char *ptr = (const unsigned char*)str.c_str(); + for (size_t k = 0; k &dec) { + if (name.empty()) + return; + + dec.push_back(string()); + + for (size_t i = 0; i < name.size(); i++) { + int bchar = toLowerStripped(name[i]); + if (isspace(bchar) || bchar == '-' || bchar == 160) { + if (!dec.back().empty()) + dec.push_back(string()); + continue; + } + if (!dec.back().empty()) { + int last = *dec.back().rbegin(); + bool lastNum = last >= '0' && last <= '9'; + bool isNum = bchar >= '0' && bchar <= '9'; + + if (lastNum^isNum) + dec.push_back(string()); // Change num/ non-num + } + dec.back().push_back(bchar); + } + if (dec.back().empty()) + dec.pop_back(); + + sort(dec.begin(), dec.end()); +} + +/** Matches H21 L with H21 Lång and H21L + but not Violet with Violet Court, which is obviously wrong. + */ +bool compareClassName(const string &a, const string &b) +{ + if (a == b) + return true; + + vector acanon; + vector bcanon; + + decompseClassName(a, acanon); + decompseClassName(b, bcanon); + + if (acanon.size() != bcanon.size()) + return false; + + for (size_t k = 0; k < acanon.size(); k++) { + if (acanon[k] == bcanon[k]) + continue; + + int sample = acanon[k][0]; + if (sample >= '0' && sample <= '9') + return false; // Numbers must match + + if (acanon[k][0] == bcanon[k][0] && (acanon[k].length() == 1 || bcanon[k].length() == 1)) + continue; // Abbrevation W <-> Women etc + + return false; // No match + } + + return true; // All parts matched +} + +string getErrorMessage(int code) { + LPVOID msg; + int s = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &msg, 0, NULL); + if (s==0 || !msg) { + if (code != 0) { + char ch[128]; + sprintf_s(ch, "Error code: %d", code); + return ch; + } + return ""; + } + + string str = LPCTSTR(msg); + if (str.empty() && code>0) { + char ch[128]; + sprintf_s(ch, "Error code: %d", code); + str = ch; + } + + LocalFree(msg); + return str; +} + +#define HLSMAX 252 /* H,L, and S vary over 0-HLSMAX */ +#define RGBMAX 255 /* R,G, and B vary over 0-RGBMAX */ + /* HLSMAX BEST IF DIVISIBLE BY 6 */ + /* RGBMAX, HLSMAX must each fit in a byte. */ + +/* Hue is undefined if Saturation is 0 (grey-scale) */ +#define UNDEFINED (HLSMAX*2/3) + +HLS &HLS::RGBtoHLS(DWORD lRGBColor) +{ + WORD R,G,B; /* input RGB values */ + BYTE cMax,cMin; /* max and min RGB values */ + WORD Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max + */ + /* get R, G, and B out of DWORD */ + R = GetRValue(lRGBColor); + G = GetGValue(lRGBColor); + B = GetBValue(lRGBColor); + WORD &L = lightness; + WORD &H = hue; + WORD &S = saturation; + + /* calculate lightness */ + cMax = (BYTE)max( max(R,G), B); + cMin = (BYTE)min( min(R,G), B); + L = ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX); + + if (cMax == cMin) { /* r=g=b --> achromatic case */ + S = 0; /* saturation */ + H = UNDEFINED; /* hue */ + } + else { /* chromatic case */ + /* saturation */ + if (L <= (HLSMAX/2)) + S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin); + else + S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) ) + / (2*RGBMAX-cMax-cMin); + + /* hue */ + Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin); + Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin); + Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin); + + if (R == cMax) + H = Bdelta - Gdelta; + else if (G == cMax) + H = (HLSMAX/3) + Rdelta - Bdelta; + else /* B == cMax */ + H = ((2*HLSMAX)/3) + Gdelta - Rdelta; + + if (H < 0) + H += HLSMAX; + if (H > HLSMAX) + H -= HLSMAX; + } + return *this; +} + + +/* utility routine for HLStoRGB */ +WORD HLS::HueToRGB(WORD n1, WORD n2, WORD hue) const +{ + /* range check: note values passed add/subtract thirds of range */ + if (hue < 0) + hue += HLSMAX; + + if (hue > HLSMAX) + hue -= HLSMAX; + + /* return r,g, or b value from this tridrant */ + if (hue < (HLSMAX/6)) + return ( n1 + (((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) ); + if (hue < (HLSMAX/2)) + return ( n2 ); + if (hue < ((HLSMAX*2)/3)) + return ( n1 + (((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6)) + ); + else + return ( n1 ); +} + +DWORD HLS::HLStoRGB() const +{ + const WORD &lum = lightness; + const WORD &sat = saturation; + + WORD R,G,B; /* RGB component values */ + WORD Magic1,Magic2; /* calculated magic numbers (really!) */ + + if (sat == 0) { /* achromatic case */ + R=G=B=(lum*RGBMAX)/HLSMAX; + if (hue != UNDEFINED) { + /* ERROR */ + } + } + else { /* chromatic case */ + /* set up magic numbers */ + if (lum <= (HLSMAX/2)) + Magic2 = (lum*(HLSMAX + sat) + (HLSMAX/2))/HLSMAX; + else + Magic2 = lum + sat - ((lum*sat) + (HLSMAX/2))/HLSMAX; + Magic1 = 2*lum-Magic2; + + /* get RGB, change units from HLSMAX to RGBMAX */ + R = (HueToRGB(Magic1,Magic2,hue+(HLSMAX/3))*RGBMAX + + (HLSMAX/2))/HLSMAX; + G = (HueToRGB(Magic1,Magic2,hue)*RGBMAX + (HLSMAX/2)) / HLSMAX; + B = (HueToRGB(Magic1,Magic2,hue-(HLSMAX/3))*RGBMAX + + (HLSMAX/2))/HLSMAX; + } + return(RGB(R,G,B)); +} + +void HLS::lighten(double f) { + lightness = min(HLSMAX, WORD(f*lightness)); +} + +void HLS::saturate(double s) { + saturation = min(HLSMAX, WORD(s*saturation)); +} + +void HLS::colorDegree(double d) { + +} + +bool isAscii(const string &s) { + for (size_t k = 0; k 0; +} + +int convertDynamicBase(const string &s, long long &out) { + out = 0; + if (s.empty()) + return 0; + + bool alpha = false; + bool general = false; + int len = s.length(); + for (int k = 0; k < len; k++) { + unsigned c = s[k]; + if (c >= '0' && c <= '9') + continue; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + alpha = true; + continue; + } + general = true; + if (c<32) + return 0; // Not a supported character + } + + int base = general ? 256-32 : (alpha ? 36 : 10); + long long factor = 1; + for (int k = len-1; k >= 0; k--) { + unsigned c = s[k]&0xFF; + if (general) + c -= 32; + else { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A'-10; + else if (c >= 'a' && c <= 'z') + c -= 'a'-10; + } + out += factor * c; + factor *= base; + } + + return base; +} + +void convertDynamicBase(long long val, int base, char out[16]) { + int len = 0; + while (val != 0) { + unsigned int c = val % base; + val = val / base; + char cc; + if (base == 10) + cc = '0' + c; + else if (base == 36) { + if (c < 10) + cc = '0' + c; + else + cc = 'A' + c - 10; + } + else { + cc = c+32; + } + out[len++] = cc; + } + out[len] = 0; + reverse(out, out+len); +} + +bool expandDirectory(const char *file, const char *filetype, vector &res) +{ + WIN32_FIND_DATA fd; + + char dir[MAX_PATH]; + char fullPath[MAX_PATH]; + + if (file[0] == '.') { + GetCurrentDirectory(MAX_PATH, dir); + strcat_s(dir, file+1); + } + else + strcpy_s(dir, MAX_PATH, file); + + if (dir[strlen(dir)-1]!='\\') + strcat_s(dir, MAX_PATH, "\\"); + + strcpy_s(fullPath, MAX_PATH, dir); + strcat_s(dir, MAX_PATH, filetype); + + HANDLE h=FindFirstFile(dir, &fd); + + if (h == INVALID_HANDLE_VALUE) + return false; + + bool more = true; + + while (more) { + if (fd.cFileName[0] != '.') { + //Avoid .. and . + char fullPathFile[MAX_PATH]; + strcpy_s(fullPathFile, MAX_PATH, fullPath); + strcat_s(fullPathFile, MAX_PATH, fd.cFileName); + res.push_back(fullPathFile); + } + more=FindNextFile(h, &fd)!=0; + } + + FindClose(h); + return true; +} + +string encodeSex(PersonSex sex) { + if (sex == sFemale) + return "F"; + else if (sex == sMale) + return "M"; + else if (sex == sBoth) + return "B"; + else + return ""; +} + +PersonSex interpretSex(const string &sex) { + if (sex == "F" || sex == "K" || sex == "W") + return sFemale; + else if (sex == "M" || sex == "H") + return sMale; + else if (sex == "B") + return sBoth; + else + return sUnknown; +} + +bool matchNumber(int a, const char *b) { + if (a == 0 && b[0]) + return false; + + char bf[32]; + _itoa_s(a, bf, 10); + + // Check matching substring + for (int k = 0; k < 12; k++) { + if (b[k] == 0) + return true; + if (bf[k] != b[k]) + return false; + } + + return false; +} + +string makeValidFileName(const string &input, bool strict) { + string out; + out.reserve(input.size()); + + if (strict) { + for (size_t k = 0; k < input.length(); k++) { + int b = input[k]; + if ( (b>='0' && b<='9') || (b>='a' && b<='z') || (b>='A' && b<='Z') || b == '_' || b=='.' ) + out.push_back(b); + else if (b == ' ' || b == ',') + out.push_back('_'); + else { + b = toLowerStripped(b); + if ( char(b) == 'ö') + b = 'o'; + else if (char(b) == 'ä' || char(b) == 'å' || char(b)== 'à' || char(b)== 'á' || char(b)== 'â' || char(b)== 'ã' || char(b)== 'æ') + b = 'a'; + else if (char(b) == 'ç') + b = 'c'; + else if (char(b) == 'è' || char(b) == 'é' || char(b) == 'ê' || char(b) == 'ë') + b = 'e'; + else if (char(b) == 'ð') + b = 't'; + else if (char(b) == 'ï' || char(b) == 'ì' || char(b) == 'ï' || char(b) == 'î' || char(b) == 'í') + b = 'i'; + else if (char(b) == 'ò' || char(b) == 'ó' || char(b) == 'ô' || char(b) == 'õ' || char(b) == 'ø') + b = 'o'; + else if (char(b) == 'ù' || char(b) == 'ú' || char(b) == 'û' || char(b) == 'ü') + b = 'u'; + else if (char(b) == 'ý') + b = 'y'; + else + b = '-'; + + out.push_back(b); + } + } + } + else { + for (size_t k = 0; k < input.length(); k++) { + unsigned b = input[k]; + if (b < 32 || b == '*' || b == '?' || b==':' || b=='/' || b == '\\') + b = '_'; + out.push_back(b); + } + } + return out; +} + +void capitalize(string &str) { + if (str.length() > 0) { + char c = str[0] & 0xFF; + + if (c>='a' && c<='z') + c += ('A' - 'a'); + else if (c == 'ö') + c = 'Ö'; + else if (c == 'ä') + c = 'Ä'; + else if (c == 'å') + c = 'Å'; + else if (c == 'é') + c = 'É'; + + str[0] = c; + } +} + +/** Return bias in seconds. UTC = local time + bias. */ +int getTimeZoneInfo(const string &date) { + static char lastDate[16] = {0}; + static int lastValue = -1; + // Local cacheing + if (lastValue != -1 && lastDate == date) { + return lastValue; + } + strcpy_s(lastDate, 16, date.c_str()); +// TIME_ZONE_INFORMATION tzi; + SYSTEMTIME st; + convertDateYMS(date, st, false); + st.wHour = 12; + SYSTEMTIME utc; + TzSpecificLocalTimeToSystemTime(0, &st, &utc); + + int datecode = ((st.wYear * 12 + st.wMonth) * 31) + st.wDay; + int datecodeUTC = ((utc.wYear * 12 + utc.wMonth) * 31) + utc.wDay; + + int daydiff = 0; + if (datecodeUTC > datecode) + daydiff = 1; + else if (datecodeUTC < datecode) + daydiff = -1; + + int t = st.wHour * 3600; + int tUTC = daydiff * 24 * 3600 + utc.wHour * 3600 + utc.wMinute * 60 + utc.wSecond; + + lastValue = tUTC - t; + return lastValue; +} + +string getTimeZoneString(const string &date) { + int a = getTimeZoneInfo(date); + if (a == 0) + return "+00:00"; + else if (a>0) { + char bf[12]; + sprintf_s(bf, "-%02d:%02d", a/3600, (a/60)%60); + return bf; + } + else { + char bf[12]; + sprintf_s(bf, "+%02d:%02d", a/-3600, (a/-60)%60); + return bf; + } +} + +bool compareBib(const string &b1, const string &b2) { + int l1 = b1.length(); + int l2 = b2.length(); + if (l1 != l2) + return l1 < l2; + + unsigned char maxc = 0, minc = 255; + for (int k = 0; k < l1; k++) { + unsigned char b = b1[k]; + maxc = max(maxc, b); + minc = min(minc, b); + } + for (int k = 0; k < l2; k++) { + unsigned char b = b2[k]; + maxc = max(maxc, b); + minc = min(minc, b); + } + + unsigned coeff = maxc-minc + 1; + + unsigned z1 = 0; + for (int k = 0; k < l1; k++) { + unsigned char b = b1[k]-minc; + z1 = coeff * z1 + b; + } + + unsigned z2 = 0; + for (int k = 0; k < l2; k++) { + unsigned char b = b2[k]-minc; + z2 = coeff * z2 + b; + } + + return z1 < z2; +} + + +/// Split a name into first name and last name +int getNameCommaSplitPoint(const string &name) { + int commaSplit = -1; + + for (unsigned k = 1; k + 1 < name.size(); k++) { + if (name[k] == ',') { + commaSplit = k; + break; + } + } + + if (commaSplit >= 0) { + commaSplit += 2; + } + + return commaSplit; +} + + +/// Split a name into first name and last name +int getNameSplitPoint(const string &name) { + int split[10]; + int nSplit = 0; + + for (unsigned k = 1; k + 1=9 ) + break; + } + } + if (nSplit == 1) + return split[0] + 1; + else if (nSplit == 0) + return -1; + else { + const oWordList &givenDB = lang.get().getGivenNames(); + int sp_ix = 0; + for (int k = 1; k= 'a' && c <= 'z' && !noCapitalize(str, i)) + str[i] = c + ('A' - 'a'); + init = isspace(c) != 0; + } +} + +void MeOSFileLock::unlockFile() { + if (lockedFile != INVALID_HANDLE_VALUE) + CloseHandle(lockedFile); + + lockedFile = INVALID_HANDLE_VALUE; +} + +void MeOSFileLock::lockFile(const string &file) { + unlockFile(); + lockedFile = CreateFile(file.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + //lockedFile = _open(file.c_str(), _O_RDWR); + if (lockedFile == INVALID_HANDLE_VALUE) { + int err = GetLastError(); + if (err == ERROR_SHARING_VIOLATION) + throw meosException("open_error_locked"); + else { + TCHAR buff[256]; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, buff, sizeof(buff), 0); + throw meosException("open_error#" + file + "#" + buff); + } + } +} + +void processGeneralTime(const string &generalTime, string &meosTime, string &meosDate) { + meosTime = ""; + meosDate = ""; + vector parts; + split(generalTime, ":-,. /\t", parts); + + // Indices into parts + int year = -2; + int month = -2; + int day = -2; + + int hour = -2; + int minute = -2; + int second = -2; + int subsecond = -2; + + int found = 0, base = -1, iter = 0; + bool pm = strstr(generalTime.c_str(), "PM") != 0 || + strstr(generalTime.c_str(), "pm") != 0; + + while (iter < 2 && second==-2) { + if (base == found) + iter++; + + base = found; + for (size_t k = 0; k < parts.size(); k++) { + if (parts[k].empty()) + continue; + int number = atoi(parts[k].c_str()); + if (number == 0 && parts[k][0] != '0') + number = -1; // Not a number + + if (iter == 0) { + // Date + if (number > 1900 && number < 3000 && year < 0) { + found++; + year = k; + } + else if (number >= 1 && number <= 12 && month < 0 && (year == k+1 || year == k-1) ) { + month = k; + found++; + } + else if (number >= 1 && number <=31 && day < 0 && (month == k+1 || month == k-1)) { + day = k; + found++; + iter++; + break; + } + else if (number > 1011900 && number < 30000101 && year < 0 && month < 0 && day < 0) { + day = k; //Date with format 20160906 or 06092016 + month = k; + year = k; + found++; + break; + } + } + else if (iter == 1) { + + // Time + if (number >= 0 && number <= 24 && year != k && day != k && month != k && hour < 0) { + hour = k; + found++; + } + else if (number >= 0 && number <= 59 && minute < 0 && hour == k-1) { + minute = k; + found++; + } + else if (number >= 0 && number <= 59 && second < 0 && minute == k-1) { + second = k; + found++; + } + else if (number >= 0 && number < 1000 && subsecond < 0 && second == k-1 && k != year) { + subsecond = k; + found++; + iter++; + break; + } + } + } + } + + if (second >= 0 && minute >= 0 && hour>= 0) { + if (!pm) + meosTime = parts[hour] + ":" + parts[minute] + ":" + parts[second]; + else { + int rawHour = atoi(parts[hour].c_str()); + if (rawHour < 12) + rawHour+=12; + meosTime = itos(rawHour) + ":" + parts[minute] + ":" + parts[second]; + } + } + + if (year >= 0 && month >= 0 && day >= 0) { + int y = -1, m = -1, d = -1; + if (year != month) { + y = atoi(parts[year].c_str()); + m = atoi(parts[month].c_str()); + d = atoi(parts[day].c_str()); + + //meosDate = parts[year] + "-" + parts[month] + "-" + parts[day]; + } + else { + int td = atoi(parts[year].c_str()); + int y1 = td / 10000; + int m1 = (td / 100) % 100; + int d1 = td % 100; + bool ok = y1 > 2000 && y1 < 3000 && m1>=1 && m1<=12 && d1 >= 1 && d1 <= 31; + if (!ok) { + y1 = td % 10000; + m1 = (td / 10000) % 100; + d1 = (td / 1000000); + + ok = y1 > 2000 && y1 < 3000 && m1>=1 && m1<=12 && d1 >= 1 && d1 <= 31; + } + if (ok) { + y = y1; + m = m1; + d = d1; + } + meosDate = itos(y1) + "-" + itos(m1) + "-" + itos(d1); + } + if (y > 0) { + char bf[24]; + sprintf_s(bf, 24, "%d-%02d-%02d", y, m, d); + meosDate = bf; + } + } + +} diff --git a/code/meos_util.h b/code/meos_util.h new file mode 100644 index 0000000..3c06743 --- /dev/null +++ b/code/meos_util.h @@ -0,0 +1,236 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include + +class StringCache { +private: + vector cache; + size_t ix; + + vector wcache; + size_t wix; +public: + static StringCache &getInstance(); + + void init() {cache.resize(256); wcache.resize(256);} + void clear() {cache.clear(); wcache.clear();} + + std::string &get() { + if ( (++ix) >= cache.size() ) + ix = 0; + int lx = ix; + return cache[lx]; + } + + std::wstring &wget() { + if ( (++wix) >= wcache.size() ) + wix = 0; + int lx = wix; + return wcache[lx]; + } +}; + +string convertSystemTime(const SYSTEMTIME &st); +string convertSystemTimeOnly(const SYSTEMTIME &st); +string convertSystemDate(const SYSTEMTIME &st); +string getLocalTime(); +string getLocalDate(); +string getLocalTimeOnly(); + +// Get a day number after a fixed day some time ago... +int getRelativeDay(); + +/// Get time and date in a format that forms a part of a filename +string getLocalTimeFileName(); + +const string &getTimeMS(int m); +const string &formatTime(int rt); +const string &formatTimeHMS(int rt); +string formatTimeIOF(int rt, int zeroTime); + +int convertDateYMS(const string &m, bool checkValid); +int convertDateYMS(const string &m, SYSTEMTIME &st, bool checkValid); + +// Convert a "general" time string to a MeOS compatible time string +void processGeneralTime(const string &generalTime, string &meosTime, string &meosDate); + +// Format number date 20160421 -> 2016-04-21 (if iso) or according to a custom format otherwise +string formatDate(int m, bool useIsoFormat); + +__int64 SystemTimeToInt64Second(const SYSTEMTIME &st); +SYSTEMTIME Int64SecondToSystemTime(__int64 time); + +#define NOTIME 0x7FFFFFFF + +//Returns a time converted from +/-MM:SS or NOTIME, in seconds +int convertAbsoluteTimeMS(const string &m); +// Parses a time on format HH:MM:SS+01:00Z or HHMMSS+0100Z (but ignores time zone) +int convertAbsoluteTimeISO(const string &m); + +/** Returns a time converted from HH:MM:SS or -1, in seconds + @param m time to convert + @param daysZeroTime -1 do not support days syntax, positive interpret days w.r.t the specified zero time. +*/ +int convertAbsoluteTimeHMS(const string &m, int daysZeroTime); + +const vector &split(const string &line, const string &separators, vector &split_vector); +const string &unsplit(const vector &split_vector, const string &separators, string &line); + +const string &MakeDash(const string &t); +const string &MakeDash(const char *t); +string FormatRank(int rank); +const string &itos(int i); +string itos(unsigned long i); +string itos(unsigned int i); +string itos(__int64 i); + +///Lower case match (filt_lc must be lc) +bool filterMatchString(const string &c, const char *filt_lc); +bool matchNumber(int number, const char *key); + +int getMeosBuild(); +string getMeosDate(); +string getMeosFullVersion(); +string getMajorVersion(); +string getMeosCompectVersion(); + +void getSupporters(vector &supp); + +int countWords(const char *p); + +string trim(const string &s); + +bool fileExist(const char *file); + +bool stringMatch(const string &a, const string &b); + +const char *decodeXML(const char *in); +const string &decodeXML(const string &in); +const string &encodeXML(const string &in); + +/** Extend a year from 03 -> 2003, 97 -> 1997 etc */ +int extendYear(int year); + +/** Get current year, e.g., 2010 */ +int getThisYear(); + +/** Translate a char to lower/stripped of accents etc.*/ +int toLowerStripped(int c); + +/** Canonize a person/club name */ +const char *canonizeName(const char *name); + +/** String distance between 0 and 1. 0 is equal*/ +double stringDistance(const char *a, const char *b); + + +/** Get a number suffix, Start 1 -> 1. Zero for none*/ +int getNumberSuffix(const string &str); + +/// Extract any number from a string and return the number, prefix and suffix +int extractAnyNumber(const string &str, string &prefix, string &suffix); + + +/** Compare classnames, match H21 Elit with H21E and H21 E */ +bool compareClassName(const string &a, const string &b); + +/** Get WinAPI error from code */ +string getErrorMessage(int code); + +class HLS { +private: + WORD HueToRGB(WORD n1, WORD n2, WORD hue) const; +public: + + HLS(WORD H, WORD L, WORD S) : hue(H), lightness(L), saturation(S) {} + HLS() : hue(0), lightness(0), saturation(1) {} + WORD hue; + WORD lightness; + WORD saturation; + void lighten(double f); + void saturate(double s); + void colorDegree(double d); + HLS &RGBtoHLS(DWORD lRGBColor); + DWORD HLStoRGB() const; +}; + +#ifndef MEOSDB + void unzip(const char *zipfilename, const char *password, vector &extractedFiles); + int zip(const char *zipfilename, const char *password, const vector &files); +#endif + +bool isAscii(const string &s); +bool isNumber(const string &s); +int convertDynamicBase(const string &s, long long &out); +void convertDynamicBase(long long val, int base, char out[16]); + +/// Find all files in dir matching given file pattern +bool expandDirectory(const char *dir, const char *pattern, vector &res); + +enum PersonSex {sFemale = 1, sMale, sBoth, sUnknown}; + +PersonSex interpretSex(const string &sex); + +string encodeSex(PersonSex sex); + +string makeValidFileName(const string &input, bool strict); + +/** Initial capital letter. */ +void capitalize(string &str); + +/** Initial capital letter for each word. */ +void capitalizeWords(string &str); + +string getTimeZoneString(const string &date); + +/** Return bias in seconds. UTC = local time + bias. */ +int getTimeZoneInfo(const string &date); + +/** Compare bib numbers (which may contain non-digits, e.g. A-203, or 301a, 301b)*/ +bool compareBib(const string &b1, const string &b2); + +/** Split a name into Given, Family, and return Given.*/ +string getGivenName(const string &name); + +/** Split a name into Given, Family, and return Family.*/ +string getFamilyName(const string &name); + +/** Simple file locking class to prevent opening in different MeOS session. */ +class MeOSFileLock { + HANDLE lockedFile; + // Not supported + MeOSFileLock(const MeOSFileLock &); + const MeOSFileLock &operator=(const MeOSFileLock &); + +public: + MeOSFileLock() {lockedFile = INVALID_HANDLE_VALUE;} + ~MeOSFileLock() {unlockFile();} + + void unlockFile(); + void lockFile(const string &file); +}; + +namespace MeOSUtil { + extern int useHourFormat; +} diff --git a/code/meos_vc10.sln b/code/meos_vc10.sln new file mode 100644 index 0000000..9651228 --- /dev/null +++ b/code/meos_vc10.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "meos", "meos.vcxproj", "{B854EF2A-2BB7-4D62-B08B-96BD64B347E8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4614D306-CDFF-466A-AAA3-6017F2237DB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|Win64 = Debug|Win64 + Release|Win32 = Release|Win32 + Release|Win64 = Release|Win64 + test|Win32 = test|Win32 + test|Win64 = test|Win64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|Win32.ActiveCfg = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|Win32.Build.0 = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|Win64.ActiveCfg = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|Win32.ActiveCfg = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|Win32.Build.0 = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|Win64.ActiveCfg = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|Win32.ActiveCfg = test|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|Win32.Build.0 = test|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|Win64.ActiveCfg = test|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/code/meos_vc15.sln b/code/meos_vc15.sln new file mode 100644 index 0000000..2c0f00c --- /dev/null +++ b/code/meos_vc15.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "meos", "meosvc15.vcxproj", "{B854EF2A-2BB7-4D62-B08B-96BD64B347E8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + test|x86 = test|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|x86.ActiveCfg = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Debug|x86.Build.0 = Debug|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|x86.ActiveCfg = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.Release|x86.Build.0 = Release|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|x86.ActiveCfg = test|Win32 + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8}.test|x86.Build.0 = test|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/code/meosdb/MeosSQL.cpp b/code/meosdb/MeosSQL.cpp new file mode 100644 index 0000000..f27aa99 --- /dev/null +++ b/code/meosdb/MeosSQL.cpp @@ -0,0 +1,3664 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + +#include "StdAfx.h" + +#include +#include +#include + + +#include "MeosSQL.h" + +#include "../oRunner.h" +#include "../oEvent.h" +#include "../meos_util.h" +#include "../RunnerDB.h" +#include "../progress.h" +#include "../metalist.h" +#include "../MeOSFeatures.h" + +using namespace mysqlpp; + +MeosSQL::MeosSQL(void) +{ + monitorId=0; + warnedOldVersion=false; + buildVersion=getMeosBuild(); +} + +MeosSQL::~MeosSQL(void) +{ +} + +void MeosSQL::alert(const string &s) +{ + errorMessage=s; +} + +string C_INT(string name) +{ + return " "+name+" INT NOT NULL DEFAULT 0, "; +} + +string C_INT64(string name) +{ + return " "+name+" BIGINT NOT NULL DEFAULT 0, "; +} + +string C_STRING(string name, int len=64) +{ + char bf[16]; + sprintf_s(bf, "%d", len); + return " "+name+" VARCHAR("+ bf +") NOT NULL DEFAULT '', "; +} + +string C_TEXT(string name) +{ + return " "+name+" TEXT NOT NULL, "; +} + +string C_MTEXT(string name) +{ + return " "+name+" MEDIUMTEXT NOT NULL, "; +} + + +string C_UINT(string name) +{ + return " "+name+" INT UNSIGNED NOT NULL DEFAULT 0, "; +} + +string C_START(string name) +{ + return "CREATE TABLE IF NOT EXISTS "+name+" (" + + " Id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY (Id), "; +} + +string C_START_noid(string name) +{ + return "CREATE TABLE IF NOT EXISTS "+name+" ("; +} + +string C_END() +{ + return " Modified TIMESTAMP, Counter INT UNSIGNED NOT NULL DEFAULT 0, " + "INDEX(Counter), INDEX(Modified), Removed BOOL NOT NULL DEFAULT 0) " + "ENGINE = MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci"; +} + +string C_END_noindex() +{ + return " Modified TIMESTAMP) " + "ENGINE = MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci"; +} + +string limitLength(const string &in, size_t max) { + if (in.length() < max) + return in; + else + return in.substr(0, max); +} + +bool MeosSQL::listCompetitions(oEvent *oe, bool keepConnection) { + errorMessage.clear(); + CmpDataBase=""; + if (oe->isClient()) + throw std::exception("Runtime error."); + + oe->serverName.clear(); + + if (!keepConnection) { + try { + con.connect("", oe->MySQLServer.c_str(), oe->MySQLUser.c_str(), + oe->MySQLPassword.c_str(), oe->MySQLPort); + } + catch (const Exception& er) { + alert(string(er.what()) + " MySQL Error"); + return false; + } + } + + if (!con.connected()) { + errorMessage = "Internal error connecting to MySQL"; + return false; + } + + string serverInfo = con.server_info(); + + if (serverInfo < "5.0.3") { + errorMessage = "Minst MySQL X krävs. Du använder version Y.#5.0.3#" + serverInfo; + return false; + } + + serverName=oe->MySQLServer; + serverUser=oe->MySQLUser; + serverPassword=oe->MySQLPassword; + serverPort=oe->MySQLPort; + + //Store verified server name + oe->serverName=serverName; + + NoExceptions ne(con); + + if (!con.select_db("MeOSMain")){ + con.create_db("MeOSMain"); + con.select_db("MeOSMain"); + } + + Query query = con.query(); + + try{ + query << C_START("oEvent") + << C_STRING("Name", 128) + << C_STRING("Annotation", 128) + << C_STRING("Date", 32) + << C_UINT("ZeroTime") + << C_STRING("NameId", 64) + << " Version INT UNSIGNED DEFAULT 1, " << C_END(); + + query.execute(); + + query.reset(); + Result res = query.store("DESCRIBE oEvent"); + int nr = (int)res.num_rows(); + if (nr == 9) { + query.execute("ALTER TABLE oEvent ADD COLUMN " + "Annotation VARCHAR(128) NOT NULL DEFAULT '' AFTER Name"); + } + } + catch (const Exception& er) { + alert(string(er.what())+ " MySQL Error"); + // Try a repair operation + try { + query.execute("REPAIR TABLE oEvent EXTENDED"); + } + catch (const Exception&) { + } + + return false; + } + + query.reset(); + + try { + query << "SELECT * FROM oEvent"; + + Result res = query.store(); + + if (res) { + for (int i=0; idbVersion) { + CompetitionInfo ci; + ci.Name = row["Name"]; + ci.Annotation = row["Annotation"]; + ci.Id = row["Id"]; + ci.Date = row["Date"]; + ci.FullPath = row["NameId"]; + ci.NameId = row["NameId"]; + ci.Server = oe->MySQLServer; + ci.ServerPassword = oe->MySQLPassword; + ci.ServerUser = oe->MySQLUser; + ci.ServerPort = oe->MySQLPort; + + oe->cinfo.push_front(ci); + } + else { + CompetitionInfo ci; + ci.Name = row["Name"]; + ci.Date = row["Date"]; + ci.Annotation = row["Annotation"]; + ci.Id=0; + ci.Server="bad"; + ci.FullPath=row["NameId"]; + oe->cinfo.push_front(ci); + } + } + } + } + catch (const Exception& er) { + // Try a repair operation + try { + query.execute("REPAIR TABLE oEvent EXTENDED"); + } + catch (const Exception&) { + } + + setDefaultDB(); + alert(string(er.what()) + " MySQL Error"); + return false; + } + + return true; +} + +bool MeosSQL::repairTables(const string &db, vector &output) { + // Update list database; + con.select_db(db); + output.clear(); + + if (!con.connected()) { + errorMessage = "Internal error connecting to MySQL"; + return false; + } + + Query q = con.query(); + Result res = q.store("SHOW TABLES"); + int numtab = (int)res.num_rows(); + vector tb; + for (int k = 0; k < numtab; k++) + tb.push_back(res.at(k).at(0).c_str()); + + for (int k = 0; k < numtab; k++) { + string sql = "REPAIR TABLE " + tb[k] + " EXTENDED"; + try { + res = q.store(sql); + string msg; + Row row = res.at(0); + for (size_t j = 0; j < row.size(); j++) { + string t = row.at(j).get_string(); + if (!msg.empty()) + msg += ", "; + msg += t; + } + output.push_back(msg); + } + catch (const Exception &ex) { + string err1 = "FAILED: " + sql; + output.push_back(err1); + output.push_back(ex.what()); + } + } + return true; +} + +bool MeosSQL::createRunnerDB(oEvent *oe, Query &query) +{ + query.reset(); + + query << C_START_noid("dbRunner") + << C_STRING("Name", 31) << C_INT("CardNo") + << C_INT("Club") << C_STRING("Nation", 3) + << C_STRING("Sex", 1) << C_INT("BirthYear") + << C_INT64("ExtId") << C_END_noindex(); + + query.execute(); + + query.reset(); + query << C_START_noid("dbClub") + << " Id INT NOT NULL, " + << C_STRING("Name", 64) + << oe->oClubData->generateSQLDefinition() << C_END_noindex(); + query.execute(); + + // Ugrade dbClub + upgradeDB("dbClub", oe->oClubData); + + return true; +} + +void MeosSQL::getColumns(const string &table, set &output) { + Query query = con.query(); + output.clear(); + Result res = query.store("DESCRIBE " + table); + for (size_t k = 0; k < res.size(); k++) { + output.insert((const char *)res.at(k).at(0)); + } +} + +void MeosSQL::upgradeDB(const string &db, oDataContainer const * dc) { + set eCol; + getColumns(db, eCol); + + Query query = con.query(); + + if (db == "oEvent") { + if (!eCol.count("Annotation")) { + query.execute("ALTER TABLE oEvent ADD COLUMN " + "Annotation VARCHAR(128) NOT NULL DEFAULT '' AFTER Name"); + } + if (!eCol.count("Lists")) { + string sql = "ALTER TABLE oEvent ADD COLUMN " + C_MTEXT("Lists"); + sql = sql.substr(0, sql.length() - 2); + query.execute(sql); + } + } + else if (db == "oCourse") { + if (!eCol.count("Legs")) { + string sql = "ALTER TABLE oCourse ADD COLUMN " + C_STRING("Legs", 1024); + sql = sql.substr(0, sql.length() - 2); + query.execute(sql); + } + } + else if (db == "oRunner") { + if (!eCol.count("InputTime")) { + string sql = "ALTER TABLE oRunner "; + sql += "ADD COLUMN " + C_INT("InputTime"); + sql += "ADD COLUMN " + C_INT("InputStatus"); + sql += "ADD COLUMN " + C_INT("InputPoints"); + sql += "ADD COLUMN " + C_INT("InputPlace"); + sql = sql.substr(0, sql.length() - 2); + query.execute(sql); + } + } + + // Ugrade table + string sqlAdd = dc->generateSQLDefinition(eCol); + if (!sqlAdd.empty()) { + query.execute("ALTER TABLE " + db + " " + sqlAdd); + } +} + +bool MeosSQL::openDB(oEvent *oe) +{ + clearReadTimes(); + errorMessage.clear(); + if (!con.connected() && !listCompetitions(oe, false)) + return false; + + try{ + con.select_db("MeOSMain"); + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what()) + " MySQL Error. Select MeosMain"); + setDefaultDB(); + return 0; + } + monitorId=0; + string dbname=oe->CurrentNameId; + + try { + Query query = con.query(); + query << "SELECT * FROM oEvent WHERE NameId=" << quote << dbname; + Result res = query.store(); + + if (res && res.num_rows()>=1) { + Row row=res.at(0); + + int version = row["Version"]; + + if (version < oEvent::dbVersion) { + query.reset(); + query << "UPDATE oEvent SET Version=" << oEvent::dbVersion << " WHERE Id=" << row["Id"]; + query.execute(); + } + else if (version > oEvent::dbVersion) { + alert("A newer version av MeOS is required."); + return false; + } + /* + if (version != oe->dbVersion) { + // Wrong version. Drop and reset. + query.reset(); + query << "DELETE FROM oEvent WHERE Id=" << row["Id"]; + query.execute(); + con.drop_db(dbname); + return openDB(oe); + }*/ + + oe->Id=row["Id"]; //Don't synchronize more here... + } + else { + query.reset(); + query << "INSERT INTO oEvent SET Name='-', Date='', NameId=" << quote << dbname + << ", Version=" << oe->dbVersion; + + ResNSel res=query.execute(); + + if (res){ + oe->Id=static_cast(res.insert_id); + } + } + } + catch (const mysqlpp::Exception& er){ + setDefaultDB(); + alert(string(er.what()) + " MySQL Error. Select DB."); + return 0; + } + + { + mysqlpp::NoExceptions ne(con); + + if (!con.select_db(dbname)){ + con.create_db(dbname); + con.select_db(dbname); + } + } + + CmpDataBase=dbname; + + Query query = con.query(); + try { + //Real version of oEvent db + query << C_START("oEvent") + << C_STRING("Name", 128) + << C_STRING("Annotation", 128) + << C_STRING("Date", 32) + << C_UINT("ZeroTime") + << C_STRING("NameId", 64) + << C_UINT("BuildVersion") + << oe->getDI().generateSQLDefinition() + << C_MTEXT("Lists") << C_END(); + query.execute(); + + // Upgrade oEvent + upgradeDB("oEvent", oe->oEventData); + + query.reset(); + query << C_START("oRunner") + << C_STRING("Name") << C_INT("CardNo") + << C_INT("Club") << C_INT("Class") << C_INT("Course") << C_INT("StartNo") + << C_INT("StartTime") << C_INT("FinishTime") + << C_INT("Status") << C_INT("Card") << C_STRING("MultiR", 200) + << C_INT("InputTime") << C_INT("InputStatus") << C_INT("InputPoints") << C_INT("InputPlace") + << oe->oRunnerData->generateSQLDefinition() << C_END(); + + query.execute(); + + // Ugrade oRunner + upgradeDB("oRunner", oe->oRunnerData); + + query.reset(); + query << C_START("oCard") + << C_INT("CardNo") + << C_UINT("ReadId") + << C_STRING("Punches", 1024) << C_END(); + + query.execute(); + + query.reset(); + query << C_START("oClass") + << C_STRING("Name", 128) + << C_INT("Course") + << C_MTEXT("MultiCourse") + << C_STRING("LegMethod", 1024) + << oe->oClassData->generateSQLDefinition() << C_END(); + query.execute(); + + // Ugrade oClass + upgradeDB("oClass", oe->oClassData); + + query.reset(); + query << C_START("oClub") + << C_STRING("Name", 128) + << oe->oClubData->generateSQLDefinition() << C_END(); + query.execute(); + + // Ugrade oClub + upgradeDB("oClub", oe->oClubData); + + query.reset(); + query << C_START("oControl") + << C_STRING("Name", 128) + << C_STRING("Numbers", 128) + << C_UINT("Status") + << oe->oControlData->generateSQLDefinition() << C_END(); + query.execute(); + + // Ugrade oRunner + upgradeDB("oControl", oe->oControlData); + + + query.reset(); + query << C_START("oCourse") + << C_STRING("Name") + << C_STRING("Controls", 512) + << C_UINT("Length") + << C_STRING("Legs", 1024) + << oe->oCourseData->generateSQLDefinition() << C_END(); + query.execute(); + + // Ugrade oCourse + upgradeDB("oCourse", oe->oCourseData); + + query.reset(); + query << C_START("oTeam") + << C_STRING("Name") << C_STRING("Runners", 256) + << C_INT("Club") << C_INT("Class") + << C_INT("StartTime") << C_INT("FinishTime") + << C_INT("Status") << C_INT("StartNo") + << oe->oTeamData->generateSQLDefinition() << C_END(); + query.execute(); + + // Ugrade oTeam + upgradeDB("oTeam", oe->oTeamData); + + query.reset(); + query << C_START("oPunch") + << C_INT("CardNo") + << C_INT("Time") + << C_INT("Type") << C_END(); + query.execute(); + + query.reset(); + query << C_START("oMonitor") + << C_STRING("Client") + << C_UINT("Count") + << C_END(); + query.execute(); + + query.reset(); + query << "CREATE TABLE IF NOT EXISTS oCounter (" + << "CounterId INT NOT NULL, " + << C_UINT("oControl") + << C_UINT("oCourse") + << C_UINT("oClass") + << C_UINT("oCard") + << C_UINT("oClub") + << C_UINT("oPunch") + << C_UINT("oRunner") + << C_UINT("oTeam") + << C_UINT("oEvent") + << " Modified TIMESTAMP) ENGINE = MyISAM"; + query.execute(); + + mysqlpp::Result res = query.store("SELECT CounterId FROM oCounter"); + if (res.num_rows()==0) { + query.reset(); + query << "INSERT INTO oCounter SET CounterId=1, oPunch=1, oTeam=1, oRunner=1"; + query.execute(); + } + + // Create runner/club DB + createRunnerDB(oe, query); + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what()) + " MySQL Error."); + return 0; + } + + return true; +} + +bool MeosSQL::getErrorMessage(char *bf) +{ + strcpy_s(bf, 256, errorMessage.c_str()); + return !errorMessage.empty(); +} + +bool MeosSQL::closeDB() +{ + CmpDataBase=""; + errorMessage.clear(); + + try { + con.close(); + } + catch (const mysqlpp::Exception&) { + } + + return true; +} + + +//CAN BE RUN IN A SEPARTE THREAD. Access nothing without thinking... +//No other MySQL-call will take place in parallell. +bool MeosSQL::reConnect() +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) { + errorMessage="No database selected."; + return false; + } + + try { + con.close(); + } + catch (const mysqlpp::Exception&) { + } + + try { + con.connect("", serverName.c_str(), serverUser.c_str(), + serverPassword.c_str(), serverPort); + } + catch (const Exception& er) { + errorMessage=er.what(); + return false; + } + + try { + con.select_db(CmpDataBase); + } + catch (const Exception& er) { + errorMessage=er.what(); + return false; + } + + return true; +} + +OpFailStatus MeosSQL::SyncUpdate(oEvent *oe) +{ + OpFailStatus retValue = opStatusOK; + errorMessage.clear(); + if (CmpDataBase.empty()) + return opStatusFail; + + try{ + con.select_db("MeOSMain"); + + mysqlpp::Query queryset = con.query(); + queryset << "UPDATE oEvent SET Name=" << quote << limitLength(oe->Name, 128) << ", " + << " Annotation=" << quote << limitLength(oe->Annotation, 128) << ", " + << " Date=" << quote << oe->Date << ", " + << " NameId=" << quote << oe->CurrentNameId << ", " + << " ZeroTime=" << unsigned(oe->ZeroTime) + << " WHERE Id=" << oe->Id; + + queryset.execute(); + //syncUpdate(queryset, "oEvent", oe, true); + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [UPDATING oEvent]"); + setDefaultDB(); + return opStatusFail; + } + + try{ + con.select_db(CmpDataBase); + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [OPENING] "+CmpDataBase); + return opStatusFail; + } + + { + + string listEnc; + try { + encodeLists(oe, listEnc); + } + catch (std::exception &ex) { + retValue = opStatusWarning; + alert(ex.what()); + } + + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << limitLength(oe->Name, 128) << ", " + << " Annotation=" << quote << limitLength(oe->Annotation, 128) << ", " + << " Date=" << quote << oe->Date << ", " + << " NameId=" << quote << oe->CurrentNameId << ", " + << " ZeroTime=" << unsigned(oe->ZeroTime) << ", " + << " BuildVersion=" << buildVersion << ", " + << " Lists=" << quote << listEnc + << oe->getDI().generateSQLSet(true); + + if (syncUpdate(queryset, "oEvent", oe) == opStatusFail) + return opStatusFail; + } + + con.query().exec("DELETE FROM oCard"); + { + list::iterator it=oe->Cards.begin(); + while(it!=oe->Cards.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + + con.query().exec("DELETE FROM oClub"); + { + list::iterator it=oe->Clubs.begin(); + while(it!=oe->Clubs.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + con.query().exec("DELETE FROM oControl"); + { + list::iterator it=oe->Controls.begin(); + while(it!=oe->Controls.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + con.query().exec("DELETE FROM oCourse"); + { + list::iterator it=oe->Courses.begin(); + while(it!=oe->Courses.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + con.query().exec("DELETE FROM oClass"); + { + list::iterator it=oe->Classes.begin(); + while(it!=oe->Classes.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + con.query().exec("DELETE FROM oRunner"); + { + list::iterator it=oe->Runners.begin(); + while(it!=oe->Runners.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + + con.query().exec("DELETE FROM oTeam"); + { + list::iterator it=oe->Teams.begin(); + while(it!=oe->Teams.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + + con.query().exec("DELETE FROM oPunch"); + { + list::iterator it=oe->punches.begin(); + while(it!=oe->punches.end()){ + if (!it->isRemoved() && syncUpdate(&*it, true) == opStatusFail) + return opStatusFail; + ++it; + } + } + return retValue; +} + +OpFailStatus MeosSQL::uploadRunnerDB(oEvent *oe) +{ + errorMessage.clear(); + if (CmpDataBase.empty()) + return opStatusFail; + int errorCount = 0; + + ProgressWindow pw(oe->hWnd()); + try { + const vector &cdb = oe->runnerDB->getClubDB(); + size_t size = cdb.size(); + + const vector &rdb = oe->runnerDB->getRunnerDB(); + + if (cdb.size() + rdb.size() > 2000) + pw.init(); + + size_t tz = cdb.size() + rdb.size(); + int s1 = (1000 * cdb.size())/tz; + int s2 = (1000 * rdb.size())/tz; + + // Reset databases + con.query().exec("DELETE FROM dbClub"); + con.query().exec("DELETE FROM dbRunner"); + + for (size_t k = 0; krunnerDB->setDataDate(dateTime); + } + catch (const mysqlpp::Exception& er) { + errorMessage = er.what(); + return opStatusFail; + } + if (errorCount > 0) + return opStatusWarning; + + return opStatusOK; +} + +bool MeosSQL::storeData(oDataInterface odi, const Row &row, unsigned long &revision) { + //errorMessage.clear(); + list varint; + list varstring; + bool success=true; + bool updated = false; + try{ + odi.getVariableInt(varint); + list::iterator it_int; + for(it_int=varint.begin(); it_int!=varint.end(); it_int++) { + if (it_int->data32) { + int val = int(row[it_int->name]); + + if (val != *(it_int->data32)) { + *(it_int->data32) = val; + updated = true; + } + } + else { + __int64 val = row[it_int->name].operator mysqlpp::ulonglong(); + __int64 oldVal = *(it_int->data64); + if (val != oldVal) { + memcpy(it_int->data64, &val, 8); + updated = true; + } + + } + } + } + catch (const BadFieldName&) { + success=false; + } + + try { + odi.getVariableString(varstring); + list::iterator it_string; + for(it_string=varstring.begin(); it_string!=varstring.end(); it_string++) { + if (it_string->store(row[it_string->name].c_str())) + updated = true; + } + } + catch(const BadFieldName&){ + success=false; + } + + // Mark all data as stored in memory + odi.allDataStored(); + + if (updated) + revision++; + + return success; +} + +OpFailStatus MeosSQL::SyncRead(oEvent *oe) { + OpFailStatus retValue = opStatusOK; + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!oe || !con.connected()) + return opStatusFail; + + if (oe->HasDBConnection) { + //We already have established connectation, and just want to sync data. + return SyncEvent(oe); + } + warnedOldVersion=false; + + if (!oe->Id) return SyncUpdate(oe); + + ProgressWindow pw(oe->hWnd()); + + try { + con.select_db("MeOSMain"); + + Query query = con.query(); + query << "SELECT * FROM oEvent WHERE Id=" << oe->Id; + Result res = query.store(); + + Row row; + if (row=res.at(0)){ + oe->Name = row["Name"]; + oe->Annotation = row["Annotation"]; + oe->Date = row["Date"]; + oe->ZeroTime = row["ZeroTime"]; + strcpy_s(oe->CurrentNameId, row["NameId"].c_str()); + } + + con.select_db(CmpDataBase); + } + catch (const mysqlpp::Exception& er){ + setDefaultDB(); + alert(string(er.what())+" [SYNCREAD oEvent]"); + return opStatusFail; + } + + Query query = con.query(); + + int nRunner = 0; + int nCard = 0; + int nTeam = 0; + int nClubDB = 0; + int nRunnerDB = 0; + + int nSum = 1; + + try { + mysqlpp::Result cnt = query.store("SELECT COUNT(*) FROM dbClub"); + nClubDB = cnt.at(0).at(0); + + cnt = query.store("SELECT COUNT(*) FROM dbRunner"); + nRunnerDB = cnt.at(0).at(0); + + string time = oe->runnerDB->getDataDate(); + + cnt = query.store("SELECT COUNT(*) FROM dbClub WHERE Modified>'" + time + "'"); + int modclub = cnt.at(0).at(0); + cnt = query.store("SELECT COUNT(*) FROM dbRunner WHERE Modified>'" + time + "'"); + int modrunner = cnt.at(0).at(0); + + bool skipDB = modclub==0 && modrunner==0 && nClubDB == oe->runnerDB->getClubDB().size() && + nRunnerDB == oe->runnerDB->getRunnerDB().size(); + + if (skipDB) { + nClubDB = 0; + nRunnerDB = 0; + } + + cnt = query.store("SELECT COUNT(*) FROM oRunner"); + nRunner = cnt.at(0).at(0); + + cnt = query.store("SELECT COUNT(*) FROM oCard"); + nCard = cnt.at(0).at(0); + + cnt = query.store("SELECT COUNT(*) FROM oTeam"); + nTeam = cnt.at(0).at(0); + + nSum = nClubDB + nRunnerDB + nRunner + nTeam + nCard + 50; + + if (nSum > 400) + pw.init(); + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD INFO]"); + return opStatusFail; + } + + int pStart = 0, pPart = 50; + + try { + //Update oEvent + query << "SELECT * FROM oEvent"; + Result res = query.store(); + + Row row; + if (row=res.at(0)) { + oe->Name = row["Name"]; + oe->Annotation = row["Annotation"]; + oe->Date = row["Date"]; + oe->ZeroTime = row["ZeroTime"]; + strcpy_s(oe->CurrentNameId, row["NameId"].c_str()); + oe->sqlUpdated = row["Modified"]; + oe->counter = row["Counter"]; + + if (checkOldVersion(oe, row)) { + warnOldDB(); + retValue = opStatusWarning; + } + + const string &lRaw = row.raw_string(res.field_num("Lists")); + try { + importLists(oe, lRaw.c_str()); + } + catch (std::exception &ex) { + alert(ex.what()); + retValue = opStatusWarning; + } + + oDataInterface odi=oe->getDI(); + storeData(odi, row, oe->dataRevision); + oe->changed = false; + oe->setCurrency(-1, "", "", false); // Set currency tmp data + oe->getMeOSFeatures().deserialize(oe->getDCI().getString("Features"), *oe); + } + } + catch (const EndOfResults& ) { + errorMessage = "Unexpected error, oEvent table was empty"; + return opStatusFail; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Club]"); + return opStatusFail; + } + + pw.setProgress(20); + + try { + ResUse res = query.use("SELECT * FROM oClub WHERE Removed=0"); + + // Retreive result rows one by one. + if (res){ + // Get each row in result set. + Row row; + + while (row = res.fetch_row()) { + oClub c(oe, row["Id"]); + storeClub(row, c); + oe->addClub(c); + + oe->sqlUpdateClubs = max(c.sqlUpdated, oe->sqlUpdateClubs); + oe->sqlCounterClubs = max(c.counter, oe->sqlCounterClubs); + } + } + } + catch (const EndOfResults&) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Club]"); + return opStatusFail; + } + + pw.setProgress(30); + + oe->sqlCounterControls=0; + try { + ResUse res = query.use("SELECT * FROM oControl WHERE Removed=0"); + + if (res) { + // Get each row in result set. + Row row; + + while (row = res.fetch_row()) { + oControl c(oe, row["Id"]); + storeControl(row, c); + oe->Controls.push_back(c); + + oe->sqlUpdateControls = max(c.sqlUpdated, oe->sqlUpdateControls); + oe->sqlCounterControls = max(c.counter, oe->sqlCounterControls); + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Control]"); + return opStatusFail; + } + + oe->sqlCounterCourses = 0; + pw.setProgress(40); + + try{ + ResUse res = query.use("SELECT * FROM oCourse WHERE Removed=0"); + + if (res){ + // Get each row in result set. + Row row; + set tmp; + while (row = res.fetch_row()) { + oCourse c(oe, row["Id"]); + storeCourse(row, c, tmp); + oe->addCourse(c); + + oe->sqlUpdateCourses = max(c.sqlUpdated, oe->sqlUpdateCourses); + oe->sqlCounterCourses = max(c.counter, oe->sqlCounterCourses); + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Course]"); + return opStatusFail; + } + + pw.setProgress(50); + + oe->sqlCounterClasses = 0; + try{ + ResUse res = query.use("SELECT * FROM oClass WHERE Removed=0"); + + if (res) { + Row row; + while (row = res.fetch_row()) { + oClass c(oe, row["Id"]); + storeClass(row, c, false); + + c.changed = false; + c.reChanged = false; + oe->addClass(c); + + oe->sqlUpdateClasses = max(c.sqlUpdated, oe->sqlUpdateClasses); + oe->sqlCounterClasses = max(c.counter, oe->sqlCounterClasses); + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Class]"); + return opStatusFail; + } + + oe->sqlCounterCards=0; + + try{ + ResUse res = query.use("SELECT * FROM oCard WHERE Removed=0"); + int counter = 0; + pStart += pPart; + pPart = (1000 * nCard) / nSum; + + if (res){ + Row row; + while (row = res.fetch_row()) { + oCard c(oe, row["Id"]); + storeCard(row, c); + oe->addCard(c); + assert(!c.changed); + + oe->sqlCounterCards = max(c.counter, oe->sqlCounterCards); + oe->sqlUpdateCards = max(c.sqlUpdated, oe->sqlUpdateCards); + + if (++counter % 100 == 50) + pw.setProgress(pStart + (counter * pPart) / nCard); + } + } + + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Card]"); + return opStatusFail; + } + + oe->sqlCounterRunners = 0; + try{ + ResUse res = query.use("SELECT * FROM oRunner WHERE Removed=0"); + int counter = 0; + pStart += pPart; + pPart = (1000 * nRunner) / nSum; + + if (res){ + Row row; + while (row = res.fetch_row()) { + oRunner r(oe, row["Id"]); + storeRunner(row, r, false, false, false); + assert(!r.changed); + oe->addRunner(r, false); + + oe->sqlUpdateRunners = max(r.sqlUpdated, oe->sqlUpdateRunners); + oe->sqlCounterRunners = max(r.counter,oe->sqlCounterRunners); + + if (++counter % 100 == 50) + pw.setProgress(pStart + (counter * pPart) / nRunner); + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Runner]"); + return opStatusFail; + } + + oe->sqlCounterTeams=0; + + try{ + ResUse res = query.use("SELECT * FROM oTeam WHERE Removed=0"); + int counter = 0; + pStart += pPart; + pPart = (1000 * nTeam) / nSum; + + if (res){ + Row row; + while (row = res.fetch_row()) { + oTeam t(oe, row["Id"]); + + storeTeam(row, t, false); + + pTeam at = oe->addTeam(t, false); + + if (at) { + at->apply(false, 0, true); + at->changed = false; + for (size_t k = 0; kRunners.size(); k++) { + if (at->Runners[k]) { + assert(!at->Runners[k]->changed); + at->Runners[k]->changed = false; + } + } + } + oe->sqlUpdateTeams = max(t.sqlUpdated, oe->sqlUpdateTeams); + oe->sqlCounterTeams = max(t.counter, oe->sqlCounterTeams); + + if (++counter % 100 == 50) + pw.setProgress(pStart + (counter * pPart) / nTeam); + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oEvent/Team]"); + return opStatusFail; + } + + string dateTime; + try { + if (nClubDB == 0 && nRunnerDB == 0) + return retValue; // Not modified + + Result cnt; + // Note dbRunner is stored after dbClub + if (nRunnerDB>0) + cnt = query.store("SELECT DATE_FORMAT(MAX(Modified),'%Y-%m-%d %H:%i:%s') FROM dbRunner"); + else + cnt = query.store("SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s')"); + + dateTime = cnt.at(0).at(0); + + oe->runnerDB->prepareLoadFromServer(nRunnerDB, nClubDB); + + ResUse res = query.use("SELECT * FROM dbClub"); + int counter = 0; + pStart += pPart; + pPart = (1000 * nClubDB) / nSum; + + if (res) { + Row row; + while (row = res.fetch_row()) { + oClub t(oe, row["Id"]); + + string n = row["Name"]; + t.internalSetName(n); + storeData(t.getDI(), row, oe->dataRevision); + + oe->runnerDB->addClub(t, false); + + if (++counter % 100 == 50) + pw.setProgress(pStart + (counter * pPart) / nClubDB); + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD dbClub]"); + return opStatusFail; + } + + try { + ResUse res = query.use("SELECT * FROM dbRunner"); + int counter = 0; + pStart += pPart; + pPart = (1000 * nRunnerDB) / nSum; + + if (res) { + Row row; + while (row = res.fetch_row()) { + string name = row["Name"]; + string ext = row["ExtId"]; + string club = row["Club"]; + string card = row["CardNo"]; + string sex = row["Sex"]; + string nat = row["Nation"]; + string birth = row["BirthYear"]; + RunnerDBEntry *db = oe->runnerDB->addRunner(name.c_str(), _atoi64(ext.c_str()), + atoi(club.c_str()), atoi(card.c_str())); + if (db) { + if (sex.length()==1) + db->sex = sex[0]; + db->birthYear = short(atoi(birth.c_str())); + + if (nat.length()==3) { + db->national[0] = nat[0]; + db->national[1] = nat[1]; + db->national[2] = nat[2]; + } + } + + if (++counter % 100 == 50) + pw.setProgress(pStart + (counter * pPart) / nRunnerDB); + + } + } + } + catch (const EndOfResults& ) { + } + catch (const mysqlpp::Exception& er) { + alert(string(er.what())+" [SYNCREAD dbRunner]"); + return opStatusFail; + } + + oe->runnerDB->setDataDate(dateTime); + + return retValue; +} + +void MeosSQL::storeClub(const Row &row, oClub &c) +{ + string n = row["Name"]; + c.internalSetName(n); + + c.sqlUpdated = row["Modified"]; + c.counter = row["Counter"]; + c.Removed = row["Removed"]; + + c.oe->sqlChangedClubs = true; + c.changedObject(); + + synchronized(c); + storeData(c.getDI(), row, c.oe->dataRevision); +} + +void MeosSQL::storeControl(const Row &row, oControl &c) +{ + c.Name = row["Name"]; + c.setNumbers(string(row["Numbers"])); + oControl::ControlStatus oldStat = c.Status; + c.Status = oControl::ControlStatus(int(row["Status"])); + + c.sqlUpdated = row["Modified"]; + c.counter = row["Counter"]; + c.Removed = row["Removed"]; + + c.oe->sqlChangedControls = true; + if (c.changed || oldStat != c.Status) { + c.oe->dataRevision++; + c.changed = false; + } + + c.changedObject(); + + synchronized(c); + storeData(c.getDI(), row, c.oe->dataRevision); +} + +void MeosSQL::storeCard(const Row &row, oCard &c) +{ + c.cardNo = row["CardNo"]; + c.readId = row["ReadId"]; + c.importPunches(string(row["Punches"])); + + c.sqlUpdated = row["Modified"]; + c.counter = row["Counter"]; + c.Removed = row["Removed"]; + + pRunner r = c.getOwner(); + if (r) { + r->sqlChanged = true; + } + c.changedObject(); + synchronized(c); + c.oe->sqlChangedCards = true; +} + +void MeosSQL::storePunch(const Row &row, oFreePunch &p, bool rehash) +{ + if (rehash) { + p.setCardNo(row["CardNo"], true); + p.setTimeInt(row["Time"], true); + p.setType(string(row["Type"]), true); + } + else { + p.CardNo = row["CardNo"]; + p.Time = row["Time"]; + p.Type = row["Type"]; + } + + p.sqlUpdated = row["Modified"]; + p.counter = row["Counter"]; + p.Removed = row["Removed"]; + + p.changedObject(); + synchronized(p); + p.oe->sqlChangedPunches = true; +} + +OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c, + bool readCourses) +{ + OpFailStatus success = opStatusOK; + + c.Name=row["Name"]; + string multi = row["MultiCourse"]; + + string lm(row["LegMethod"]); + c.importLegMethod(lm); + + set cid; + vector< vector > multip; + oClass::parseCourses(multi, multip, cid); + int classCourse = row["Course"]; + if (classCourse != 0) + cid.insert(classCourse); + if (!readCourses) { + for (set::iterator clsIt = cid.begin(); clsIt != cid.end(); ++clsIt) { + if (!c.oe->getCourse(*clsIt)) + readCourses = true; // There are missing courses. Force read. + } + } + + if (readCourses) + success = min(success, syncReadClassCourses(&c, cid, readCourses)); + if (classCourse != 0) + c.Course = c.oe->getCourse(classCourse); + else + c.Course = 0; + + c.importCourses(multip); + + c.sqlUpdated = row["Modified"]; + c.counter = row["Counter"]; + c.Removed = row["Removed"]; + + storeData(c.getDI(), row, c.oe->dataRevision); + + c.changed = false; + + c.changedObject(); + c.oe->sqlChangedClasses = true; + synchronized(c); + return success; +} + +OpFailStatus MeosSQL::storeCourse(const Row &row, oCourse &c, + set &readControls) +{ + OpFailStatus success = opStatusOK; + + c.Name = row["Name"]; + c.importControls(string(row["Controls"]), false); + c.Length = row["Length"]; + c.importLegLengths(string(row["Legs"]), false); + + for (int i=0;iexistInDB()) { + c.Controls[i]->changed = false; + success = min(success, syncRead(true, c.Controls[i])); + } + else + readControls.insert(c.Controls[i]->getId()); + //success = min(success, syncRead(false, c.Controls[i])); + } + } + + c.sqlUpdated = row["Modified"]; + c.counter = row["Counter"]; + c.Removed = row["Removed"]; + + storeData(c.getDI(), row, c.oe->dataRevision); + c.oe->dataRevision++; + c.changed = false; + c.changedObject(); + c.oe->sqlChangedCourses = true; + synchronized(c); + return success; +} + +OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, + bool readCourseCard, + bool readClassClub, + bool readRunners) +{ + OpFailStatus success = opStatusOK; + oEvent *oe=r.oe; + + // Mark old class as changed + if (r.Class) + r.markClassChanged(-1); + + int oldSno = r.StartNo; + const string &oldBib = r.getBib(); + + r.sName = row["Name"]; + oRunner::getRealName(r.sName, r.tRealName); + r.setCardNo(row["CardNo"], false, true); + r.StartNo = row["StartNo"]; + r.tStartTime = r.startTime = row["StartTime"]; + r.FinishTime = row["FinishTime"]; + r.tStatus = r.status = RunnerStatus(int(row["Status"])); + + r.inputTime = row["InputTime"]; + r.inputPoints = row["InputPoints"]; + r.inputStatus = RunnerStatus(int(row["InputStatus"])); + r.inputPlace = row["InputPlace"]; + + r.Removed = row["Removed"]; + r.sqlUpdated = row["Modified"]; + r.counter = row["Counter"]; + + storeData(r.getDI(), row, oe->dataRevision); + + if (oldSno != r.StartNo || oldBib != r.getBib()) + oe->bibStartNoToRunnerTeam.clear(); // Clear quick map (lazy setup) + + if (int(row["Course"])!=0) { + r.Course = oe->getCourse(int(row["Course"])); + set controlIds; + if (!r.Course) { + oCourse oc(oe, row["Course"]); + success = min(success, syncReadCourse(true, &oc, controlIds)); + r.Course = oe->addCourse(oc); + } + else if (readCourseCard) + success = min(success, syncReadCourse(false, r.Course, controlIds)); + + if (readCourseCard) + success = min(success, syncReadControls(oe, controlIds)); + } + else r.Course=0; + + if (int(row["Class"])!=0) { + r.Class=oe->getClass(int(row["Class"])); + + if (!r.Class) { + oClass oc(oe, row["Class"]); + success = min(success, syncRead(true, &oc, readClassClub)); + r.Class = oe->addClass(oc); + } + else if (readClassClub) + success = min(success, syncRead(false, r.Class, true)); + + if (r.tInTeam && r.tInTeam->Class!=r.Class) + r.tInTeam = 0; //Temporaraly disable belonging. Restored on next apply. + } + else r.Class=0; + + if (int(row["Club"])!=0){ + r.Club = oe->getClub(int(row["Club"])); + + if (!r.Club) { + oClub oc(oe, row["Club"]); + success = min(success, syncRead(true, &oc)); + r.Club = oe->addClub(oc); + } + else if (readClassClub) + success = min(success, syncRead(false, r.Club)); + } + else r.Club=0; + + pCard oldCard = r.Card; + + if (int(row["Card"])!=0) { + r.Card = oe->getCard(int(row["Card"])); + + if (!r.Card){ + oCard oc(oe, row["Card"]); + oe->Cards.push_back(oc); + r.Card = &oe->Cards.back(); + r.Card->changed = false; + success = min(success, syncRead(true, r.Card)); + } + else if (readCourseCard) + success = min(success, syncRead(false, r.Card)); + } + else r.Card=0; + + // Update card ownership + if (oldCard && oldCard != r.Card && oldCard->tOwner == &r) + oldCard->tOwner = 0; + + // This is updated by addRunner if this is a temporary copy. + if (r.Card) + r.Card->tOwner=&r; + + // This only loads indexes + r.decodeMultiR(string(row["MultiR"])); + + // We now load/reload required other runners. + if (readRunners) { + for (size_t i=0;i0) { + pRunner pr = oe->getRunner(rid, 0); + if (pr==0) { + oRunner or(oe, rid); + success = min(success, syncRead(true, &or, false, readCourseCard)); + pr = oe->addRunner(or, false); + } + else + success = min(success, syncRead(false, pr, false, readCourseCard)); + } + } + } + + // Mark new class as changed + r.changedObject(); + r.sqlChanged = true; + r.oe->sqlChangedRunners = true; + + synchronized(r); + return success; +} + +OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t, + bool readRecursive) +{ + oEvent *oe=t.oe; + OpFailStatus success = opStatusOK; + + // Mark old class as changed + if (t.Class) + t.Class->markSQLChanged(-1,-1); + + int oldSno = t.StartNo; + const string &oldBib = t.getBib(); + + t.sName=row["Name"]; + t.StartNo=row["StartNo"]; + t.tStartTime = t.startTime = row["StartTime"]; + t.FinishTime=row["FinishTime"]; + t.tStatus = t.status = RunnerStatus(int(row["Status"])); + storeData(t.getDI(), row, oe->dataRevision); + + if (oldSno != t.StartNo || oldBib != t.getBib()) + oe->bibStartNoToRunnerTeam.clear(); // Clear quick map (lazy setup) + + t.Removed = row["Removed"]; + if (t.Removed) + t.prepareRemove(); + + t.sqlUpdated = row["Modified"]; + t.counter = row["Counter"]; + + if (!t.Removed) { + int classId = row["Class"]; + if (classId!=0) { + t.Class = oe->getClass(classId); + + if (!t.Class) { + oClass oc(oe, classId); + success = min(success, syncRead(true, &oc, readRecursive)); + t.Class = oe->addClass(oc); + } + else if (readRecursive) + success = min(success, syncRead(false, t.Class, readRecursive)); + } + else t.Class=0; + + int clubId = row["Club"]; + if (clubId!=0) { + t.Club=oe->getClub(clubId); + + if (!t.Club) { + oClub oc(oe, clubId); + success = min(success, syncRead(true, &oc)); + t.Club = oe->addClub(oc); + } + else if (readRecursive) + success = min(success, syncRead(false, t.Club)); + } + else t.Club = 0; + + vector rns; + vector pRns; + t.decodeRunners(static_cast(row["Runners"]), rns); + + pRns.resize(rns.size()); + for (size_t k=0;k0) { + pRns[k] = oe->getRunner(rns[k], 0); + + if (!pRns[k]) { + oRunner or(oe, rns[k]); + success = min(success, syncRead(true, &or, readRecursive, readRecursive)); + + if (or.sName.empty()) { + or.sName = "@AutoCorrection"; + oRunner::getRealName(or.sName, or.tRealName); + } + pRns[k] = oe->addRunner(or, false); + assert(pRns[k] && !pRns[k]->changed); + } + else if (readRecursive) + success = min(success, syncRead(false, pRns[k])); + } + } + t.importRunners(pRns); + } + + // Mark new class as changed. + if (t.Class) + t.Class->markSQLChanged(-1,-1); + + t.sqlChanged = true; + t.oe->sqlChangedTeams = true; + synchronized(t); + return success; +} + +bool MeosSQL::Remove(oBase *ob) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return false; + + if (!ob || !con.connected()) + return false; + + if (!ob->Id) + return true; //Not in DB. + + Query query = con.query(); + + string oTable; + + if (typeid(*ob)==typeid(oRunner)){ + oTable="oRunner"; + } + else if (typeid(*ob)==typeid(oClass)){ + oTable="oClass"; + } + else if (typeid(*ob)==typeid(oCourse)){ + oTable="oCourse"; + } + else if (typeid(*ob)==typeid(oControl)){ + oTable="oControl"; + } + else if (typeid(*ob)==typeid(oClub)){ + oTable="oClub"; + } + else if (typeid(*ob)==typeid(oCard)){ + oTable="oCard"; + } + else if (typeid(*ob)==typeid(oFreePunch)){ + oTable="oPunch"; + } + else if (typeid(*ob)==typeid(oTeam)){ + oTable="oTeam"; + } + else if (typeid(*ob)==typeid(oEvent)){ + oTable="oEvent"; + //Must change db! + return 0; + } + + query << "Removed=1"; + try{ + ResNSel res = updateCounter(oTable.c_str(), ob->Id, &query); + ob->Removed = true; + ob->changed = false; + ob->reChanged = false; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [REMOVE " +oTable +"]"); + return false; + } + + return true; +} + + +OpFailStatus MeosSQL::syncUpdate(oRunner *r, bool forceWriteAll) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!r || !con.connected()) + return opStatusFail; + + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << r->sName << ", " + << " CardNo=" << r->CardNo << ", " + << " StartNo=" << r->StartNo << ", " + << " StartTime=" << r->startTime << ", " + << " FinishTime=" << r->FinishTime << ", " + << " Course=" << r->getCourseId() << ", " + << " Class=" << r->getClassId() << ", " + << " Club=" << r->getClubId() << ", " + << " Card=" << r->getCardId() << ", " + << " Status=" << r->status << ", " + << " InputTime=" << r->inputTime << ", " + << " InputStatus=" << r->inputStatus << ", " + << " InputPoints=" << r->inputPoints << ", " + << " InputPlace=" << r->inputPlace << ", " + << " MultiR=" << quote << r->codeMultiR() + << r->getDI().generateSQLSet(forceWriteAll); + + + string str = "write runner " + r->sName + ", st = " + itos(r->startTime) + "\n"; + OutputDebugString(str.c_str()); + + return syncUpdate(queryset, "oRunner", r); +} + +bool MeosSQL::isOld(int counter, const string &time, oBase *ob) +{ + return counter>ob->counter || time>ob->sqlUpdated; +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r) +{ + return syncRead(forceRead, r, true, true); +} + +string MeosSQL::andWhereOld(oBase *ob) { + return " AND (Counter!=" + itos(ob->counter) + " OR Modified!='" + ob->sqlUpdated + "')"; +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r, bool readClassClub, bool readCourseCard) +{ + errorMessage.clear(); + if (CmpDataBase.empty()) + return opStatusFail; + + if (!r || !con.connected()) + return opStatusFail; + + if (!forceRead && !r->existInDB()) + return syncUpdate(r, true); + + if (!r->changed && skipSynchronize(*r)) + return opStatusOK; + + try { + Query query = con.query(); + query << "SELECT * FROM oRunner WHERE Id=" << r->Id << andWhereOld(r); + Result res = query.store(); + + Row row; + if (!res.empty()) { + row=res.at(0); + // Remotly changed update! + OpFailStatus success=opStatusOK; + if (r->changed) + success=opStatusWarning; + + success = min (success, storeRunner(row, *r, readCourseCard, readClassClub, true)); + + r->oe->dataRevision++; + r->Modified.update(); + r->changed = false; + + vector mp; + r->evaluateCard(true, mp, 0, false); + + //Forget evaluated changes. Not our buisness to update. + r->changed = false; + + return success; + } + else { + if (r->Card && readCourseCard) + syncRead(false, r->Card); + if (r->Class && readClassClub) + syncRead(false, r->Class, readClassClub); + if (r->Course && readCourseCard) { + set controlIds; + syncReadCourse(false, r->Course, controlIds); + if (readClassClub) + syncReadControls(r->oe, controlIds); + } + if (r->Club && readClassClub) + syncRead(false, r->Club); + + if (r->changed) + return syncUpdate(r, false); + + vector mp; + r->evaluateCard(true, mp, 0, false); + r->changed = false; + r->reChanged = false; + return opStatusOK; + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oRunner]"); + return opStatusFail; + } + + return opStatusFail; +} + +OpFailStatus MeosSQL::syncUpdate(oCard *c, bool forceWriteAll) +{ + errorMessage.clear(); + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + mysqlpp::Query queryset = con.query(); + queryset << " CardNo=" << c->cardNo << ", " + << " ReadId=" << c->readId << ", " + << " Punches=" << quote << c->getPunchString(); + + return syncUpdate(queryset, "oCard", c); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oCard *c) +{ + errorMessage.clear(); + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + if (!forceRead && !c->existInDB()) + return syncUpdate(c, true); + + if (!c->changed && skipSynchronize(*c)) + return opStatusOK; + + try{ + Query query = con.query(); + query << "SELECT * FROM oCard WHERE Id=" << c->Id; + Result res = query.store(); + + Row row; + if (!res.empty()){ + row=res.at(0); + if (!c->changed || isOld(row["Counter"], string(row["Modified"]), c)){ + + OpFailStatus success=opStatusOK; + if (c->changed) + success=opStatusWarning; + + storeCard(row, *c); + c->oe->dataRevision++; + c->Modified.update(); + c->changed=false; + return success; + } + else if (c->changed){ + return syncUpdate(c, false); + } + } + else{ + //Something is wrong!? Deleted? + return syncUpdate(c, true); + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oCard]"); + return opStatusFail; + } + + return opStatusFail; +} + + +OpFailStatus MeosSQL::syncUpdate(oTeam *t, bool forceWriteAll) { + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!t || !con.connected()) + return opStatusFail; + + mysqlpp::Query queryset = con.query(); + + queryset << " Name=" << quote << t->sName << ", " + << " Runners=" << quote << t->getRunners() << ", " + << " StartTime=" << t->startTime << ", " + << " FinishTime=" << t->FinishTime << ", " + << " Class=" << t->getClassId() << ", " + << " Club=" << t->getClubId() << ", " + << " StartNo=" << t->getStartNo() << ", " + << " Status=" << t->status + << t->getDI().generateSQLSet(forceWriteAll); + + string str = "write team " + t->sName + "\n"; + OutputDebugString(str.c_str()); + return syncUpdate(queryset, "oTeam", t); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t) +{ + return syncRead(forceRead, t, true); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t, bool readRecursive) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!t || !con.connected()) + return opStatusFail; + + if (!forceRead && !t->existInDB()) + return syncUpdate(t, true); + + if (!t->changed && skipSynchronize(*t)) + return opStatusOK; + + try{ + Query query = con.query(); + query << "SELECT * FROM oTeam WHERE Id=" << t->Id << andWhereOld(t); + Result res = query.store(); + + Row row; + if (!res.empty()) { + row=res.at(0); + + OpFailStatus success=opStatusOK; + if (t->changed) + success=opStatusWarning; + + storeTeam(row, *t, readRecursive); + t->oe->dataRevision++; + t->Modified.update(); + t->changed = false; + t->reChanged = false; + return success; + } + else { + OpFailStatus success = opStatusOK; + + if (readRecursive) { + if (t->Class) + success = min(success, syncRead(false, t->Class, readRecursive)); + if (t->Club) + success = min(success, syncRead(false, t->Club)); + for (size_t k = 0; kRunners.size(); k++) { + if (t->Runners[k]) + success = min(success, syncRead(false, t->Runners[k], false, readRecursive)); + } + } + if (t->changed) + return min(success, syncUpdate(t, false)); + else + return success; + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oTeam]"); + return opStatusFail; + } + + return opStatusFail; +} + +OpFailStatus MeosSQL::syncUpdate(oClass *c, bool forceWriteAll) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + mysqlpp::Query queryset = con.query(); + + queryset << " Name=" << quote << c->Name << "," + << " Course=" << c->getCourseId() << "," + << " MultiCourse=" << quote << c->codeMultiCourse() << "," + << " LegMethod=" << quote << c->codeLegMethod() + << c->getDI().generateSQLSet(forceWriteAll); + + return syncUpdate(queryset, "oClass", c); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oClass *c) +{ + return syncRead(forceRead, c, true); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oClass *c, bool readCourses) +{ + errorMessage.clear(); + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + if (!forceRead && !c->existInDB()) + return syncUpdate(c, true); + + if (!c->changed && skipSynchronize(*c)) + return opStatusOK; + + try { + Query query = con.query(); + query << "SELECT * FROM oClass WHERE Id=" << c->Id << andWhereOld(c); + Result res = query.store(); + + Row row; + if (!res.empty()){ + row=res.at(0); + OpFailStatus success = opStatusOK; + + if (c->changed) + success=opStatusWarning; + + storeClass(row, *c, readCourses); + c->oe->dataRevision++; + c->Modified.update(); + c->changed = false; + c->reChanged = false; + return opStatusOK; + } + else { + OpFailStatus success = opStatusOK; + if (readCourses) { + set d; + c->getMCourseIdSet(d); + if (c->getCourseId() != 0) + d.insert(c->getCourseId()); + success = syncReadClassCourses(c, d, true); + } + + if (c->changed && !forceRead) + success = min(success, syncUpdate(c, false)); + + return success; + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oClass]"); + return opStatusFail; + } + + return opStatusFail; +} + +OpFailStatus MeosSQL::syncReadClassCourses(oClass *c, const set &courses, + bool readRecursive) { + OpFailStatus success = opStatusOK; + if (courses.empty()) + return success; + oEvent *oe = c->oe; + try { + Query query = con.query(); + string in; + for(set::const_iterator it=courses.begin(); it!=courses.end(); ++it) { + if (!in.empty()) + in += ","; + in += itos(*it); + } + query << "SELECT Id, Counter, Modified FROM oCourse WHERE Id IN (" << in << ")"; + Result res = query.store(); + set processedCourses(courses); + set controlIds; + for (size_t k = 0; k < res.size(); k++) { + Row row = res.at(k); + int id = row["Id"]; + int counter = row["Counter"]; + string modified = row["Modified"]; + + pCourse pc = oe->getCourse(id); + if (!pc) { + oCourse oc(oe, id); + success = min(success, syncReadCourse(true, &oc, controlIds)); + oe->addCourse(oc); + } + else if (pc->changed || isOld(counter, modified, pc)) { + success = min(success, syncReadCourse(false, pc, controlIds)); + } + else { + for (int m = 0; m nControls; m++) + if (pc->Controls[m]) + controlIds.insert(pc->Controls[m]->getId()); + } + processedCourses.erase(id); + } + + // processedCourses should now be empty. The only change it is not empty is that + // there are locally added courses that are not on the server (which is an error). + for(set::iterator it = processedCourses.begin(); it != processedCourses.end(); ++it) { + assert(false); + pCourse pc = oe->getCourse(*it); + if (pc) { + success = min(success, syncUpdate(pc, true)); + } + } + + if (readRecursive) + success = min(success, syncReadControls(oe, controlIds)); + + return success; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oClassCourse]"); + return opStatusFail; + } +} + +OpFailStatus MeosSQL::syncReadControls(oEvent *oe, const set &controls) { + OpFailStatus success = opStatusOK; + if (controls.empty()) + return success; + try { + Query query = con.query(); + string in; + for(set::const_iterator it=controls.begin(); it!=controls.end(); ++it) { + if (!in.empty()) + in += ","; + in += itos(*it); + } + query << "SELECT Id, Counter, Modified FROM oControl WHERE Id IN (" << in << ")"; + Result res = query.store(); + set processedControls(controls); + for (size_t k = 0; k < res.size(); k++) { + Row row = res.at(k); + int id = row["Id"]; + int counter = row["Counter"]; + string modified = row["Modified"]; + + pControl pc = oe->getControl(id, false); + if (!pc) { + oControl oc(oe, id); + success = min(success, syncRead(true, &oc)); + oe->addControl(oc); + } + else if (pc->changed || isOld(counter, modified, pc)) { + success = min(success, syncRead(false, pc)); + } + processedControls.erase(id); + } + + // processedCourses should now be empty, unless there are local controls not yet added. + for(set::iterator it = processedControls.begin(); it != processedControls.end(); ++it) { + pControl pc = oe->getControl(*it, false); + if (pc) { + success = min(success, syncUpdate(pc, true)); + } + } + + return success; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oClass]"); + return opStatusFail; + } +} + + +OpFailStatus MeosSQL::syncUpdate(oClub *c, bool forceWriteAll) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << c->name + << c->getDI().generateSQLSet(forceWriteAll); + + return syncUpdate(queryset, "oClub", c); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oClub *c) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + if (!forceRead && !c->existInDB()) + return syncUpdate(c, true); + + try{ + Query query = con.query(); + query << "SELECT * FROM oClub WHERE Id=" << c->Id; + Result res = query.store(); + + Row row; + if (!res.empty()){ + row=res.at(0); + if (!c->changed || isOld(row["Counter"], string(row["Modified"]), c)) { + + OpFailStatus success = opStatusOK; + if (c->changed) + success = opStatusWarning; + + storeClub(row, *c); + + c->Modified.update(); + c->changed=false; + return success; + } + else if (c->changed){ + return syncUpdate(c, false); + } + } + else{ + //Something is wrong!? Deleted? + return syncUpdate(c, true); + } + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oClub]"); + return opStatusFail; + } + + return opStatusFail; +} + +OpFailStatus MeosSQL::syncUpdate(oControl *c, bool forceWriteAll) { + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << c->Name << ", " + << " Numbers=" << quote << c->codeNumbers() << "," + << " Status=" << c->Status + << c->getDI().generateSQLSet(forceWriteAll); + + return syncUpdate(queryset, "oControl", c); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oControl *c) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + if (!forceRead && !c->existInDB()) + return syncUpdate(c, true); + + try{ + Query query = con.query(); + query << "SELECT * FROM oControl WHERE Id=" << c->Id << andWhereOld(c); + Result res = query.store(); + + Row row; + if (!res.empty()){ + row=res.at(0); + + OpFailStatus success=opStatusOK; + if (c->changed) + success=opStatusWarning; + + storeControl(row, *c); + c->oe->dataRevision++; + c->Modified.update(); + c->changed=false; + return success; + } + else if (c->changed) { + return syncUpdate(c, false); + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oControl]"); + return opStatusFail; + } + return opStatusFail; +} + +OpFailStatus MeosSQL::syncUpdate(oCourse *c, bool forceWriteAll) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + bool isTMP = c->sqlUpdated == "TMP"; + assert(!isTMP); + if (isTMP) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << c->Name << ", " + << " Length=" << unsigned(c->Length) << ", " + << " Controls=" << quote << c->getControls() << ", " + << " Legs=" << quote << c->getLegLengths() + << c->getDI().generateSQLSet(true); + + return syncUpdate(queryset, "oCourse", c); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oCourse *c) +{ + set controls; + OpFailStatus res = syncReadCourse(forceRead, c, controls); + res = min( res, syncReadControls(c->oe, controls)); + return res; +} + +OpFailStatus MeosSQL::syncReadCourse(bool forceRead, oCourse *c, set &readControls) { + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + bool isTMP = c->sqlUpdated == "TMP"; + assert(!isTMP); + if (isTMP) + return opStatusFail; + + if (!forceRead && !c->existInDB()) + return syncUpdate(c, true); + + if (!c->changed && skipSynchronize(*c)) + return opStatusOK; // Skipped readout + + try{ + Query query = con.query(); + query << "SELECT * FROM oCourse WHERE Id=" << c->Id << andWhereOld(c); + Result res = query.store(); + + Row row; + if (!res.empty()) { + row=res.at(0); + + OpFailStatus success = opStatusOK; + if (c->changed) + success = opStatusWarning; + + storeCourse(row, *c, readControls); + c->oe->dataRevision++; + c->Modified.update(); + c->changed=false; + c->reChanged=false; + return success; + } + else { + OpFailStatus success = opStatusOK; + + // Plain read controls + for (int i=0;inControls; i++) { + if (c->Controls[i]) + readControls.insert(c->Controls[i]->getId()); + //success = min(success, syncRead(false, c->Controls[i])); + } + + if (c->changed && !forceRead) + return min(success, syncUpdate(c, false)); + else + return success; + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oCourse]"); + return opStatusFail; + } + + return opStatusFail; +} + +OpFailStatus MeosSQL::syncUpdate(oFreePunch *c, bool forceWriteAll) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) { + errorMessage = "Not connected"; + return opStatusFail; + } + + if (!c || !con.connected()) { + errorMessage = "Not connected"; + return opStatusFail; + } + mysqlpp::Query queryset = con.query(); + queryset << " CardNo=" << c->CardNo << ", " + << " Type=" << c->Type << "," + << " Time=" << c->Time; + + return syncUpdate(queryset, "oPunch", c); +} + +OpFailStatus MeosSQL::syncRead(bool forceRead, oFreePunch *c, bool rehash) +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return opStatusFail; + + if (!c || !con.connected()) + return opStatusFail; + + if (!forceRead && !c->existInDB()) + return syncUpdate(c, true); + + if (!c->changed && skipSynchronize(*c)) + return opStatusOK; + + try{ + Query query = con.query(); + query << "SELECT * FROM oPunch WHERE Id=" << c->Id << andWhereOld(c); + Result res = query.store(); + + Row row; + if (!res.empty()) { + row=res.at(0); + OpFailStatus success = opStatusOK; + if (c->changed) + success = opStatusWarning; + + storePunch(row, *c, rehash); + c->oe->dataRevision++; + c->Modified.update(); + c->changed=false; + return success; + } + else if (c->changed) { + return syncUpdate(c, false); + } + + return opStatusOK; + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCREAD oPunch]"); + return opStatusFail; + } + return opStatusFail; +} + +OpFailStatus MeosSQL::updateTime(const char *oTable, oBase *ob) +{ + errorMessage.clear(); + + mysqlpp::Query query = con.query(); + + query << "SELECT Modified, Counter FROM " << oTable << " WHERE Id=" << ob->Id; + + mysqlpp::Result res = query.store(); + + if (!res.empty()) { + ob->sqlUpdated=res.at(0)["Modified"]; + ob->counter = res.at(0)["Counter"]; + ob->changed=false; //Mark as saved. + // Mark all data as stored in memory + if (ob->getDISize() >= 0) + ob->getDI().allDataStored(); + return opStatusOK; + } + else { + alert("Update time failed for " + string(oTable)); + return opStatusFail; + } +} + +static int nUpdate = 0; + +mysqlpp::ResNSel MeosSQL::updateCounter(const char *oTable, int id, mysqlpp::Query *updateqry) { + Query query = con.query(); + + try { + query.exec(string("LOCK TABLES ") + oTable + string(" WRITE")); + query << "SELECT MAX(Counter) FROM " << oTable; + int counter; + { + const mysqlpp::ColData c = query.store().at(0).at(0); + bool null = c.is_null(); + counter = null ? 1 : int(c) + 1; + } + query.reset(); + query << "UPDATE " << oTable << " SET Counter=" << counter; + + if (updateqry != 0) + query << "," << updateqry->str(); + + query << " WHERE Id=" << id; + + mysqlpp::ResNSel res = query.execute(); + + query.exec("UNLOCK TABLES"); + + query.reset(); + query << "UPDATE oCounter SET " << oTable << "=GREATEST(" << counter << "," << oTable << ")"; + query.execute(); + return res; + } + catch(...) { + query.exec("UNLOCK TABLES"); + throw; + } +} + + +OpFailStatus MeosSQL::syncUpdate(mysqlpp::Query &updateqry, + const char *oTable, oBase *ob) +{ + nUpdate++; + if (nUpdate % 100 == 99) + OutputDebugString((itos(nUpdate) +" updates\n").c_str()); + + assert(ob->getEvent()); + if (!ob->getEvent()) + return opStatusFail; + + if (ob->getEvent()->isReadOnly()) + return opStatusOK; + + errorMessage.clear(); + + if (!con.connected()) { + errorMessage = "Not connected"; + return opStatusFail; + } + + mysqlpp::Query query = con.query(); + try{ + if (!ob->existInDB()) { + bool setId = false; + + if (ob->Id > 0) { + query << "SELECT Id FROM " << oTable << " WHERE Id=" << ob->Id; + Result res=query.store(); + if (res && res.num_rows()==0) + setId = true; + } + + query.reset(); + query << "INSERT INTO " << oTable << " SET " << updateqry.str(); + + if (setId) + query << ", Id=" << ob->Id; + + mysqlpp::ResNSel res=query.execute(); + if (res) { + if (ob->Id > 0 && ob->Id!=(int)res.insert_id) { + ob->correctionNeeded = true; + } + + if (ob->Id != res.insert_id) + ob->changeId((int)res.insert_id); + + updateCounter(oTable, ob->Id, 0); + ob->oe->updateFreeId(ob); + + return updateTime(oTable, ob); + } + else { + errorMessage = "Unexpected error: update failed"; + return opStatusFail; + } + } + else { + + mysqlpp::ResNSel res = updateCounter(oTable, ob->Id, &updateqry); + + if (res){ + if (res.rows==0){ + query.reset(); + + query << "SELECT Id FROM " << oTable << " WHERE Id=" << ob->Id; + mysqlpp::Result store_res = query.store(); + + if (store_res.num_rows()==0){ + query.reset(); + query << "INSERT INTO " << oTable << " SET " << + updateqry.str() << ", Id=" << ob->Id; + + res=query.execute(); + if (!res) { + errorMessage = "Unexpected error: insert failed"; + return opStatusFail; + } + + updateCounter(oTable, ob->Id, 0); + } + } + } + + return updateTime(oTable, ob); + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [" + oTable + " \n\n(" + query.str() + ")]"); + return opStatusFail; + } + + return opStatusFail; +} + +bool MeosSQL::checkOldVersion(oEvent *oe, Row &row) { + int dbv=int(row["BuildVersion"]); + if ( dbvupdateChanged(); + else if (dbv>buildVersion) + return true; + + return false; +} + +OpFailStatus MeosSQL::SyncEvent(oEvent *oe) { + errorMessage.clear(); + OpFailStatus retValue = opStatusOK; + if (!con.connected()) + return opStatusOK; + + bool oldVersion=false; + try{ + Query query = con.query(); + + query << "SELECT * FROM oEvent"; + query << " WHERE Counter>" << oe->counter; + + Result res = query.store(); + + if (res && res.num_rows()>0) { + Row row=res.at(0); + string Modified=row["Modified"]; + int counter = row["Counter"]; + + oldVersion = checkOldVersion(oe, row); + /* int dbv=int(row["BuildVersion"]); + if ( dbvupdateChanged(); + else if (dbv>buildVersion) + oldVersion=true; +*/ + if (isOld(counter, Modified, oe)) { + oe->Name=row["Name"]; + oe->Annotation = row["Annotation"]; + oe->Date=row["Date"]; + oe->ZeroTime=row["ZeroTime"]; + oe->sqlUpdated=Modified; + const string &lRaw = row.raw_string(res.field_num("Lists")); + try { + importLists(oe, lRaw.c_str()); + } + catch (std::exception &ex) { + alert(ex.what()); + } + oe->counter = counter; + oDataInterface odi=oe->getDI(); + storeData(odi, row, oe->dataRevision); + oe->setCurrency(-1, "", "", false);//Init temp data from stored data + oe->getMeOSFeatures().deserialize(oe->getDCI().getString("Features"), *oe); + oe->changed=false; + oe->changedObject(); + } + else if (oe->isChanged()) { + + string listEnc; + try { + encodeLists(oe, listEnc); + } + catch (std::exception &ex) { + retValue = opStatusWarning; + alert(ex.what()); + } + + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << limitLength(oe->Name, 128) << ", " + << " Annotation=" << quote << limitLength(oe->Annotation, 128) << ", " + << " Date=" << quote << oe->Date << ", " + << " NameId=" << quote << oe->CurrentNameId << ", " + << " ZeroTime=" << unsigned(oe->ZeroTime) << ", " + << " BuildVersion=if (BuildVersion<" << + buildVersion << "," << buildVersion << ",BuildVersion), " + << " Lists=" << quote << listEnc + << oe->getDI().generateSQLSet(false); + + syncUpdate(queryset, "oEvent", oe); + + // Update list database; + con.select_db("MeOSMain"); + queryset.reset(); + queryset << "UPDATE oEvent SET Name=" << quote << limitLength(oe->Name, 128) << ", " + << " Annotation=" << quote << limitLength(oe->Annotation, 128) << ", " + << " Date=" << quote << oe->Date << ", " + << " NameId=" << quote << oe->CurrentNameId << ", " + << " ZeroTime=" << unsigned(oe->ZeroTime) + << " WHERE Id=" << oe->Id; + + queryset.execute(); + //syncUpdate(queryset, "oEvent", oe, true); + con.select_db(CmpDataBase); + } + } + else if ( oe->isChanged() ){ + string listEnc; + encodeLists(oe, listEnc); + + mysqlpp::Query queryset = con.query(); + queryset << " Name=" << quote << limitLength(oe->Name, 128) << ", " + << " Annotation=" << quote << limitLength(oe->Annotation, 128) << ", " + << " Date=" << quote << oe->Date << "," + << " NameId=" << quote << oe->CurrentNameId << "," + << " ZeroTime=" << unsigned(oe->ZeroTime) << "," + << " BuildVersion=if (BuildVersion<" << + buildVersion << "," << buildVersion << ",BuildVersion)," + << " Lists=" << quote << listEnc + << oe->getDI().generateSQLSet(false); + + syncUpdate(queryset, "oEvent", oe); + + // Update list database; + con.select_db("MeOSMain"); + queryset.reset(); + queryset << "UPDATE oEvent SET Name=" << quote << limitLength(oe->Name, 128) << ", " + << " Annotation=" << quote << limitLength(oe->Annotation, 128) << ", " + << " Date=" << quote << oe->Date << ", " + << " NameId=" << quote << oe->CurrentNameId << ", " + << " ZeroTime=" << unsigned(oe->ZeroTime) + << " WHERE Id=" << oe->Id; + + queryset.execute(); + //syncUpdate(queryset, "oEvent", oe, true); + con.select_db(CmpDataBase); + } + } + catch (const mysqlpp::Exception& er){ + setDefaultDB(); + alert(string(er.what())+" [SYNCLIST oEvent]"); + return opStatusFail; + } + + if (oldVersion) { + warnOldDB(); + return opStatusWarning; + } + + return retValue; +} + +void MeosSQL::warnOldDB() { + if (!warnedOldVersion) { + warnedOldVersion=true; + alert("warn:olddbversion"); + } +} + +bool MeosSQL::syncListRunner(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + + /*query << "SELECT Id, Counter, Modified, Removed FROM oRunner"; + query << " WHERE Counter > " << oe->sqlCounterRunners; + query << " OR Modified > '" << oe->sqlUpdateRunners << "'";*/ + Result res = query.store(selectUpdated("oRunner", oe->sqlUpdateRunners, oe->sqlCounterRunners)); + + if (res) { + for (int i=0; igetRunner(Id, 0); + + if (r) { + r->Removed=true; + if (r->tInTeam) + r->tInTeam->correctRemove(r); + + if (r->tParentRunner) { + r->tParentRunner->correctRemove(r); + } + + r->changedObject(); + oe->sqlChangedRunners = true; + } + } + else{ + oRunner *r=oe->getRunner(Id, 0); + + if (r){ + if (isOld(counter, modified, r)) + syncRead(false, r); + } + else { + oRunner or(oe, Id); + syncRead(true, &or, false, false); + r = oe->addRunner(or, false); + } + } + oe->sqlCounterRunners = max(counter, oe->sqlCounterRunners); + oe->sqlUpdateRunners = max(modified, oe->sqlUpdateRunners); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oRunner]"); + return false; + } + return true; +} + +bool MeosSQL::syncListClass(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + /* + query << "SELECT Id, Counter, Modified, Removed FROM oClass"; + query << " WHERE Counter > " << oe->sqlCounterClasses; + query << " OR Modified > '" << oe->sqlUpdateClasses << "'";*/ + + //Result res = query.store(); + Result res = query.store(selectUpdated("oClass", oe->sqlUpdateClasses, oe->sqlCounterClasses)); + + if (res) { + + for (int i=0; igetClass(Id); + if (c) { + c->changedObject(); + c->Removed=true; + } + } + else { + oClass *c=oe->getClass(Id); + + if (!c) { + oClass oc(oe, Id); + syncRead(true, &oc, false); + c=oe->addClass(oc); + if (c!=0) { + c->changed = false; + //syncRead(true, c, false); + } + } + else if (isOld(counter, modified, c)) + syncRead(false, c, false); + } + oe->sqlCounterClasses = max(counter, oe->sqlCounterClasses); + oe->sqlUpdateClasses = max(modified, oe->sqlUpdateClasses); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oClass]"); + return false; + } + return true; +} + + +bool MeosSQL::syncListClub(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + + /*query << "SELECT Id, Counter, Modified, Removed FROM oClub"; + query << " WHERE Counter > " << oe->sqlCounterClubs; + query << " OR Modified > '" << oe->sqlUpdateClubs << "'";*/ + Result res = query.store(selectUpdated("oClub", oe->sqlUpdateClubs, oe->sqlCounterClubs)); + + if (res) { + for(int i=0; igetClub(Id); + + if (c) { + c->Removed=true; + c->changedObject(); + } + } + else { + oClub *c=oe->getClub(Id); + + if (c==0) { + oClub oc(oe, Id); + syncRead(true, &oc); + oe->addClub(oc); + } + else if (isOld(counter, modified, c)) + syncRead(false, c); + } + oe->sqlCounterClubs = max(counter, oe->sqlCounterClubs); + oe->sqlUpdateClubs = max(modified, oe->sqlUpdateClubs); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oClub]"); + return false; + } + return true; +} + + +bool MeosSQL::syncListCourse(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + /* + query << "SELECT Id, Counter, Modified, Removed FROM oCourse"; + query << " WHERE Counter > " << oe->sqlCounterCourses; + query << " OR Modified > '" << oe->sqlUpdateCourses << "'"; + */ + Result res = query.store(selectUpdated("oCourse", oe->sqlUpdateCourses, oe->sqlCounterCourses)); + + + if (res) { + set tmp; + for(int i=0; igetCourse(Id); + + if (c) { + c->Removed=true; + c->changedObject(); + } + } + else{ + oCourse *c=oe->getCourse(Id); + + if (c==0) { + oCourse oc(oe, Id); + syncReadCourse(true, &oc, tmp); + oe->addCourse(oc); + } + else if (isOld(counter, modified, c)) + syncReadCourse(false, c, tmp); + } + oe->sqlCounterCourses = max(counter, oe->sqlCounterCourses); + oe->sqlUpdateCourses = max(modified, oe->sqlUpdateCourses); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oCourse]"); + return false; + } + return true; +} + +bool MeosSQL::syncListCard(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + + /*query << "SELECT Id, Counter, Modified, Removed FROM oCard"; + query << " WHERE Counter>0 AND (Counter>" << oe->sqlCounterCards; + query << " OR Modified>'" << oe->sqlUpdateCards << "')";*/ + + Result res = query.store(selectUpdated("oCard", oe->sqlUpdateCards, oe->sqlCounterCards)); + + if (res) { + for (int i=0; igetCard(Id); + if (c) { + c->changedObject(); + c->Removed=true; + } + } + else { + oCard *c=oe->getCard(Id); + + if (c) { + if (isOld(counter, modified, c)) + syncRead(false, c); + } + else { + oCard oc(oe, Id); + c = oe->addCard(oc); + if (c!=0) + syncRead(true, c); + } + } + oe->sqlCounterCards = max(counter, oe->sqlCounterCards); + oe->sqlUpdateCards = max(modified, oe->sqlUpdateCards); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oCard]"); + return false; + } + return true; +} + +bool MeosSQL::syncListControl(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + + /*query << "SELECT Id, Counter, Modified, Removed FROM oControl"; + query << " WHERE Counter > " << oe->sqlCounterControls; + query << " OR Modified > '" << oe->sqlUpdateControls << "'";*/ + + Result res = query.store(selectUpdated("oControl", oe->sqlUpdateControls, oe->sqlCounterControls)); + + //Result res = query.store(); + + if (res) { + for(int i=0; igetControl(Id, false); + + if (c) { + c->Removed=true; + c->changedObject(); + } + } + else { + oControl *c=oe->getControl(Id, false); + if (c) { + if (isOld(counter, modified, c)) + syncRead(false, c); + } + else { + oControl oc(oe, Id); + syncRead(true, &oc); + c = oe->addControl(oc); +// if (c!=0) +// syncRead(true, c); + } + } + oe->sqlCounterControls = max(counter, oe->sqlCounterControls); + oe->sqlUpdateControls = max(modified, oe->sqlUpdateControls); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oControl]"); + return false; + } + return true; +} + +bool MeosSQL::syncListPunch(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + + /*query << "SELECT Id, Counter, Modified, Removed FROM oPunch"; + query << " WHERE Counter > " << oe->sqlCounterPunches; + query << " OR Modified > '" << oe->sqlUpdatePunches << "' ORDER BY Id";*/ + Result res = query.store(selectUpdated("oPunch", oe->sqlUpdatePunches, oe->sqlCounterPunches) + " ORDER BY Id"); + //Result res = query.store(); + + if (res) { + for(int i=0; igetPunch(Id); + if (c) { + c->Removed=true; + int cid = c->getControlId(); + oFreePunch::rehashPunches(*oe, c->CardNo, 0); + pRunner r = oe->getRunner(c->tRunnerId, 0); + if (r) + r->markClassChanged(cid); + } + } + else { + oFreePunch *c=oe->getPunch(Id); + + if (c) { + if (isOld(counter, modified, c)) + syncRead(false, c, true); + } + else { + oFreePunch p(oe, Id); + syncRead(true, &p, false); + oe->addFreePunch(p); + } + } + oe->sqlCounterPunches = max(counter, oe->sqlCounterPunches); + oe->sqlUpdatePunches = max(modified, oe->sqlUpdatePunches); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oPunch]"); + return false; + } + return true; +} + +bool MeosSQL::syncListTeam(oEvent *oe) +{ + errorMessage.clear(); + + if (!con.connected()) + return false; + + try{ + Query query = con.query(); + /* + query << "SELECT Id, Counter, Modified, Removed FROM oTeam"; + query << " WHERE Counter > " << oe->sqlCounterTeams; + query << " OR Modified > '" << oe->sqlUpdateTeams << "'";*/ + + Result res = query.store(selectUpdated("oTeam", oe->sqlUpdateTeams, oe->sqlCounterTeams)); + + if (res) { + for (int i=0; igetTeam(Id); + if (t) { + t->changedObject(); + t->prepareRemove(); + t->Removed=true; + oe->sqlChangedTeams = true; + } + } + else { + oTeam *t=oe->getTeam(Id); + + if (t) { + if (isOld(counter, modified, t)) + syncRead(false, t, false); + } + else{ + oTeam ot(oe, Id); + t = oe->addTeam(ot, false); + if (t) { + syncRead(true, t, false); + t->apply(false, 0, false); + t->changed = false; + } + } + } + oe->sqlCounterTeams = max(counter, oe->sqlCounterTeams); + oe->sqlUpdateTeams = max(modified, oe->sqlUpdateTeams); + } + } + } + catch (const mysqlpp::Exception& er){ + alert(string(er.what())+" [SYNCLIST oTeam]"); + return false; + } + return true; +} + +string MeosSQL::selectUpdated(const char *oTable, const string &updated, int counter) { + string p1 = string("SELECT Id, Counter, Modified, Removed FROM ") + oTable; + + string q = "(" + p1 + " WHERE Counter>" + itos(counter) + ") UNION ALL ("+ + p1 + " WHERE Modified>'" + updated + "' AND Counter<" + itos(counter) + " AND Counter>0)"; + + return q; +} + +bool MeosSQL::checkConnection(oEvent *oe) +{ + errorMessage.clear(); + + if (!oe) { + if (monitorId && con.connected()) { + try { + Query query = con.query(); + query << "Update oMonitor SET Removed=1 WHERE Id = " << monitorId; + query.execute(); + } + catch(...) { + return false; //Not an important error. + } + } + return true; + } + + oe->connectedClients.clear(); + if (monitorId==0) { + try { + Query query = con.query(); + query << "INSERT INTO oMonitor SET Count=1, Client=" << quote << oe->clientName; + ResNSel res=query.execute(); + if (res) + monitorId=static_cast(res.insert_id); + } + catch (const mysqlpp::Exception& er){ + oe->connectedClients.push_back(er.what()); + return false; + } + } + else { + try { + Query query = con.query(); + query << "Update oMonitor SET Count=Count+1, Client=" << quote << oe->clientName + << " WHERE Id = " << monitorId; + query.execute(); + } + catch (const mysqlpp::Exception& er){ + oe->connectedClients.push_back(er.what()); + return false; + } + } + bool callback=false; + + try { + Query query = con.query(); + query << "SELECT Id, Client FROM oMonitor WHERE Modified>TIMESTAMPADD(SECOND, -30, NOW())" + " AND Removed=0 ORDER BY Client"; + + Result res = query.store(); + + if (res) { + for (int i=0; iconnectedClients.push_back(string(row["Client"])); + + if (int(row["Id"])==monitorId) + callback=true; + } + } + } + catch (const mysqlpp::Exception& er){ + oe->connectedClients.push_back(er.what()); + return false; + } + return callback; +} + +void MeosSQL::setDefaultDB() +{ + errorMessage.clear(); + + if (CmpDataBase.empty()) + return; + + try { + if (!con.connected()) + return; + + con.select_db(CmpDataBase); + } + catch(...) { + } +} + +bool MeosSQL::dropDatabase(oEvent *oe) +{ + // Check if other cients are connected. + if ( !checkConnection(oe) ) { + if (!oe->connectedClients.empty()) + alert(oe->connectedClients[0]); + + return false; + } + + if (oe->connectedClients.size()!=1) { + alert("Database is used and cannot be deleted"); + return false; + } + + try { + con.select_db("MeOSMain"); + } + catch (const mysqlpp::Exception& er) { + alert(string(er.what()) + " MySQL Error. Select MeosMain"); + setDefaultDB(); + return 0; + } + + try { + con.drop_db(CmpDataBase); + } + catch (const mysqlpp::Exception& ) { + //Don't care if we fail. + } + + try { + Query query = con.query(); + query << "DELETE FROM oEvent WHERE NameId=" << quote << CmpDataBase; + query.execute(); + } + catch (const mysqlpp::Exception& ) { + //Don't care if we fail. + } + + CmpDataBase.clear(); + + errorMessage.clear(); + + try { + con.close(); + } + catch (const mysqlpp::Exception&) { + } + + return true; +} + +void MeosSQL::importLists(oEvent *oe, const char *bf) { + xmlparser xml(0); + xml.readMemory(bf, 0); + oe->listContainer->clearExternal(); + oe->listContainer->load(MetaListContainer::ExternalList, xml.getObject("Lists"), false); +} + +void MeosSQL::encodeLists(const oEvent *oe, string &listEnc) const { + xmlparser parser(0); + parser.openMemoryOutput(true); + parser.startTag("Lists"); + oe->listContainer->save(MetaListContainer::ExternalList, parser, oe); + parser.endTag(); + parser.getMemoryOutput(listEnc); +} + +void MeosSQL::clearReadTimes() { + readTimes.clear(); +} + +int getTypeId(const oBase &ob) +{ + if (typeid(ob)==typeid(oRunner)){ + return 1; + } + else if (typeid(ob)==typeid(oClass)){ + return 2; + } + else if (typeid(ob)==typeid(oCourse)){ + return 3; + } + else if (typeid(ob)==typeid(oControl)){ + return 4; + } + else if (typeid(ob)==typeid(oClub)){ + return 5; + } + else if (typeid(ob)==typeid(oCard)){ + return 6; + } + else if (typeid(ob)==typeid(oFreePunch)){ + return 7; + } + else if (typeid(ob)==typeid(oTeam)){ + return 8; + } + else if (typeid(ob)==typeid(oEvent)){ + return 9; + } + return -1; +} +static int skipped = 0, notskipped = 0, readent = 0; + +void MeosSQL::synchronized(const oBase &entity) { + int id = getTypeId(entity); + readTimes[make_pair(id, entity.getId())] = GetTickCount(); + readent++; + if (readent % 100 == 99) + OutputDebugString("Read 100 entities\n"); +} + +bool MeosSQL::skipSynchronize(const oBase &entity) const { + int id = getTypeId(entity); + map, DWORD>::const_iterator res = readTimes.find(make_pair(id, entity.getId())); + + if (res != readTimes.end()) { + DWORD t = GetTickCount(); + if (t > res->second && (t - res->second) < 1000) { + skipped++; + return true; + } + } + + notskipped++; + return false; +} + +int MeosSQL::getModifiedMask(oEvent &oe) { + try { + Query query = con.query(); + int res = 0; + Result store_res = query.store("SELECT * FROM oCounter"); + if (store_res.num_rows()>0) { + Row r = store_res.at(0); + int ctrl = r["oControl"]; + int crs = r["oCourse"]; + int cls = r["oClass"]; + int card = r["oCard"]; + int club = r["oClub"]; + int punch = r["oPunch"]; + int runner = r["oRunner"]; + int t = r["oTeam"]; + int e = r["oEvent"]; + + if (ctrl > oe.sqlCounterControls) + res |= oLControlId; + if (crs > oe.sqlCounterCourses) + res |= oLCourseId; + if (cls > oe.sqlCounterClasses) + res |= oLClassId; + if (card > oe.sqlCounterCards) + res |= oLCardId; + if (club > oe.sqlCounterClubs) + res |= oLClubId; + if (punch > oe.sqlCounterPunches) + res |= oLPunchId; + if (runner > oe.sqlCounterRunners) + res |= oLRunnerId; + if (t > oe.sqlCounterTeams) + res |= oLTeamId; + if (e > oe.counter) + res |= oLEventId; + + return res; + } + } + catch(...) { + } + return -1; +} \ No newline at end of file diff --git a/code/meosdb/MeosSQL.h b/code/meosdb/MeosSQL.h new file mode 100644 index 0000000..4b3d2c8 --- /dev/null +++ b/code/meosdb/MeosSQL.h @@ -0,0 +1,184 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2012 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include + +#include +#include "sqltypes.h" + +class oRunner; +class oEvent; +class oCard; +class oClub; +class oCourse; +class oClass; +class oControl; +class oBase; +class oFreePunch; +class oDataInterface; +class oTeam; +class oDataContainer; + +namespace mysqlpp { + class Query; +} + +using namespace std; + + +class MeosSQL +{ +protected: + bool warnedOldVersion; + int monitorId; + int buildVersion; + mysqlpp::Connection con; + string CmpDataBase; + void alert(const string &s); + + string errorMessage; + + string serverName; + string serverUser; + string serverPassword; + unsigned int serverPort; + + bool isOld(int counter, const string &time, oBase *ob); + string andWhereOld(oBase *ob); + + OpFailStatus updateTime(const char *oTable, oBase *ob); + // Update object in database with fixed query. If useId is false, Id is ignored (used + OpFailStatus syncUpdate(mysqlpp::Query &updateqry, const char *oTable, oBase *ob); + bool storeData(oDataInterface odi, const mysqlpp::Row &row, unsigned long &revision); + + void importLists(oEvent *oe, const char *bf); + void encodeLists(const oEvent *or, string &listEnc) const; + + //Set DB to default competition DB + void setDefaultDB(); + + // Update the courses of a class. + OpFailStatus syncReadClassCourses(oClass *c,const set &courses, + bool readRecursive); + OpFailStatus syncRead(bool forceRead, oTeam *t, bool readRecursive); + OpFailStatus syncRead(bool forceRead, oRunner *r, bool readClassClub, bool readCourseCard); + OpFailStatus syncReadCourse(bool forceRead, oCourse *c, set &readControls); + OpFailStatus syncRead(bool forceRead, oClass *c, bool readCourses); + OpFailStatus syncReadControls(oEvent *oe, const set &controlIds); + + void storeClub(const mysqlpp::Row &row, oClub &c); + void storeControl(const mysqlpp::Row &row, oControl &c); + void storeCard(const mysqlpp::Row &row, oCard &c); + void storePunch(const mysqlpp::Row &row, oFreePunch &p, bool rehash); + + OpFailStatus storeTeam(const mysqlpp::Row &row, oTeam &t, + bool readRecursive); + + OpFailStatus storeRunner(const mysqlpp::Row &row, oRunner &r, + bool readCourseCard, + bool readClassClub, + bool readRunners); + OpFailStatus storeCourse(const mysqlpp::Row &row, oCourse &c, + set &readControls); + OpFailStatus storeClass(const mysqlpp::Row &row, oClass &c, + bool readCourses); + + void getColumns(const string &table, set &output); + + void upgradeDB(const string &db, oDataContainer const *odi); + + void warnOldDB(); + bool checkOldVersion(oEvent *oe, mysqlpp::Row &row); + + map, DWORD> readTimes; + void clearReadTimes(); + void synchronized(const oBase &entity); + bool skipSynchronize(const oBase &entity) const; + + mysqlpp::ResNSel updateCounter(const char *oTable, int id, mysqlpp::Query *updateqry); + string selectUpdated(const char *oTable, const string &updated, int counter); + +public: + bool dropDatabase(oEvent *oe); + bool checkConnection(oEvent *oe); + + bool repairTables(const string &db, vector &output); + + bool getErrorMessage(char *bf); + bool reConnect(); + bool listCompetitions(oEvent *oe, bool keepConnection); + bool Remove(oBase *ob); + + // Create database of runners and clubs + bool createRunnerDB(oEvent *oe, mysqlpp::Query &query); + + // Upload runner database to server + OpFailStatus uploadRunnerDB(oEvent *oe); + + bool openDB(oEvent *oe); + + bool closeDB(); + + bool syncListRunner(oEvent *oe); + bool syncListClass(oEvent *oe); + bool syncListCourse(oEvent *oe); + bool syncListControl(oEvent *oe); + bool syncListCard(oEvent *oe); + bool syncListClub(oEvent *oe); + bool syncListPunch(oEvent *oe); + bool syncListTeam(oEvent *oe); + + OpFailStatus SyncEvent(oEvent *oe); + + OpFailStatus SyncUpdate(oEvent *oe); + OpFailStatus SyncRead(oEvent *oe); + + OpFailStatus syncUpdate(oRunner *r, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oRunner *r); + + OpFailStatus syncUpdate(oCard *c, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oCard *c); + + OpFailStatus syncUpdate(oClass *c, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oClass *c); + + OpFailStatus syncUpdate(oClub *c, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oClub *c); + + OpFailStatus syncUpdate(oCourse *c, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oCourse *c); + + OpFailStatus syncUpdate(oControl *c, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oControl *c); + + OpFailStatus syncUpdate(oFreePunch *c, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oFreePunch *c, bool rehash); + + OpFailStatus syncUpdate(oTeam *t, bool forceWriteAll); + OpFailStatus syncRead(bool forceRead, oTeam *t); + + int getModifiedMask(oEvent &oe); + + MeosSQL(void); + virtual ~MeosSQL(void); +}; diff --git a/code/meosdb/dllmain.cpp b/code/meosdb/dllmain.cpp new file mode 100644 index 0000000..8a4edd3 --- /dev/null +++ b/code/meosdb/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/code/meosdb/meosdb.cpp b/code/meosdb/meosdb.cpp new file mode 100644 index 0000000..bd65900 --- /dev/null +++ b/code/meosdb/meosdb.cpp @@ -0,0 +1,266 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + +// meosdb.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" + +#ifdef c + #include "meosdb.h" +#else + #define MEOSDB_API +#endif + +#include + +#include +#include + +#include +#include +#include + +#include "MeosSQL.h" +#include "../meos_util.h" + +using namespace std; + +#include "../oRunner.h" +#include "../oEvent.h" +#include "../Localizer.h" + +#include + +#ifdef BUILD_DB_DLL + HINSTANCE hInst=0; + Localizer lang; +#endif + +extern "C"{ + +int MEOSDB_API getMeosVersion() +{ + return getMeosBuild(); +} + +MeosSQL msql; +static int nSynchList = 0; +static int nSynchEnt = 0; + +int getListMask(oEvent &oe) { + return msql.getModifiedMask(oe); +} + +bool MEOSDB_API msSynchronizeList(oEvent *oe, int lid) +{ + nSynchList++; + if (nSynchList % 100 == 99) + OutputDebugString("Synchronized 100 lists\n"); + + if (lid==oLRunnerId) + return msql.syncListRunner(oe); + else if (lid==oLClassId) + return msql.syncListClass(oe); + else if (lid==oLCourseId) + return msql.syncListCourse(oe); + else if (lid==oLControlId) + return msql.syncListControl(oe); + else if (lid==oLClubId) + return msql.syncListClub(oe); + else if (lid==oLCardId) + return msql.syncListCard(oe); + else if (lid==oLPunchId) + return msql.syncListPunch(oe); + else if (lid==oLTeamId) + return msql.syncListTeam(oe); + + return false; +} + +int MEOSDB_API msSynchronizeUpdate(oBase *obj) +{ + if (typeid(*obj)==typeid(oRunner)){ + return msql.syncUpdate((oRunner *) obj, false); + } + else if (typeid(*obj)==typeid(oClass)){ + return msql.syncUpdate((oClass *) obj, false); + } + else if (typeid(*obj)==typeid(oCourse)){ + return msql.syncUpdate((oCourse *) obj, false); + } + else if (typeid(*obj)==typeid(oControl)){ + return msql.syncUpdate((oControl *) obj, false); + } + else if (typeid(*obj)==typeid(oClub)){ + return msql.syncUpdate((oClub *) obj, false); + } + else if (typeid(*obj)==typeid(oCard)){ + return msql.syncUpdate((oCard *) obj, false); + } + else if (typeid(*obj)==typeid(oFreePunch)){ + return msql.syncUpdate((oFreePunch *) obj, false); + } + else if (typeid(*obj)==typeid(oEvent)){ + + return msql.SyncUpdate((oEvent *) obj); + } + else if (typeid(*obj)==typeid(oTeam)){ + return msql.syncUpdate((oTeam *) obj, false); + } + return 0; +} + +int MEOSDB_API msSynchronizeRead(oBase *obj) +{ + nSynchEnt++; + if (nSynchEnt % 100 == 99) + OutputDebugString("Synchronized 100 entities\n"); + + if (typeid(*obj)==typeid(oRunner)){ + return msql.syncRead(false, (oRunner *) obj ); + } + else if (typeid(*obj)==typeid(oClass)){ + return msql.syncRead(false, (oClass *) obj); + } + else if (typeid(*obj)==typeid(oCourse)){ + return msql.syncRead(false, (oCourse *) obj); + } + else if (typeid(*obj)==typeid(oControl)){ + return msql.syncRead(false, (oControl *) obj); + } + else if (typeid(*obj)==typeid(oClub)){ + return msql.syncRead(false, (oClub *) obj); + } + else if (typeid(*obj)==typeid(oCard)){ + return msql.syncRead(false, (oCard *) obj); + } + else if (typeid(*obj)==typeid(oFreePunch)){ + return msql.syncRead(false, (oFreePunch *) obj, true); + } + else if (typeid(*obj)==typeid(oTeam)){ + return msql.syncRead(false, (oTeam *) obj); + } + else if (typeid(*obj)==typeid(oEvent)){ + return msql.SyncRead((oEvent *) obj); + } + return 0; +} + +// Removes (marks it as removed) an entry from the database. +int MEOSDB_API msRemove(oBase *obj) +{ + return msql.Remove(obj); +} + +// Checks the database connection, lists other connected components +// and register ourself in the database. The value oe=0 unregister us. +int MEOSDB_API msMonitor(oEvent *oe) +{ + return msql.checkConnection(oe); +} + +// Tries to open the database defined by oe. +int MEOSDB_API msUploadRunnerDB(oEvent *oe) +{ + return msql.uploadRunnerDB(oe); +} + +// Tries to open the database defined by oe. +int MEOSDB_API msOpenDatabase(oEvent *oe) +{ + return msql.openDB(oe); +} + +// Tries to remove the database defined by oe. +int MEOSDB_API msDropDatabase(oEvent *oe) +{ + return msql.dropDatabase(oe); +} + +// Tries to connect to the server defined by oe. +int MEOSDB_API msConnectToServer(oEvent *oe) +{ + return msql.listCompetitions(oe, false); +} + +// Reloads competitions. Assumes a connection. +int MEOSDB_API msListCompetitions(oEvent *oe) +{ + return msql.listCompetitions(oe, true); +} + +// Fills string msgBuff with the current error stage +bool MEOSDB_API msGetErrorState(char *msgBuff) +{ + return msql.getErrorMessage(msgBuff); +} + +// Close database connection. +bool MEOSDB_API msResetConnection() +{ + return msql.closeDB(); +} + +// Try to reconnect to the database. Returns true if successful. +bool MEOSDB_API msReConnect() +{ + return msql.reConnect(); +} + + +} //Extern "C" + +bool repairTables(const string &db, vector &output) { + return msql.repairTables(db, output); +} + + +#ifdef BUILD_DB_DLL + +bool getUserFile(char *file, const char *in) +{ + throw 0; + strcpy_s(file, 256, in); + return true; +} + +string MakeDash(string) +{ + throw 0; + return ""; +} + +bool __cdecl GetRandomBit() +{ + throw 0; + return true; +} + +int __cdecl GetRandomNumber(int) +{ + throw 0; + return 0; +} + +#endif diff --git a/code/meosdb/meosdb.h b/code/meosdb/meosdb.h new file mode 100644 index 0000000..3dc6b47 --- /dev/null +++ b/code/meosdb/meosdb.h @@ -0,0 +1,29 @@ +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the MEOSDB_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// MEOSDB_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#ifdef MEOSDB_EXPORTS +#define MEOSDB_API __declspec(dllexport) __cdecl +#else +#define MEOSDB_API __declspec(dllimport) __cdecl +#endif + +#include +#include + +/* +extern "C"{ +// This class is exported from the meosdb.dll +class Cmeosdb { +public: + Cmeosdb(void); + // TODO: add your methods here. +}; + +//extern MEOSDB_API int nmeosdb; + + +MEOSDB_API int fnmeosdb(void); +}*/ \ No newline at end of file diff --git a/code/meosdb/meosdb.vcproj b/code/meosdb/meosdb.vcproj new file mode 100644 index 0000000..085de92 --- /dev/null +++ b/code/meosdb/meosdb.vcproj @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/meosdb/meosdb.vcxproj b/code/meosdb/meosdb.vcxproj new file mode 100644 index 0000000..ec88d9c --- /dev/null +++ b/code/meosdb/meosdb.vcxproj @@ -0,0 +1,158 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {13A51976-5F88-471F-A1E9-259102710806} + meosdb + Win32Proj + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + NotSet + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + mysql++\;C:\Program Files\MySQL\MySQL Server 5.5\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MEOSDB_EXPORTS;MEOSDB;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + true + + + mysqlpp.lib;Msimg32.lib;comctl32.lib;winmm.lib;%(AdditionalDependencies) + ..\lib_db;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + MaxSpeed + AnySuitable + true + Speed + F:\Dev\meos\code\meosdb\mysql++;F:\Dev\meos\code\meosdb\mysql50;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;MEOSDB_EXPORTS;MEOSDB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Use + Level3 + + + + + Msimg32.lib;comctl32.lib;mysqlpp.lib;winmm.lib;%(AdditionalDependencies) + ..\lib;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + + + + + + false + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/meosdb/mysql++/Doxyfile.in b/code/meosdb/mysql++/Doxyfile.in new file mode 100644 index 0000000..b5fa682 --- /dev/null +++ b/code/meosdb/mysql++/Doxyfile.in @@ -0,0 +1,1258 @@ +# Doxyfile 1.5.2-1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file that +# follow. The default is UTF-8 which is also the encoding used for all text before +# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into +# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of +# possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = MySQL++ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# This tag can be used to specify the character encoding of the source files that +# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default +# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. +# See http://www.gnu.org/software/libiconv for the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = custom.h \ + custom-macros.h + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the output. +# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, +# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html/refman + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = ../doc/html/refman/_header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = DOXYGEN_IGNORE + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to +# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to +# specify the directory where the mscgen tool resides. If left empty the tool is assumed to +# be found in the default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen will always +# show the root nodes and its direct children regardless of this setting. + +DOT_GRAPH_MAX_NODES = 50 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/code/meosdb/mysql++/autoflag.h b/code/meosdb/mysql++/autoflag.h new file mode 100644 index 0000000..77ef8a6 --- /dev/null +++ b/code/meosdb/mysql++/autoflag.h @@ -0,0 +1,57 @@ +/// \file autoflag.h +/// \brief Defines a template for setting a flag within a given variable +/// scope, and resetting it when exiting that scope. + +/*********************************************************************** + Copyright (c) 2007 by Educational Technology Resources, Inc. Others + may also hold copyrights on code in this file. See the CREDITS file in + the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_AUTOFLAG_H) +#define MYSQLPP_AUTOFLAG_H + +/// \brief A template for setting a flag on a variable as long as the +/// object that set it is in scope. Flag resets when object goes +/// out of scope. Works on anything that looks like bool. + +template +class AutoFlag +{ +public: + /// \brief Constructor: sets ref to true. + AutoFlag(T& ref) : + referent_(ref) + { + referent_ = true; + } + + /// \brief Destructor: sets referent passed to ctor to false. + ~AutoFlag() + { + referent_ = false; + } + +private: + T& referent_; +}; + +#endif // !defined(MYSQLPP_AUTOFLAG_H) + diff --git a/code/meosdb/mysql++/coldata.cpp b/code/meosdb/mysql++/coldata.cpp new file mode 100644 index 0000000..9f9f3eb --- /dev/null +++ b/code/meosdb/mysql++/coldata.cpp @@ -0,0 +1,37 @@ +/*********************************************************************** + coldata.cpp - Implements the ColData_Tmpl template. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "coldata.h" +#include "const_string.h" + +#include + +namespace mysqlpp { + +template class ColData_Tmpl; +template class ColData_Tmpl; + +} // end namespace mysqlpp diff --git a/code/meosdb/mysql++/coldata.h b/code/meosdb/mysql++/coldata.h new file mode 100644 index 0000000..1504f4c --- /dev/null +++ b/code/meosdb/mysql++/coldata.h @@ -0,0 +1,386 @@ +/// \file coldata.h +/// \brief Declares classes for converting string data to any of +/// the basic C types. +/// +/// Roughly speaking, this defines classes that are the inverse of +/// mysqlpp::SQLString. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_COLDATA_H +#define MYSQLPP_COLDATA_H + +#include "common.h" + +#include "const_string.h" +#include "convert.h" +#include "exceptions.h" +#include "null.h" +#include "string_util.h" +#include "type_info.h" + +#include +#include +#include + +#include + +namespace mysqlpp { + +/// \brief Template for string data that can convert itself to any +/// standard C data type. +/// +/// Do not use this class directly. Use the typedef ColData or +/// MutableColData instead. ColData is a \c ColData_Tmpl and MutableColData is a +/// \c ColData_Tmpl. +/// +/// The ColData types add to the C++ string type the ability to +/// automatically convert the string data to any of the basic C types. +/// This is important with SQL, because all data coming from the +/// database is in string form. MySQL++ uses this class internally +/// to hold the data it receives from the server, so you can use it +/// naturally, because it does the conversions implicitly: +/// +/// \code ColData("12.86") + 2.0 \endcode +/// +/// That works fine, but be careful. If you had said this instead: +/// +/// \code ColData("12.86") + 2 \endcode +/// +/// the result would be 14 because 2 is an integer, and C++'s type +/// conversion rules put the ColData object in an integer context. +/// +/// If these automatic conversions scare you, define the macro +/// NO_BINARY_OPERS to disable this behavior. +/// +/// This class also has some basic information about the type of data +/// stored in it, to allow it to do the conversions more intelligently +/// than a trivial implementation would allow. + +template +class MYSQLPP_EXPORT ColData_Tmpl : public Str +{ +public: + /// \brief Default constructor + /// + /// Null flag is set to false, type data is not set, and string + /// data is left empty. + /// + /// It's probably a bad idea to use this ctor, becuase there's no + /// way to set the type data once the object's constructed. + ColData_Tmpl() : + null_(false) + { + } + + /// \brief Copy ctor + /// + /// \param cd the other ColData_Tmpl object + ColData_Tmpl(const ColData_Tmpl& cd) : + Str(cd.data(), cd.length()), + type_(cd.type_), + null_(cd.null_) + { + } + + /// \brief Constructor allowing you to set the null flag and the + /// type data. + /// + /// \param n if true, data is a SQL null + /// \param t MySQL type information for data being stored + explicit ColData_Tmpl(bool n, + mysql_type_info t = mysql_type_info::string_type) : + type_(t), + null_(n) + { + } + + /// \brief C++ string version of full ctor + /// + /// \param str the string this object represents + /// \param t MySQL type information for data within str + /// \param n if true, str is a SQL null + explicit ColData_Tmpl(const std::string& str, + mysql_type_info t = mysql_type_info::string_type, + bool n = false) : + Str(str), + type_(t), + null_(n) + { + } + + /// \brief Null-terminated C string version of full ctor + /// + /// \param str the string this object represents + /// \param t MySQL type information for data within str + /// \param n if true, str is a SQL null + explicit ColData_Tmpl(const char* str, + mysql_type_info t = mysql_type_info::string_type, + bool n = false) : + Str(str), + type_(t), + null_(n) + { + } + + /// \brief Full constructor. + /// + /// \param str the string this object represents + /// \param len the length of the string; embedded nulls are legal + /// \param t MySQL type information for data within str + /// \param n if true, str is a SQL null + explicit ColData_Tmpl(const char* str, typename Str::size_type len, + mysql_type_info t = mysql_type_info::string_type, + bool n = false) : + Str(str, len), + type_(t), + null_(n) + { + } + + /// \brief Get this object's current MySQL type. + mysql_type_info type() const { return type_; } + + /// \brief Returns true if data of this type should be quoted, false + /// otherwise. + bool quote_q() const { return type_.quote_q(); } + + /// \brief Returns true if data of this type should be escaped, false + /// otherwise. + bool escape_q() const { return type_.escape_q(); } + + /// \brief Template for converting data from one type to another. + template Type conv(Type dummy) const; + + /// \brief Set a flag indicating that this object is a SQL null. + void it_is_null() { null_ = true; } + + /// \brief Returns true if this object is a SQL null. + inline const bool is_null() const { return null_; } + + /// \brief Returns this object's data in C++ string form. + /// + /// This method is inefficient, and not recommended. It makes a + /// duplicate copy of the string that lives as long as the + /// \c ColData object itself. + /// + /// If you are using the \c MutableColData typedef for this + /// template, you can avoid the duplicate copy entirely. You can + /// pass a \c MutableColData object to anything expecting a + /// \c std::string and get the right result. (This didn't work + /// reliably prior to v2.3.) + /// + /// This method is arguably useful with plain \c ColData objects, + /// but there are more efficient alternatives. If you know your + /// data is a null-terminated C string, just cast this object to + /// a \c const \c char* or call the \c data() method. This gives + /// you a pointer to our internal buffer, so the copy isn't needed. + /// If the \c ColData can contain embedded null characters, you do + /// need to make a copy, but it's better to make your own copy of + /// the string, instead of calling get_string(), so you can better + /// control its lifetime: + /// + /// \code + /// ColData cd = ...; + /// std::string s(cd.data(), cd.length()); + /// \endcode + inline const std::string& get_string() const + { + temp_buf_.assign(Str::data(), Str::length()); + return temp_buf_; + } + + /// \brief Returns a const char pointer to the object's raw data + operator cchar*() const { return Str::data(); } + + /// \brief Converts this object's string data to a signed char + operator signed char() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to an unsigned char + operator unsigned char() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to an int + operator int() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to an unsigned int + operator unsigned int() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to a short int + operator short int() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to an unsigned short + /// int + operator unsigned short int() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to a long int + operator long int() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to an unsigned long + /// int + operator unsigned long int() const + { return conv(static_cast(0)); } + +#if !defined(NO_LONG_LONGS) + /// \brief Converts this object's string data to the platform- + /// specific 'longlong' type, usually a 64-bit integer. + operator longlong() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to the platform- + /// specific 'ulonglong' type, usually a 64-bit unsigned integer. + operator ulonglong() const + { return conv(static_cast(0)); } +#endif + + /// \brief Converts this object's string data to a float + operator float() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to a double + operator double() const + { return conv(static_cast(0)); } + + /// \brief Converts this object's string data to a bool + operator bool() const { return conv(0); } + + template operator Null() const; + +private: + mysql_type_info type_; + mutable std::string temp_buf_; + bool null_; +}; + +/// \typedef ColData_Tmpl ColData +/// \brief The type that is returned by constant rows +typedef ColData_Tmpl ColData; + +/// \typedef ColData_Tmpl MutableColData +/// \brief The type that is returned by mutable rows +typedef ColData_Tmpl MutableColData; + + +#if !defined(NO_BINARY_OPERS) && !defined(DOXYGEN_IGNORE) +// Ignore this section is NO_BINARY_OPERS is defined, or if this section +// is being parsed by Doxygen. In the latter case, it's ignored because +// Doxygen doesn't understand it correctly, and we can't be bothered to +// explain it to Doxygen. + +#define oprsw(opr, other, conv) \ + template \ + inline other operator opr (ColData_Tmpl x, other y) \ + {return static_cast(x) opr y;} \ + template \ + inline other operator opr (other x, ColData_Tmpl y) \ + {return x opr static_cast(y);} + +#define operator_binary(other, conv) \ + oprsw(+, other, conv) \ + oprsw(-, other, conv) \ + oprsw(*, other, conv) \ + oprsw(/, other, conv) + +#define operator_binary_int(other, conv) \ + operator_binary(other, conv) \ + oprsw(%, other, conv) \ + oprsw(&, other, conv) \ + oprsw(^, other, conv) \ + oprsw(|, other, conv) \ + oprsw(<<, other, conv) \ + oprsw(>>, other, conv) + +operator_binary(float, double) +operator_binary(double, double) + +operator_binary_int(char, long int) +operator_binary_int(int, long int) +operator_binary_int(short int, long int) +operator_binary_int(long int, long int) + +operator_binary_int(unsigned char, unsigned long int) +operator_binary_int(unsigned int, unsigned long int) +operator_binary_int(unsigned short int, unsigned long int) +operator_binary_int(unsigned long int, unsigned long int) + +#if !defined(NO_LONG_LONGS) +operator_binary_int(longlong, longlong) +operator_binary_int(ulonglong, ulonglong) +#endif +#endif // NO_BINARY_OPERS + +/// \brief Converts this object to a SQL null +/// +/// Returns a copy of the global null object if the string data held by +/// the object is exactly equal to "NULL". Else, it constructs an empty +/// object of type T and tries to convert it to Null. +template template +ColData_Tmpl::operator Null() const +{ + if ((Str::size() == 4) && + (*this)[0] == 'N' && + (*this)[1] == 'U' && + (*this)[2] == 'L' && + (*this)[3] == 'L') { + return Null(null); + } + else { + return Null(conv(T())); + } +} + +template template +Type ColData_Tmpl::conv(Type /* dummy */) const +{ + std::string strbuf(Str::data(), Str::length()); + strip_all_blanks(strbuf); + std::string::size_type len = strbuf.size(); + const char* str = strbuf.c_str(); + const char* end = str; + Type num = mysql_convert(str, end); + + if (*end == '.') { + ++end; + for (; *end == '0'; ++end) ; + } + + if (*end != '\0' && end != 0) { + throw BadConversion(typeid(Type).name(), Str::c_str(), + end - str, len); + } + + return num; +} + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/common.h b/code/meosdb/mysql++/common.h new file mode 100644 index 0000000..065fa57 --- /dev/null +++ b/code/meosdb/mysql++/common.h @@ -0,0 +1,161 @@ +/// \file common.h +/// \brief This file includes top-level definitions for use both +/// internal to the library, and outside it. Contrast mysql++.h +/// +/// This file mostly takes care of platform differences. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_COMMON_H) +#define MYSQLPP_COMMON_H + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for the following stuff. + +// Work out major platform-specific stuff here. +#if defined(__WIN32__) || defined(_WIN32) +# define MYSQLPP_PLATFORM_WINDOWS + + // Windows compiler support. Tested with Microsoft Visual C++, + // Borland C++ Builder, and MinGW GCC. +# include + + // Stuff for Visual C++ only +# if defined(_MSC_VER) + // Disable whining about using 'this' as a member initializer on VC++. +# pragma warning(disable: 4355) + // Disable whining about implicit conversions to bool +# pragma warning(disable: 4800) + // Disable nagging about new "secure" functions like strncpy_s() +# pragma warning(disable: 4996) + // Disable complaints about STL data members: VC++ believes + // these need to be __declspec(dllexport) for some reason. +//# pragma warning(disable: 4251) + // Call _snprintf() for VC++ version of snprintf() function +//# define snprintf _snprintf +# endif + + // Define DLL import/export tags for Windows compilers, where we build + // the library into a DLL, for LGPL license compatibility reasons. + // (This is based on a similar mechanism in wxWindows.) + + #ifdef MYSQLPP_MAKING_DLL + // When making the DLL, export tagged symbols, so they appear + // in the import library. + #define MYSQLPP_EXPORT __declspec(dllexport) + #elif !defined(MYSQLPP_NO_DLL) + // We must be _using_ the DLL, so import symbols instead. + #define MYSQLPP_EXPORT __declspec(dllimport) + #else + // Not making a DLL at all, so no-op these declspecs + #define MYSQLPP_EXPORT + #endif +#else + // If not Windows, we assume some sort of Unixy build environment, + // where autotools is used. (This includes Cygwin!) #include the + // config.h file only if this file was included from a non-header + // file, because headers must not be dependent on config.h. +# if defined(MYSQLPP_NOT_HEADER) +# include "config.h" +# endif + + // Make DLL stuff a no-op on this platform. + #define MYSQLPP_EXPORT +#endif + +#if defined(MYSQLPP_MYSQL_HEADERS_BURIED) +# include +#else +# include +#endif + +namespace mysqlpp { + +/// \brief Alias for 'true', to make code requesting exceptions more +/// readable. +const bool use_exceptions = true; + +/// \brief Used to disambiguate overloads of equal_list() in SSQLSes. +enum sql_cmp_type { sql_use_compare }; + +#if !defined(DOXYGEN_IGNORE) +// Figure out how to get large integer support on this system. Suppress +// refman documentation for these typedefs, as they're system-dependent. +#if defined(NO_LONG_LONGS) +// Alias "longlong" and "ulonglong" to the regular "long" counterparts +typedef unsigned long ulonglong; +typedef long longlong; +#elif defined(_MSC_VER) +// It's VC++, so we'll use Microsoft's 64-bit integer types +typedef unsigned __int64 ulonglong; +typedef __int64 longlong; +#else +// No better idea, so assume the C99 convention. If your compiler +// doesn't support this, please provide a patch to extend this ifdef, or +// define NO_LONG_LONGS. +typedef unsigned long long ulonglong; +typedef long long longlong; +#endif +#endif // !defined(DOXYGEN_IGNORE) + +/// \brief Contraction for 'const char*' +typedef const char cchar; + +#if !defined(MYSQLPP_NO_UNSIGNED_INT_TYPES) +/// \brief Contraction for 'unsigned int' +typedef unsigned int uint; +/// \brief Contraction for 'unsigned long' +typedef unsigned long ulong; +#endif + +} // end namespace mysqlpp + +// The MySQL headers define these macros, which is completely wrong in a +// C++ project. Undo the damage. +#undef min +#undef max + +#endif // !defined(DOXYGEN_IGNORE) + + +// Now that we've defined all the stuff above, we can pull in the full +// MySQL header. Basically, the above largely replaces MySQL's my_global.h +// while actually working with C++. This is why we disobey the MySQL +// developer docs, which recommend including my_global.h before mysql.h. +#if defined(MYSQLPP_MYSQL_HEADERS_BURIED) +# include +#else +# include +#endif + + +namespace mysqlpp { + +/// \brief Alias for MYSQL_FIELD +typedef MYSQL_FIELD Field; + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_COMMON_H) diff --git a/code/meosdb/mysql++/connection.cpp b/code/meosdb/mysql++/connection.cpp new file mode 100644 index 0000000..e575d2d --- /dev/null +++ b/code/meosdb/mysql++/connection.cpp @@ -0,0 +1,725 @@ +/*********************************************************************** + connection.cpp - Implements the Connection class. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2006 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#define MYSQLPP_NOT_HEADER +#include "common.h" + +#include "connection.h" + +#include "query.h" +#include "result.h" + +// An argument was added to mysql_shutdown() in MySQL 4.1.3 and 5.0.1. +#if ((MYSQL_VERSION_ID >= 40103) && (MYSQL_VERSION_ID <= 49999)) || (MYSQL_VERSION_ID >= 50001) +# define SHUTDOWN_ARG ,SHUTDOWN_DEFAULT +#else +# define SHUTDOWN_ARG +#endif + +#define NELEMS(a) (sizeof(a) / sizeof(a[0])) + +using namespace std; + +namespace mysqlpp { + +/// \brief Sets a variable to a given value temporarily. +/// +/// Saves existing value, sets new value, and restores old value when +/// the object is destroyed. Used to set a flag in an exception-safe +/// manner. +template +class scoped_var_set +{ +public: + /// \brief Create object, saving old value, setting new value + scoped_var_set(T& var, T new_value) : + var_(var) + { + old_value_ = var_; + var_ = new_value; + } + + /// \brief Destroy object, restoring old value + ~scoped_var_set() + { + var_ = old_value_; + } + +private: + T& var_; + T old_value_; +}; + + +// Initialize table of legal option argument types. +Connection::OptionArgType +Connection::legal_opt_arg_types_[Connection::opt_COUNT] = { + Connection::opt_type_integer, // opt_connect_timeout + Connection::opt_type_none, // opt_compress + Connection::opt_type_none, // opt_named_pipe + Connection::opt_type_string, // opt_init_command + Connection::opt_type_string, // opt_read_default_file + Connection::opt_type_string, // opt_read_default_group + Connection::opt_type_string, // opt_set_charset_dir + Connection::opt_type_string, // opt_set_charset_name + Connection::opt_type_integer, // opt_local_infile + Connection::opt_type_integer, // opt_protocol + Connection::opt_type_string, // opt_shared_memory_base_name + Connection::opt_type_integer, // opt_read_timeout + Connection::opt_type_integer, // opt_write_timeout + Connection::opt_type_none, // opt_use_result + Connection::opt_type_none, // opt_use_remote_connection + Connection::opt_type_none, // opt_use_embedded_connection + Connection::opt_type_none, // opt_guess_connection + Connection::opt_type_string, // opt_set_client_ip + Connection::opt_type_boolean, // opt_secure_auth + Connection::opt_type_boolean, // opt_multi_statements + Connection::opt_type_boolean, // opt_report_data_truncation + Connection::opt_type_boolean, // opt_reconnect +}; + + +Connection::Connection(bool te) : +OptionalExceptions(te), +Lockable(false), +is_connected_(false), +connecting_(false), +success_(false) +{ + mysql_init(&mysql_); +} + + +Connection::Connection(const char* db, const char* host, + const char* user, const char* passwd, uint port, + my_bool compress, unsigned int connect_timeout, + cchar* socket_name, unsigned int client_flag) : +OptionalExceptions(), +Lockable(false), +connecting_(false) +{ + mysql_init(&mysql_); + if (connect(db, host, user, passwd, port, compress, + connect_timeout, socket_name, client_flag)) { + unlock(); + success_ = is_connected_ = true; + } + else { + unlock(); + success_ = is_connected_ = false; + if (throw_exceptions()) { + throw ConnectionFailed(error()); + } + } +} + + +Connection::Connection(const Connection& other) : +OptionalExceptions(), +Lockable(false), +is_connected_(false) +{ + copy(other); +} + + +Connection::~Connection() +{ + disconnect(); +} + + +Connection& +Connection::operator=(const Connection& rhs) +{ + copy(rhs); + return *this; +} + + +bool +Connection::connect(cchar* db, cchar* host, cchar* user, + cchar* passwd, uint port, my_bool compress, + unsigned int connect_timeout, cchar* socket_name, + unsigned int client_flag) +{ + lock(); + + // Drop previous connection, if any + if (connected()) { + disconnect(); + } + + // Set defaults for certain connection options. User can override + // these by calling set_option() before connect(). + set_option_default(opt_read_default_file, "my"); + set_option_default(opt_connect_timeout, connect_timeout); + if (compress) { + set_option_default(opt_compress); + } + +#if MYSQL_VERSION_ID >= 40101 + // Check to see if user turned on multi-statements before + // establishing the connection. This one we handle specially, by + // setting a flag during connection establishment. + if (option_set(opt_multi_statements)) { + client_flag |= CLIENT_MULTI_STATEMENTS; + } +#endif + + // Establish connection + scoped_var_set sb(connecting_, true); + if (mysql_real_connect(&mysql_, host, user, passwd, db, port, + socket_name, client_flag)) { + unlock(); + success_ = is_connected_ = true; + + if (db && db[0]) { + // Also attach to given database + success_ = select_db(db); + } + } + else { + unlock(); + success_ = is_connected_ = false; + if (throw_exceptions()) { + throw ConnectionFailed(error()); + } + } + + return success_; +} + + +bool +Connection::connect(const MYSQL& mysql) +{ + return connect(mysql.db, mysql.host, mysql.user, mysql.passwd, + mysql.port, mysql.options.compress, + mysql.options.connect_timeout, mysql.unix_socket, + mysql.client_flag); +} + + +void +Connection::copy(const Connection& other) +{ + if (connected()) { + disconnect(); + } + + mysql_init(&mysql_); + set_exceptions(other.throw_exceptions()); + + if (other.connected()) { + // Try to reconnect to server using same parameters + connect(other.mysql_); + } + else { + is_connected_ = false; + connecting_ = false; + success_ = false; + } +} + + +void +Connection::disconnect() +{ + mysql_close(&mysql_); + is_connected_ = false; +} + + +bool +Connection::create_db(const std::string& db) +{ + Query q(this, throw_exceptions()); + return q.exec("CREATE DATABASE " + db); +} + + +bool +Connection::drop_db(const std::string& db) +{ + Query q(this, throw_exceptions()); + return q.exec("DROP DATABASE " + db); +} + + +bool +Connection::select_db(const char *db) +{ + if (connected()) { + bool suc = !(mysql_select_db(&mysql_, db)); + if (throw_exceptions() && !suc) { + throw DBSelectionFailed(error()); + } + else { + return suc; + } + } + else { + if (throw_exceptions()) { + throw DBSelectionFailed("MySQL++ connection not established"); + } + else { + return false; + } + } +} + + +bool +Connection::reload() +{ + if (connected()) { + bool suc = !mysql_reload(&mysql_); + if (throw_exceptions() && !suc) { + // Reloading grant tables through this API isn't precisely a + // query, but it's acceptable to signal errors with BadQuery + // because the new mechanism is the FLUSH PRIVILEGES query. + // A program won't have to change when doing it the new way. + throw BadQuery(error()); + } + else { + return suc; + } + } + else { + if (throw_exceptions()) { + throw BadQuery("MySQL++ connection not established"); + } + else { + return false; + } + } +} + + +bool +Connection::shutdown() +{ + if (connected()) { + bool suc = !(mysql_shutdown(&mysql_ SHUTDOWN_ARG)); + if (throw_exceptions() && !suc) { + throw ConnectionFailed(error()); + } + else { + return suc; + } + } + else { + if (throw_exceptions()) { + throw ConnectionFailed("MySQL++ connection not established"); + } + else { + return false; + } + } +} + + +string +Connection::info() +{ + const char* i = mysql_info(&mysql_); + if (!i) { + return string(); + } + else { + return string(i); + } +} + + +Query +Connection::query() +{ + return Query(this, throw_exceptions()); +} + + +bool +Connection::set_option(Option option) +{ + if (connected()) { + // None of the argument-less options can be set once the + // connection is up. + return bad_option(option, opt_err_conn); + } + + bool success = false; + switch (option) { + case opt_compress: + success = set_option_impl(MYSQL_OPT_COMPRESS); + break; + + case opt_named_pipe: + success = set_option_impl(MYSQL_OPT_NAMED_PIPE); + break; + +#if MYSQL_VERSION_ID >= 40101 + case opt_use_result: + success = set_option_impl(MYSQL_OPT_USE_RESULT); + break; + + case opt_use_remote_connection: + success = set_option_impl(MYSQL_OPT_USE_REMOTE_CONNECTION); + break; + + case opt_use_embedded_connection: + success = set_option_impl(MYSQL_OPT_USE_EMBEDDED_CONNECTION); + break; + + case opt_guess_connection: + success = set_option_impl(MYSQL_OPT_GUESS_CONNECTION); + break; +#endif + default: + return bad_option(option, opt_err_type); + } + + if (success) { + applied_options_.push_back(OptionInfo(option)); + return true; + } + else { + return bad_option(option, opt_err_value); + } +} + + +bool +Connection::set_option(Option option, const char* arg) +{ + if (connected()) { + // None of the options taking a char* argument can be set once + // the connection is up. + return bad_option(option, opt_err_conn); + } + + bool success = false; + switch (option) { + case opt_init_command: + success = set_option_impl(MYSQL_INIT_COMMAND, arg); + break; + + case opt_read_default_file: + success = set_option_impl(MYSQL_READ_DEFAULT_FILE, arg); + break; + + case opt_read_default_group: + success = set_option_impl(MYSQL_READ_DEFAULT_GROUP, arg); + break; + + case opt_set_charset_dir: + success = set_option_impl(MYSQL_SET_CHARSET_DIR, arg); + break; + + case opt_set_charset_name: + success = set_option_impl(MYSQL_SET_CHARSET_NAME, arg); + break; + +#if MYSQL_VERSION_ID >= 40100 + case opt_shared_memory_base_name: + success = set_option_impl(MYSQL_SHARED_MEMORY_BASE_NAME, arg); + break; +#endif +#if MYSQL_VERSION_ID >= 40101 + case opt_set_client_ip: + success = set_option_impl(MYSQL_SET_CLIENT_IP, arg); + break; +#endif + default: + return bad_option(option, opt_err_type); + } + + if (success) { + applied_options_.push_back(OptionInfo(option, arg)); + return true; + } + else { + return bad_option(option, opt_err_value); + } +} + + +bool +Connection::set_option(Option option, unsigned int arg) +{ + if (connected()) { + // None of the options taking an int argument can be set once + // the connection is up. + return bad_option(option, opt_err_conn); + } + + bool success = false; + switch (option) { + case opt_connect_timeout: + success = set_option_impl(MYSQL_OPT_CONNECT_TIMEOUT, &arg); + break; + + case opt_local_infile: + success = set_option_impl(MYSQL_OPT_LOCAL_INFILE, &arg); + break; + +#if MYSQL_VERSION_ID >= 40100 + case opt_protocol: + success = set_option_impl(MYSQL_OPT_PROTOCOL, &arg); + break; +#endif +#if MYSQL_VERSION_ID >= 40101 + case opt_read_timeout: + success = set_option_impl(MYSQL_OPT_READ_TIMEOUT, &arg); + break; + + case opt_write_timeout: + success = set_option_impl(MYSQL_OPT_WRITE_TIMEOUT, &arg); + break; +#endif + default: + return bad_option(option, opt_err_type); + } + + if (success) { + applied_options_.push_back(OptionInfo(option, arg)); + return true; + } + else { + return bad_option(option, opt_err_value); + } +} + + +bool +Connection::set_option(Option option, bool arg) +{ + if (connected() && (option != opt_multi_statements)) { + // We're connected and it isn't an option that can be set + // after connection is up, so complain to user. + return bad_option(option, opt_err_conn); + } + + bool success = false; + switch (option) { +#if MYSQL_VERSION_ID >= 40101 + case opt_secure_auth: + success = set_option_impl(MYSQL_SECURE_AUTH, &arg); + break; + + case opt_multi_statements: + // If connection is up, set the flag immediately. If not, + // and caller wants this turned on, pretend success so that + // we store the info we need to turn this flag on when + // bringing the connection up. (If the caller is turning it + // off before conn comes up, we effectively ignore this, + // because that's the default.) + if (connected()) { + success = set_option_impl(arg ? + MYSQL_OPTION_MULTI_STATEMENTS_ON : + MYSQL_OPTION_MULTI_STATEMENTS_OFF); + } + else { + success = arg; + } + break; +#endif +#if MYSQL_VERSION_ID >= 50003 + case opt_report_data_truncation: + success = set_option_impl(MYSQL_REPORT_DATA_TRUNCATION, &arg); + break; +#endif +#if MYSQL_VERSION_ID >= 50013 + case opt_reconnect: + success = set_option_impl(MYSQL_OPT_RECONNECT, &arg); + break; +#endif + default: + return bad_option(option, opt_err_type); + } + + if (success) { + applied_options_.push_back(OptionInfo(option, arg)); + return true; + } + else { + return bad_option(option, opt_err_value); + } +} + + +bool +Connection::set_option_default(Option option) +{ + if (option_set(option)) { + return true; + } + else { + return set_option(option); + } +} + + +template +bool +Connection::set_option_default(Option option, T arg) +{ + if (option_set(option)) { + return true; + } + else { + return set_option(option, arg); + } +} + + +bool +Connection::set_option_impl(mysql_option moption, const void* arg) +{ + return !mysql_options(&mysql_, moption, + static_cast(arg)); +} + + +#if MYSQL_VERSION_ID >= 40101 +bool +Connection::set_option_impl(enum_mysql_set_option msoption) +{ + return !mysql_set_server_option(&mysql_, msoption); +} +#endif + + +bool +Connection::bad_option(Option option, OptionError error) +{ + if (throw_exceptions()) { + ostringstream os; + + switch (error) { + case opt_err_type: { + // Option was set using wrong argument type + OptionArgType type = option_arg_type(option); + os << "option " << option; + if (type == opt_type_none) { + os << " does not take an argument"; + } + else { + os << " requires an argument of type " << type; + } + break; + } + + case opt_err_value: + // C API rejected option, which probably indicates that + // you passed a option that it doesn't understand. + os << "option " << option << " not supported in MySQL " + "C API v"; + api_version(os); + break; + + case opt_err_conn: + os << "option " << option << " can only be set " + "before connection is established"; + break; + } + + throw BadOption(os.str(), option); + } + + return false; +} + + +Connection::OptionArgType +Connection::option_arg_type(Option option) +{ + if ((option > opt_FIRST) && (option < opt_COUNT)) { + return legal_opt_arg_types_[option]; + } + else { + // Non-optional exception. Something is wrong with the library + // internals if this one is thrown. + throw BadOption("bad value given to option_arg_type()", option); + } +} + + +bool +Connection::option_set(Option option) +{ + for (OptionListIt it = applied_options_.begin(); + it != applied_options_.end(); + ++it) { + if (it->option == option) { + return true; + } + } + + return false; +} + + +void +Connection::enable_ssl(const char* key, const char* cert, + const char* ca, const char* capath, const char* cipher) +{ +#if defined(HAVE_MYSQL_SSL_SET) + mysql_ssl_set(&mysql_, key, cert, ca, capath, cipher); +#endif +} + + +ostream& +Connection::api_version(ostream& os) +{ + const int major = MYSQL_VERSION_ID / 10000; + const int minor = (MYSQL_VERSION_ID - (major * 10000)) / 100; + const int bug = MYSQL_VERSION_ID - (major * 10000) - (minor * 100); + + os << major << '.' << minor << '.' << bug; + + return os; +} + + +int +Connection::ping() +{ + if (connected()) { + return mysql_ping(&mysql_); + } + else { + // Not connected, and we've forgotten everything we need in + // order to re-connect, if we once were connected. + return 1; + } +} + + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/connection.h b/code/meosdb/mysql++/connection.h new file mode 100644 index 0000000..0debaf5 --- /dev/null +++ b/code/meosdb/mysql++/connection.h @@ -0,0 +1,579 @@ +/// \file connection.h +/// \brief Declares the Connection class. +/// +/// Every program using MySQL++ must create a Connection object, which +/// manages information about the connection to the MySQL database, and +/// performs connection-related operations once the connection is up. +/// Subordinate classes, such as Query and Row take their defaults as +/// to whether exceptions are thrown when errors are encountered from +/// the Connection object that created them, directly or indirectly. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_CONNECTION_H +#define MYSQLPP_CONNECTION_H + +#include "common.h" + +#include "lockable.h" +#include "noexceptions.h" + +#include +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Query; +#endif + +/// \brief Manages the connection to the MySQL database. + +class MYSQLPP_EXPORT Connection : public OptionalExceptions, public Lockable +{ +public: + /// \brief Legal types of option arguments + enum OptionArgType { + opt_type_none, + opt_type_string, + opt_type_integer, + opt_type_boolean + }; + + /// \brief Per-connection options you can set with set_option() + /// + /// This is currently a combination of the MySQL C API + /// \c mysql_option and \c enum_mysql_set_option enums. It may + /// be extended in the future. + enum Option + { + // Symbolic "first" option, before real options. Never send + // this to set_option()! + opt_FIRST = -1, + + opt_connect_timeout = 0, + opt_compress, + opt_named_pipe, + opt_init_command, + opt_read_default_file, + opt_read_default_group, + opt_set_charset_dir, + opt_set_charset_name, + opt_local_infile, + opt_protocol, + opt_shared_memory_base_name, + opt_read_timeout, + opt_write_timeout, + opt_use_result, + opt_use_remote_connection, + opt_use_embedded_connection, + opt_guess_connection, + opt_set_client_ip, + opt_secure_auth, + + // Set multi-query statement support; no argument + opt_multi_statements, + + // Set reporting of data truncation errors + opt_report_data_truncation, + + // Enable or disable automatic reconnection to the server if + // the connection is found to have been lost. + opt_reconnect, + + // Number of options supported. Never send this to + // set_option()! + opt_COUNT + }; + + /// \brief Create object without connecting it to the MySQL server. + /// + /// \param te if true, exceptions are thrown on errors + Connection(bool te = true); + + /// \brief Create object and connect to database server in one step. + /// + /// This constructor allows you to most fully specify the options + /// used when connecting to the MySQL database. It is the thinnest + /// layer in MySQL++ over the MySQL C API function + /// \c mysql_real_connect(). The correspondence isn't exact as + /// we have some additional parameters you'd have to set with + /// \c mysql_option() when using the C API. + /// + /// \param db name of database to use + /// \param host host name or IP address of MySQL server, or 0 + /// if server is running on the same host as your program + /// \param user user name to log in under, or 0 to use the user + /// name this program is running under + /// \param passwd password to use when logging in + /// \param port TCP port number MySQL server is listening on, or 0 + /// to use default value + /// \param compress if true, compress data passing through + /// connection, to save bandwidth at the expense of CPU time + /// \param connect_timeout max seconds to wait for server to + /// respond to our connection attempt + /// \param socket_name Unix domain socket server is using, if + /// connecting to MySQL server on the same host as this program + /// running on, or 0 to use default name + /// \param client_flag special connection flags. See MySQL C API + /// documentation for \c mysql_real_connect() for details. + Connection(const char* db, const char* host = "", + const char* user = "", const char* passwd = "", + uint port = 0, my_bool compress = 0, + unsigned int connect_timeout = 60, cchar* socket_name = 0, + unsigned int client_flag = 0); + + /// \brief Establish a new connection using the same parameters as + /// an existing C API connection. + /// + /// \param other existing Connection object + Connection(const Connection& other); + + /// \brief Establish a new connection using the same parameters as + /// an existing C API connection. + /// + /// \param mysql existing MySQL C API connection object + bool connect(const MYSQL& mysql); + + /// \brief Destroy connection object + ~Connection(); + + /// \brief Connect to database after object is created. + /// + /// It's better to use the connect-on-create constructor if you can. + /// See its documentation for the meaning of these parameters. + /// + /// If you call this method on an object that is already connected + /// to a database server, the previous connection is dropped and a + /// new connection is established. + bool connect(cchar* db = "", cchar* host = "", + cchar* user = "", cchar* passwd = "", uint port = 0, + my_bool compress = 0, unsigned int connect_timeout = 60, + cchar* socket_name = 0, unsigned int client_flag = 0); + + /// \brief Close connection to MySQL server. + /// + /// Closes the connection to the MySQL server. + void close() + { + mysql_close(&mysql_); + is_connected_ = false; + } + + /// \brief Calls MySQL C API function \c mysql_info() and returns + /// result as a C++ string. + std::string info(); + + /// \brief return true if connection was established successfully + /// + /// \return true if connection was established successfully + bool connected() const + { + return is_connected_; + } + + /// \brief Return true if the last query was successful + bool success() const + { + return success_; + } + + /// \brief Alias for close() + void purge() { close(); } + + /// \brief Return a new query object. + /// + /// The returned query object is tied to this MySQL connection, + /// so when you call a method like + /// \link mysqlpp::Query::execute() execute() \endlink + /// on that object, the query is sent to the server this object + /// is connected to. + Query query(); + + /// \brief Alias for success() + /// + /// Alias for success() member function. Allows you to have code + /// constructs like this: + /// + /// \code + /// Connection conn; + /// .... use conn + /// if (conn) { + /// ... last SQL query was successful + /// } + /// else { + /// ... error occurred in SQL query + /// } + /// \endcode + operator bool() { return success(); } + + /// \brief Copy an existing Connection object's state into this + /// object. + Connection& operator=(const Connection& rhs); + + /// \brief Return error message for last MySQL error associated with + /// this connection. + /// + /// Simply wraps \c mysql_error() in the C API. + const char* error() + { + return mysql_error(&mysql_); + } + + /// \brief Return last MySQL error number associated with this + /// connection + /// + /// Simply wraps \c mysql_errno() in the C API. + int errnum() { return mysql_errno(&mysql_); } + + /// \brief Wraps MySQL C API function \c mysql_refresh() + /// + /// The corresponding C API function is undocumented. All I know + /// is that it's used by \c mysqldump and \c mysqladmin, according + /// to MySQL bug database entry http://bugs.mysql.com/bug.php?id=9816 + /// If that entry changes to say that the function is now documented, + /// reevaluate whether we need to wrap it. It may be that it's not + /// supposed to be used by regular end-user programs. + int refresh(unsigned int refresh_options) + { + return mysql_refresh(&mysql_, refresh_options); + } + + /// \brief "Pings" the MySQL database + /// + /// Wraps \c mysql_ping() in the C API. As a result, this function + /// will try to reconnect to the server if the connection has been + /// dropped. + /// + /// \retval 0 if server is responding, regardless of whether we had + /// to reconnect or not + /// \retval nonzero if either we already know the connection is down + /// and cannot re-establish it, or if the server did not respond to + /// the ping and we could not re-establish the connection. + int ping(); + + /// \brief Kill a MySQL server thread + /// + /// \param pid ID of thread to kill + /// + /// Simply wraps \c mysql_kill() in the C API. + int kill(unsigned long pid) + { + return mysql_kill(&mysql_, pid); + } + + /// \brief Get MySQL client library version + /// + /// Simply wraps \c mysql_get_client_info() in the C API. + std::string client_info() + { + return std::string(mysql_get_client_info()); + } + + /// \brief Get information about the network connection + /// + /// String contains info about type of connection and the server + /// hostname. + /// + /// Simply wraps \c mysql_get_host_info() in the C API. + std::string host_info() + { + return std::string(mysql_get_host_info(&mysql_)); + } + + /// \brief Returns version number of MySQL protocol this connection + /// is using + /// + /// Simply wraps \c mysql_get_proto_info() in the C API. + int proto_info() + { + return mysql_get_proto_info(&mysql_); + } + + /// \brief Get the MySQL server's version number + /// + /// Simply wraps \c mysql_get_server_info() in the C API. + std::string server_info() + { + return std::string(mysql_get_server_info(&mysql_)); + } + + /// \brief Returns information about MySQL server status + /// + /// String is similar to that returned by the \c mysqladmin + /// \c status command. Among other things, it contains uptime + /// in seconds, and the number of running threads, questions + /// and open tables. + std::string stat() + { + return std::string(mysql_stat(&mysql_)); + } + + /// \brief Create a database + /// + /// \param db name of database to create + /// + /// \return true if database was created successfully + bool create_db(const std::string& db); + + /// \brief Drop a database + /// + /// \param db name of database to destroy + /// + /// \return true if database was created successfully + bool drop_db(const std::string& db); + + /// \brief Change to a different database + bool select_db(const std::string& db) + { + return select_db(db.c_str()); + } + + /// \brief Change to a different database + bool select_db(const char* db); + + /// \brief Ask MySQL server to reload the grant tables + /// + /// User must have the "reload" privilege. + /// + /// Simply wraps \c mysql_reload() in the C API. Since that + /// function is deprecated, this one is, too. The MySQL++ + /// replacement is execute("FLUSH PRIVILEGES"). + bool reload(); + + /// \brief Ask MySQL server to shut down. + /// + /// User must have the "shutdown" privilege. + /// + /// Simply wraps \c mysql_shutdown() in the C API. + bool shutdown(); + + /// \brief Return the connection options object + st_mysql_options get_options() const + { + return mysql_.options; + } + + /// \brief Sets a connection option, with no argument + /// + /// \param option any of the Option enum constants + /// + /// Based on the option you give, this function calls either + /// \c mysql_options() or \c mysql_set_server_option() in the C API. + /// + /// There are several overloaded versions of this function. The + /// others take an additional argument for the option and differ + /// only by the type of the option. Unlike with the underlying C + /// API, it does matter which of these overloads you call: if you + /// use the wrong argument type or pass an argument where one is + /// not expected (or vice versa), the call will either throw an + /// exception or return false, depending on the object's "throw + /// exceptions" flag. + /// + /// This mechanism parallels the underlying C API structure fairly + /// closely, but do not expect this to continue in the future. + /// Its very purpose is to 'paper over' the differences among the + /// C API's option setting mechanisms, so it may become further + /// abstracted from these mechanisms. + /// + /// \retval true if option was successfully set, or at least queued + /// for setting during connection establishment sequence + /// + /// If exceptions are enabled, a false return means the C API + /// rejected the option, or the connection is not established and + /// so the option was queued for later processing. If exceptions + /// are disabled, false can also mean that the argument was of the + /// wrong type (wrong overload was called), the option value was out + /// of range, or the option is not supported by the C API, most + /// because it isn't a high enough version. These latter cases will + /// cause BadOption exceptions otherwise. + bool set_option(Option option); + + /// \brief Sets a connection option, with string argument + bool set_option(Option option, const char* arg); + + /// \brief Sets a connection option, with integer argument + bool set_option(Option option, unsigned int arg); + + /// \brief Sets a connection option, with Boolean argument + bool set_option(Option option, bool arg); + + /// \brief Same as set_option(), except that it won't override + /// a previously-set option. + bool set_option_default(Option option); + + /// \brief Same as set_option(), except that it won't override + /// a previously-set option. + template + bool set_option_default(Option option, T arg); + + /// \brief Returns true if the given option has been set already + bool option_set(Option option); + + /// \brief Enable SSL-encrypted connection. + /// + /// \param key the pathname to the key file + /// \param cert the pathname to the certificate file + /// \param ca the pathname to the certificate authority file + /// \param capath directory that contains trusted SSL CA + /// certificates in pem format. + /// \param cipher list of allowable ciphers to use + /// + /// Must be called before connection is established. + /// + /// Wraps \c mysql_ssl_set() in MySQL C API. + void enable_ssl(const char* key = 0, + const char* cert = 0, const char* ca = 0, + const char* capath = 0, const char* cipher = 0); + + /// \brief Return the number of rows affected by the last query + /// + /// Simply wraps \c mysql_affected_rows() in the C API. + my_ulonglong affected_rows() + { + return mysql_affected_rows(&mysql_); + } + + /// \brief Get ID generated for an AUTO_INCREMENT column in the + /// previous INSERT query. + /// + /// \retval 0 if the previous query did not generate an ID. Use + /// the SQL function LAST_INSERT_ID() if you need the last ID + /// generated by any query, not just the previous one. + my_ulonglong insert_id() + { + return mysql_insert_id(&mysql_); + } + + /// \brief Insert C API version we're linked against into C++ stream + /// + /// Version will be of the form X.Y.Z, where X is the major version + /// number, Y the minor version, and Z the bug fix number. + std::ostream& api_version(std::ostream& os); + +protected: + /// \brief Types of option setting errors we can diagnose + enum OptionError { + opt_err_type, + opt_err_value, + opt_err_conn + }; + + /// \brief Drop the connection to the database server + /// + /// This method is protected because it should only be used within + /// the library. Unless you use the default constructor, this + /// object should always be connected. + void disconnect(); + + /// \brief Error handling routine for set_option() + bool bad_option(Option option, OptionError error); + + /// \brief Given option value, return its proper argument type + OptionArgType option_arg_type(Option option); + + /// \brief Set MySQL C API connection option + /// + /// Wraps \c mysql_options() in C API. This is an internal + /// implementation detail, to be used only by the public overloads + /// above. + bool set_option_impl(mysql_option moption, const void* arg = 0); + +#if MYSQL_VERSION_ID >= 40101 + /// \brief Set MySQL C API connection option + /// + /// Wraps \c mysql_set_server_option() in C API. This is an + /// internal implementation detail, to be used only by the public + /// overloads above. + bool set_option_impl(enum_mysql_set_option msoption); +#endif + + /// \brief Establish a new connection as a copy of an existing one + /// + /// \param other the connection to copy + void copy(const Connection& other); + +private: + friend class ResNSel; + friend class ResUse; + friend class Query; + + struct OptionInfo { + Option option; + OptionArgType arg_type; + std::string str_arg; + unsigned int int_arg; + bool bool_arg; + + OptionInfo(Option o) : + option(o), + arg_type(opt_type_none), + int_arg(0), + bool_arg(false) + { + } + + OptionInfo(Option o, const char* a) : + option(o), + arg_type(opt_type_string), + str_arg(a), + int_arg(0), + bool_arg(false) + { + } + + OptionInfo(Option o, unsigned int a) : + option(o), + arg_type(opt_type_integer), + int_arg(a), + bool_arg(false) + { + } + + OptionInfo(Option o, bool a) : + option(o), + arg_type(opt_type_boolean), + int_arg(0), + bool_arg(a) + { + } + }; + typedef std::deque OptionList; + typedef OptionList::const_iterator OptionListIt; + + MYSQL mysql_; + bool is_connected_; + bool connecting_; + bool success_; + OptionList applied_options_; + static OptionArgType legal_opt_arg_types_[]; +}; + + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/const_string.h b/code/meosdb/mysql++/const_string.h new file mode 100644 index 0000000..10d751e --- /dev/null +++ b/code/meosdb/mysql++/const_string.h @@ -0,0 +1,258 @@ +/// \file const_string.h +/// \brief Declares a wrapper for const char* which behaves +/// in a way more useful to MySQL++. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_CONST_STRING_H +#define MYSQLPP_CONST_STRING_H + +#include "common.h" + +#include +#include +#include +#include + +namespace mysqlpp { + +/// \brief Wrapper for const char* to make it behave in a +/// way more useful to MySQL++. +/// +/// This class implements a small subset of the standard string class. +/// +/// As of MySQL++ 2.3, it makes a copy of the string we are initialized +/// with, instead of just copying the pointer. This is required to +/// avoid problems with the new SSQLS + BLOB support. +class MYSQLPP_EXPORT const_string +{ +public: + /// \brief Type of the data stored in this object, when it is not + /// equal to SQL null. + typedef const char value_type; + + /// \brief Type of "size" integers + typedef unsigned int size_type; + + /// \brief Type used when returning a reference to a character in + /// the string. + typedef const char& const_reference; + + /// \brief Type of iterators + typedef const char* const_iterator; + + /// \brief Same as const_iterator because the data cannot be + /// changed. + typedef const_iterator iterator; + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + typedef int difference_type; + typedef const_reference reference; + typedef const char* const_pointer; + typedef const_pointer pointer; +#endif // !defined(DOXYGEN_IGNORE) + + /// \brief Create empty string + const_string() : + str_data_(0), + length_(0) + { + } + + /// \brief Initialize string from existing C++ string + const_string(const std::string& str) : + str_data_(0), + length_(str.length()) + { + str_data_ = new char[length_ + 1]; + memcpy(str_data_, str.data(), length_); + str_data_[length_] = '\0'; + } + + /// \brief Initialize string from existing C string + const_string(const char* str) : + str_data_(0), + length_(size_type(strlen(str))) + { + str_data_ = new char[length_ + 1]; + memcpy(str_data_, str, length_); + str_data_[length_] = '\0'; + } + + /// \brief Initialize string from existing C string of known length + const_string(const char* str, size_type len) : + str_data_(0), + length_(size_type(len)) + { + str_data_ = new char[length_ + 1]; + memcpy(str_data_, str, length_); + str_data_[length_] = '\0'; + } + + /// \brief Destroy string + ~const_string() + { + delete[] str_data_; + } + + /// \brief Assignment operator, from C string + const_string& operator=(const char* str) + { + delete[] str_data_; + length_ = size_type(strlen(str)); + str_data_ = new char[length_]; + memcpy(str_data_, str, length_); + return *this; + } + + /// \brief Assignment operator, from other const_string + const_string& operator=(const const_string& cs) + { + delete[] str_data_; + length_ = cs.length_; + str_data_ = new char[length_]; + memcpy(str_data_, cs.str_data_, length_); + return *this; + } + + /// \brief Return number of characters in the string + size_type length() const { return length_; } + + /// \brief Return number of characters in string + size_type size() const { return length_; } + + /// \brief Return iterator pointing to the first character of + /// the string + const_iterator begin() const { return str_data_; } + + /// \brief Return iterator pointing to one past the last character + /// of the string. + const_iterator end() const { return str_data_ + size(); } + + /// \brief Return the maximum number of characters in the string. + /// + /// Because this is a \c const string, this is just an alias for + /// size(); its size is always equal to the amount of data currently + /// stored. + size_type max_size() const { return size(); } + + /// \brief Return a reference to a character within the string. + const_reference operator [](size_type pos) const + { return str_data_[pos]; } + + /// \brief Return a reference to a character within the string. + /// + /// Unlike \c operator[](), this function throws an + /// \c std::out_of_range exception if the index isn't within range. + const_reference at(size_type pos) const + { + if (pos >= size()) + throw std::out_of_range(""); + else + return str_data_[pos]; + } + + /// \brief Return a const pointer to the string data. Not + /// necessarily null-terminated! + const char* c_str() const { return str_data_; } + + /// \brief Alias for \c c_str() + const char* data() const { return str_data_; } + + /// \brief Lexically compare this string to another. + /// + /// \param str string to compare against this one + /// + /// \retval <0 if str1 is lexically "less than" str2 + /// \retval 0 if str1 is equal to str2 + /// \retval >0 if str1 is lexically "greater than" str2 + int compare(const const_string& str) const + { + size_type i = 0, short_len = std::min(length(), str.length()); + while ((i < short_len) && (str_data_[i] != str.str_data_[i])) { + ++i; + } + return str_data_[i] - str.str_data_[i]; + } + +private: + char* str_data_; + size_type length_; +}; + + +/// \brief Inserts a const_string into a C++ stream +inline std::ostream& operator <<(std::ostream& o, + const const_string& str) +{ + return o << str.c_str(); +} + +/// \brief Calls lhs.compare(), passing rhs +inline int compare(const const_string& lhs, const const_string& rhs) +{ + return lhs.compare(rhs); +} + +/// \brief Returns true if lhs is the same as rhs +inline bool operator ==(const_string& lhs, const_string& rhs) +{ + return compare(lhs, rhs) == 0; +} + +/// \brief Returns true if lhs is not the same as rhs +inline bool operator !=(const_string& lhs, const_string& rhs) +{ + return compare(lhs, rhs) != 0; +} + +/// \brief Returns true if lhs is lexically less than rhs +inline bool operator <(const_string& lhs, const_string& rhs) +{ + return compare(lhs, rhs) < 0; +} + +/// \brief Returns true if lhs is lexically less or equal to rhs +inline bool operator <=(const_string& lhs, const_string& rhs) +{ + return compare(lhs, rhs) <= 0; +} + +/// \brief Returns true if lhs is lexically greater than rhs +inline bool operator >(const_string& lhs, const_string& rhs) +{ + return compare(lhs, rhs) > 0; +} + +/// \brief Returns true if lhs is lexically greater than or equal to rhs +inline bool operator >=(const_string& lhs, const_string& rhs) +{ + return compare(lhs, rhs) >= 0; +} + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/convert.h b/code/meosdb/mysql++/convert.h new file mode 100644 index 0000000..fd27642 --- /dev/null +++ b/code/meosdb/mysql++/convert.h @@ -0,0 +1,117 @@ +/// \file convert.h +/// \brief Declares various string-to-integer type conversion templates. +/// +/// These templates are the mechanism used within mysqlpp::ColData_Tmpl +/// for its string-to-\e something conversions. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_CONVERT_H +#define MYSQLPP_CONVERT_H + +#include "common.h" + +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +template class mysql_convert; + +#define mysql__convert(TYPE, FUNC) \ + template <> \ + class mysql_convert {\ + public:\ + mysql_convert(const char* str, const char *& end) { \ + num_ = FUNC(str, const_cast(&end));}\ + operator TYPE () {return num_;}\ + private:\ + TYPE num_;\ + };\ + +#if defined(_MSC_VER) +# pragma warning(disable: 4244) +#endif + + mysql__convert(float, strtod) + mysql__convert(double, strtod) + +#if defined(_MSC_VER) +# pragma warning(default: 4244) +#endif + +#undef mysql__convert +#define mysql__convert(TYPE, FUNC) \ + template <> \ + class mysql_convert {\ + public:\ + mysql_convert(const char* str, const char *& end) { \ + num_ = FUNC(str, const_cast(&end),10);}\ + operator TYPE () {return num_;}\ + private:\ + TYPE num_;\ + };\ + +#if defined(_MSC_VER) +# pragma warning(disable: 4244) +#endif + + mysql__convert(char, strtol) + mysql__convert(signed char, strtol) + mysql__convert(int, strtol) + mysql__convert(short int, strtol) + mysql__convert(long int, strtol) + + mysql__convert(unsigned char, strtoul) + mysql__convert(unsigned int, strtoul) + mysql__convert(unsigned short int, strtoul) + mysql__convert(unsigned long int, strtoul) + +#if defined(_MSC_VER) +# pragma warning(default: 4244) +#endif + +#if !defined(NO_LONG_LONGS) +#if defined(_MSC_VER) +// Handle 64-bit ints the VC++ way +mysql__convert(longlong, _strtoi64) +mysql__convert(ulonglong, _strtoui64) +#else +// No better idea, so assume the C99 way. If your compiler doesn't +// support this, please provide a patch to extend this ifdef, or define +// NO_LONG_LONGS. +mysql__convert(longlong, strtoll) +mysql__convert(ulonglong, strtoull) +#endif +#endif // !defined(NO_LONG_LONGS) + +#endif // !defined(DOXYGEN_IGNORE) + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/custom-macros.h b/code/meosdb/mysql++/custom-macros.h new file mode 100644 index 0000000..dd4dfdc --- /dev/null +++ b/code/meosdb/mysql++/custom-macros.h @@ -0,0 +1,24938 @@ + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// This file is generated by the Perl script custom.pl. Please do +// not modify this file directly. Change the script instead. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// --------------------------------------------------- +// Begin Mandatory Compare +// --------------------------------------------------- + +#define sql_compare_define(NAME) \ + bool operator == (const NAME &other) const \ + {return sql_compare_##NAME(*this,other) == 0;} \ + bool operator != (const NAME &other) const \ + {return sql_compare_##NAME(*this,other) != 0;} \ + bool operator > (const NAME &other) const \ + {return sql_compare_##NAME(*this,other) > 0;} \ + bool operator < (const NAME &other) const \ + {return sql_compare_##NAME(*this,other) < 0;} \ + bool operator >= (const NAME &other) const \ + {return sql_compare_##NAME(*this,other) >= 0;} \ + bool operator <= (const NAME &other) const \ + {return sql_compare_##NAME(*this,other) <= 0;} \ + int cmp (const NAME &other) const \ + {return sql_compare_##NAME(*this,other);} \ + int compare (const NAME &other) const \ + {return sql_compare_##NAME(*this,other);} + +#define sql_compare_define_0(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) + +#define sql_construct_define_0(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) + +#define sql_COMPARE__0(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) + +#define sql_compare_type_def_0(NAME, WHAT, NUM) \ + sql_compare_type_def_##NUM (NAME, WHAT, NUM) + +#define sql_compare_type_defe_0(NAME, WHAT, NUM) \ + sql_compare_type_defe_##NUM (NAME, WHAT, NUM) + +// --------------------------------------------------- +// End Mandatory Compare +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Compare 1 +// --------------------------------------------------- + +#define sql_compare_define_1(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1) : C1 (p1) {} \ + void set (const T1 &p1) { \ + C1 = p1;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_1(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1) { \ + C1 = p1;\ + \ + } \ + NAME (const T1 &p1) : C1 (p1) {} + +#define sql_compare_type_def_1(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true) + +#define sql_compare_type_defe_1(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true) + +#define sql_COMPARE__1(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + return mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + return mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + } + +// --------------------------------------------------- +// End Compare 1 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 2 +// --------------------------------------------------- + +#define sql_compare_define_2(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2) : C1 (p1), C2 (p2) {} \ + void set (const T1 &p1, const T2 &p2) { \ + C1 = p1;\ + C2 = p2;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_2(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2) { \ + C1 = p1;\ + C2 = p2;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2) : C1 (p1), C2 (p2) {} + +#define sql_compare_type_def_2(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true) + +#define sql_compare_type_defe_2(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true) + +#define sql_COMPARE__2(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + } + +// --------------------------------------------------- +// End Compare 2 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 3 +// --------------------------------------------------- + +#define sql_compare_define_3(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3) : C1 (p1), C2 (p2), C3 (p3) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_3(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3) : C1 (p1), C2 (p2), C3 (p3) {} + +#define sql_compare_type_def_3(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true) + +#define sql_compare_type_defe_3(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true) + +#define sql_COMPARE__3(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + } + +// --------------------------------------------------- +// End Compare 3 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 4 +// --------------------------------------------------- + +#define sql_compare_define_4(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4) : C1 (p1), C2 (p2), C3 (p3), C4 (p4) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_4(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4) : C1 (p1), C2 (p2), C3 (p3), C4 (p4) {} + +#define sql_compare_type_def_4(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true) + +#define sql_compare_type_defe_4(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true) + +#define sql_COMPARE__4(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + } + +// --------------------------------------------------- +// End Compare 4 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 5 +// --------------------------------------------------- + +#define sql_compare_define_5(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_5(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5) {} + +#define sql_compare_type_def_5(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true) + +#define sql_compare_type_defe_5(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true) + +#define sql_COMPARE__5(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + } + +// --------------------------------------------------- +// End Compare 5 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 6 +// --------------------------------------------------- + +#define sql_compare_define_6(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_6(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6) {} + +#define sql_compare_type_def_6(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true) + +#define sql_compare_type_defe_6(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true) + +#define sql_COMPARE__6(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + } + +// --------------------------------------------------- +// End Compare 6 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 7 +// --------------------------------------------------- + +#define sql_compare_define_7(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_7(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7) {} + +#define sql_compare_type_def_7(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_7(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true) + +#define sql_COMPARE__7(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + } + +// --------------------------------------------------- +// End Compare 7 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 8 +// --------------------------------------------------- + +#define sql_compare_define_8(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_8(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8) {} + +#define sql_compare_type_def_8(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_8(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__8(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + } + +// --------------------------------------------------- +// End Compare 8 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 9 +// --------------------------------------------------- + +#define sql_compare_define_9(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_9(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9) {} + +#define sql_compare_type_def_9(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_9(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__9(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + } + +// --------------------------------------------------- +// End Compare 9 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 10 +// --------------------------------------------------- + +#define sql_compare_define_10(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_10(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10) {} + +#define sql_compare_type_def_10(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_10(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__10(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + } + +// --------------------------------------------------- +// End Compare 10 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 11 +// --------------------------------------------------- + +#define sql_compare_define_11(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_11(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11) {} + +#define sql_compare_type_def_11(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_11(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__11(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + } + +// --------------------------------------------------- +// End Compare 11 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 12 +// --------------------------------------------------- + +#define sql_compare_define_12(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_12(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12) {} + +#define sql_compare_type_def_12(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_12(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__12(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + } + +// --------------------------------------------------- +// End Compare 12 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 13 +// --------------------------------------------------- + +#define sql_compare_define_13(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_13(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13) {} + +#define sql_compare_type_def_13(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_13(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__13(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + } + +// --------------------------------------------------- +// End Compare 13 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 14 +// --------------------------------------------------- + +#define sql_compare_define_14(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_14(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14) {} + +#define sql_compare_type_def_14(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_14(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__14(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + } + +// --------------------------------------------------- +// End Compare 14 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 15 +// --------------------------------------------------- + +#define sql_compare_define_15(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_15(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15) {} + +#define sql_compare_type_def_15(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_15(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__15(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + } + +// --------------------------------------------------- +// End Compare 15 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 16 +// --------------------------------------------------- + +#define sql_compare_define_16(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_16(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16) {} + +#define sql_compare_type_def_16(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_16(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__16(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + } + +// --------------------------------------------------- +// End Compare 16 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 17 +// --------------------------------------------------- + +#define sql_compare_define_17(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_17(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17) {} + +#define sql_compare_type_def_17(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_17(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__17(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + } + +// --------------------------------------------------- +// End Compare 17 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 18 +// --------------------------------------------------- + +#define sql_compare_define_18(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_18(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18) {} + +#define sql_compare_type_def_18(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_18(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__18(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + } + +// --------------------------------------------------- +// End Compare 18 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 19 +// --------------------------------------------------- + +#define sql_compare_define_19(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_19(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19) {} + +#define sql_compare_type_def_19(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_19(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__19(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + } + +// --------------------------------------------------- +// End Compare 19 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 20 +// --------------------------------------------------- + +#define sql_compare_define_20(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_20(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20) {} + +#define sql_compare_type_def_20(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_20(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__20(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + } + +// --------------------------------------------------- +// End Compare 20 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 21 +// --------------------------------------------------- + +#define sql_compare_define_21(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_21(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21) {} + +#define sql_compare_type_def_21(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_21(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__21(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + } + +// --------------------------------------------------- +// End Compare 21 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 22 +// --------------------------------------------------- + +#define sql_compare_define_22(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_22(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22) {} + +#define sql_compare_type_def_22(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_22(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__22(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + } + +// --------------------------------------------------- +// End Compare 22 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 23 +// --------------------------------------------------- + +#define sql_compare_define_23(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22), C23 (p23) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + C23 = p23;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_23(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + C23 = p23;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22), C23 (p23) {} + +#define sql_compare_type_def_23(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_23(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__23(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C23 , y.C23 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C23 , y.C23 ); \ + } + +// --------------------------------------------------- +// End Compare 23 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 24 +// --------------------------------------------------- + +#define sql_compare_define_24(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22), C23 (p23), C24 (p24) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + C23 = p23;\ + C24 = p24;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_24(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + C23 = p23;\ + C24 = p24;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22), C23 (p23), C24 (p24) {} + +#define sql_compare_type_def_24(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_24(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__24(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C23 , y.C23 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C24 , y.C24 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C23 , y.C23 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C24 , y.C24 ); \ + } + +// --------------------------------------------------- +// End Compare 24 +// --------------------------------------------------- + + +// --------------------------------------------------- +// Begin Compare 25 +// --------------------------------------------------- + +#define sql_compare_define_25(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24, const T25 &p25) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22), C23 (p23), C24 (p24), C25 (p25) {} \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24, const T25 &p25) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + C23 = p23;\ + C24 = p24;\ + C25 = p25;\ + \ + } \ + sql_compare_define(NAME) + +#define sql_construct_define_25(NAME, T1, C1, T2, C2, T3, C3, T4, C4, T5, C5, T6, C6, T7, C7, T8, C8, T9, C9, T10, C10, T11, C11, T12, C12, T13, C13, T14, C14, T15, C15, T16, C16, T17, C17, T18, C18, T19, C19, T20, C20, T21, C21, T22, C22, T23, C23, T24, C24, T25, C25) \ + void set (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24, const T25 &p25) { \ + C1 = p1;\ + C2 = p2;\ + C3 = p3;\ + C4 = p4;\ + C5 = p5;\ + C6 = p6;\ + C7 = p7;\ + C8 = p8;\ + C9 = p9;\ + C10 = p10;\ + C11 = p11;\ + C12 = p12;\ + C13 = p13;\ + C14 = p14;\ + C15 = p15;\ + C16 = p16;\ + C17 = p17;\ + C18 = p18;\ + C19 = p19;\ + C20 = p20;\ + C21 = p21;\ + C22 = p22;\ + C23 = p23;\ + C24 = p24;\ + C25 = p25;\ + \ + } \ + NAME (const T1 &p1, const T2 &p2, const T3 &p3, const T4 &p4, const T5 &p5, const T6 &p6, const T7 &p7, const T8 &p8, const T9 &p9, const T10 &p10, const T11 &p11, const T12 &p12, const T13 &p13, const T14 &p14, const T15 &p15, const T16 &p16, const T17 &p17, const T18 &p18, const T19 &p19, const T20 &p20, const T21 &p21, const T22 &p22, const T23 &p23, const T24 &p24, const T25 &p25) : C1 (p1), C2 (p2), C3 (p3), C4 (p4), C5 (p5), C6 (p6), C7 (p7), C8 (p8), C9 (p9), C10 (p10), C11 (p11), C12 (p12), C13 (p13), C14 (p14), C15 (p15), C16 (p16), C17 (p17), C18 (p18), C19 (p19), C20 (p20), C21 (p21), C22 (p22), C23 (p23), C24 (p24), C25 (p25) {} + +#define sql_compare_type_def_25(NAME, WHAT, NUM) \ + return WHAT##_list(d, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_compare_type_defe_25(NAME, WHAT, NUM) \ + return WHAT##_list(d, c, m, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + +#define sql_COMPARE__25(NAME, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25) \ + template \ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C23 , y.C23 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C24 , y.C24 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C25 , y.C25 ); \ + } \ + template \ + int compare (const NAME &x, const NAME &y) { \ + int cmp; \ + cmp = mysqlpp::sql_cmp(x.C1 , y.C1 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C2 , y.C2 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C3 , y.C3 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C4 , y.C4 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C5 , y.C5 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C6 , y.C6 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C7 , y.C7 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C8 , y.C8 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C9 , y.C9 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C10 , y.C10 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C11 , y.C11 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C12 , y.C12 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C13 , y.C13 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C14 , y.C14 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C15 , y.C15 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C16 , y.C16 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C17 , y.C17 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C18 , y.C18 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C19 , y.C19 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C20 , y.C20 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C21 , y.C21 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C22 , y.C22 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C23 , y.C23 ); \ + if (cmp) return cmp; \ + cmp = mysqlpp::sql_cmp(x.C24 , y.C24 ); \ + if (cmp) return cmp; \ + return mysqlpp::sql_cmp(x.C25 , y.C25 ); \ + } + +// --------------------------------------------------- +// End Compare 25 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 1 +// --------------------------------------------------- +#define sql_create_basic_c_order_1(NAME, CMP, CONTR, T1, I1, O1)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_1(NAME, CMP, CONTR, T1, I1, N1, O1) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1) const {\ + return value_list(",", mysqlpp::quote, i1);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1) const {\ + return value_list(",", mysqlpp::quote, i1);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1) const {\ + return value_list(d, mysqlpp::quote, i1);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1) const {\ + return value_list(d, mysqlpp::quote, i1);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1) const {\ + return field_list(",", mysqlpp::do_nothing, i1);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1) const {\ + return field_list(",", mysqlpp::do_nothing, i1);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1) const {\ + return field_list(d, mysqlpp::do_nothing, i1);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1) const {\ + return field_list(d, mysqlpp::do_nothing, i1);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1) const {\ + return equal_list(d, c, mysqlpp::quote, i1);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1) const {\ + return equal_list(d, c, mysqlpp::quote, i1);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(1, false);\ + if (i1) (*include)[0]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(1, false); \ + (*include)[i1]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(1, false); \ + if (i1) (*include)[0]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(1, false); \ + (*include)[i1]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(1, false); \ + if (i1) (*include)[0]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(1, false); \ + (*include)[i1]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1) const {\ + return NAME##_cus_value_list (this, d, m, i1); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1) const { \ + return NAME##_cus_field_list (this, d, m, i1); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1) const { \ + return NAME##_cus_value_list (this, d, m, i1); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1) const {\ + return NAME##_cus_field_list (this, d, m, i1); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_1(NAME, CMP, CONTR, T1, I1) \ + sql_create_basic_c_order_1(NAME, CMP, CONTR, T1, I1, 0) + +#define sql_create_1(NAME, CMP, CONTR, T1, I1) \ + sql_create_complete_1(NAME, CMP, CONTR, T1, I1, #I1, 0) \ + +#define sql_create_c_order_1(NAME, CMP, CONTR, T1, I1, O1) \ + sql_create_complete_1(NAME, CMP, CONTR, T1, I1, #I1, O1) + +#define sql_create_c_names_1(NAME, CMP, CONTR, T1, I1, N1) \ + sql_create_complete_1(NAME, CMP, CONTR, T1, I1, N1, 0) + +// --------------------------------------------------- +// End Create 1 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 2 +// --------------------------------------------------- +#define sql_create_basic_c_order_2(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_2(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(2, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(2, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(2, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(2, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(2, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(2, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_2(NAME, CMP, CONTR, T1, I1, T2, I2) \ + sql_create_basic_c_order_2(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1) + +#define sql_create_2(NAME, CMP, CONTR, T1, I1, T2, I2) \ + sql_create_complete_2(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1) \ + +#define sql_create_c_order_2(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2) \ + sql_create_complete_2(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2) + +#define sql_create_c_names_2(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2) \ + sql_create_complete_2(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1) + +// --------------------------------------------------- +// End Create 2 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 3 +// --------------------------------------------------- +#define sql_create_basic_c_order_3(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_3(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(3, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(3, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(3, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(3, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(3, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(3, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_3(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3) \ + sql_create_basic_c_order_3(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2) + +#define sql_create_3(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3) \ + sql_create_complete_3(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2) \ + +#define sql_create_c_order_3(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3) \ + sql_create_complete_3(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3) + +#define sql_create_c_names_3(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3) \ + sql_create_complete_3(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2) + +// --------------------------------------------------- +// End Create 3 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 4 +// --------------------------------------------------- +#define sql_create_basic_c_order_4(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_4(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(4, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(4, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(4, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(4, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(4, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(4, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_4(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4) \ + sql_create_basic_c_order_4(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3) + +#define sql_create_4(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4) \ + sql_create_complete_4(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3) \ + +#define sql_create_c_order_4(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4) \ + sql_create_complete_4(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4) + +#define sql_create_c_names_4(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4) \ + sql_create_complete_4(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3) + +// --------------------------------------------------- +// End Create 4 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 5 +// --------------------------------------------------- +#define sql_create_basic_c_order_5(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_5(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(5, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(5, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(5, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(5, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(5, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(5, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_5(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5) \ + sql_create_basic_c_order_5(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4) + +#define sql_create_5(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5) \ + sql_create_complete_5(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4) \ + +#define sql_create_c_order_5(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5) \ + sql_create_complete_5(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5) + +#define sql_create_c_names_5(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5) \ + sql_create_complete_5(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4) + +// --------------------------------------------------- +// End Create 5 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 6 +// --------------------------------------------------- +#define sql_create_basic_c_order_6(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_6(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(6, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(6, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(6, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(6, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(6, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(6, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_6(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6) \ + sql_create_basic_c_order_6(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5) + +#define sql_create_6(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6) \ + sql_create_complete_6(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5) \ + +#define sql_create_c_order_6(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6) \ + sql_create_complete_6(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6) + +#define sql_create_c_names_6(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6) \ + sql_create_complete_6(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5) + +// --------------------------------------------------- +// End Create 6 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 7 +// --------------------------------------------------- +#define sql_create_basic_c_order_7(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_7(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(7, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(7, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(7, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(7, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(7, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(7, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_7(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7) \ + sql_create_basic_c_order_7(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6) + +#define sql_create_7(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7) \ + sql_create_complete_7(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6) \ + +#define sql_create_c_order_7(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7) \ + sql_create_complete_7(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7) + +#define sql_create_c_names_7(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7) \ + sql_create_complete_7(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6) + +// --------------------------------------------------- +// End Create 7 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 8 +// --------------------------------------------------- +#define sql_create_basic_c_order_8(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_8(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(8, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(8, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(8, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(8, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(8, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(8, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_8(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8) \ + sql_create_basic_c_order_8(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7) + +#define sql_create_8(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8) \ + sql_create_complete_8(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7) \ + +#define sql_create_c_order_8(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8) \ + sql_create_complete_8(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8) + +#define sql_create_c_names_8(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8) \ + sql_create_complete_8(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7) + +// --------------------------------------------------- +// End Create 8 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 9 +// --------------------------------------------------- +#define sql_create_basic_c_order_9(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_9(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(9, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(9, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(9, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(9, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(9, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(9, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_9(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9) \ + sql_create_basic_c_order_9(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8) + +#define sql_create_9(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9) \ + sql_create_complete_9(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8) \ + +#define sql_create_c_order_9(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9) \ + sql_create_complete_9(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9) + +#define sql_create_c_names_9(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9) \ + sql_create_complete_9(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8) + +// --------------------------------------------------- +// End Create 9 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 10 +// --------------------------------------------------- +#define sql_create_basic_c_order_10(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_10(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(10, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(10, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(10, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(10, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(10, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(10, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_10(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10) \ + sql_create_basic_c_order_10(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9) + +#define sql_create_10(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10) \ + sql_create_complete_10(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9) \ + +#define sql_create_c_order_10(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10) \ + sql_create_complete_10(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10) + +#define sql_create_c_names_10(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10) \ + sql_create_complete_10(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9) + +// --------------------------------------------------- +// End Create 10 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 11 +// --------------------------------------------------- +#define sql_create_basic_c_order_11(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_11(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(11, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(11, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(11, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(11, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(11, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(11, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_11(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11) \ + sql_create_basic_c_order_11(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10) + +#define sql_create_11(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11) \ + sql_create_complete_11(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10) \ + +#define sql_create_c_order_11(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11) \ + sql_create_complete_11(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11) + +#define sql_create_c_names_11(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11) \ + sql_create_complete_11(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10) + +// --------------------------------------------------- +// End Create 11 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 12 +// --------------------------------------------------- +#define sql_create_basic_c_order_12(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_12(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(12, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(12, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(12, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(12, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(12, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(12, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_12(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12) \ + sql_create_basic_c_order_12(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11) + +#define sql_create_12(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12) \ + sql_create_complete_12(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11) \ + +#define sql_create_c_order_12(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12) \ + sql_create_complete_12(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12) + +#define sql_create_c_names_12(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12) \ + sql_create_complete_12(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11) + +// --------------------------------------------------- +// End Create 12 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 13 +// --------------------------------------------------- +#define sql_create_basic_c_order_13(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_13(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(13, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(13, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(13, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(13, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(13, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(13, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_13(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13) \ + sql_create_basic_c_order_13(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12) + +#define sql_create_13(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13) \ + sql_create_complete_13(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12) \ + +#define sql_create_c_order_13(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13) \ + sql_create_complete_13(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13) + +#define sql_create_c_names_13(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13) \ + sql_create_complete_13(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12) + +// --------------------------------------------------- +// End Create 13 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 14 +// --------------------------------------------------- +#define sql_create_basic_c_order_14(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_14(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(14, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(14, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(14, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(14, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(14, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(14, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_14(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14) \ + sql_create_basic_c_order_14(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13) + +#define sql_create_14(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14) \ + sql_create_complete_14(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13) \ + +#define sql_create_c_order_14(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14) \ + sql_create_complete_14(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14) + +#define sql_create_c_names_14(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14) \ + sql_create_complete_14(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13) + +// --------------------------------------------------- +// End Create 14 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 15 +// --------------------------------------------------- +#define sql_create_basic_c_order_15(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_15(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(15, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(15, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(15, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(15, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(15, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(15, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_15(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15) \ + sql_create_basic_c_order_15(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14) + +#define sql_create_15(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15) \ + sql_create_complete_15(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14) \ + +#define sql_create_c_order_15(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15) \ + sql_create_complete_15(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15) + +#define sql_create_c_names_15(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15) \ + sql_create_complete_15(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14) + +// --------------------------------------------------- +// End Create 15 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 16 +// --------------------------------------------------- +#define sql_create_basic_c_order_16(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_16(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(16, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(16, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(16, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(16, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(16, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(16, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_16(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16) \ + sql_create_basic_c_order_16(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15) + +#define sql_create_16(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16) \ + sql_create_complete_16(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15) \ + +#define sql_create_c_order_16(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16) \ + sql_create_complete_16(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16) + +#define sql_create_c_names_16(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16) \ + sql_create_complete_16(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15) + +// --------------------------------------------------- +// End Create 16 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 17 +// --------------------------------------------------- +#define sql_create_basic_c_order_17(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_17(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(17, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(17, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(17, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(17, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(17, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(17, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, 0, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_17(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17) \ + sql_create_basic_c_order_17(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16) + +#define sql_create_17(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17) \ + sql_create_complete_17(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16) \ + +#define sql_create_c_order_17(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17) \ + sql_create_complete_17(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17) + +#define sql_create_c_names_17(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17) \ + sql_create_complete_17(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16) + +// --------------------------------------------------- +// End Create 17 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 18 +// --------------------------------------------------- +#define sql_create_basic_c_order_18(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_18(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(18, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(18, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(18, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(18, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(18, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(18, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, 0, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_18(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18) \ + sql_create_basic_c_order_18(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17) + +#define sql_create_18(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18) \ + sql_create_complete_18(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17) \ + +#define sql_create_c_order_18(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18) \ + sql_create_complete_18(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18) + +#define sql_create_c_names_18(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18) \ + sql_create_complete_18(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17) + +// --------------------------------------------------- +// End Create 18 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 19 +// --------------------------------------------------- +#define sql_create_basic_c_order_19(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_19(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(19, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(19, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(19, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(19, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(19, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(19, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, 0, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_19(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19) \ + sql_create_basic_c_order_19(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18) + +#define sql_create_19(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19) \ + sql_create_complete_19(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18) \ + +#define sql_create_c_order_19(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19) \ + sql_create_complete_19(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19) + +#define sql_create_c_names_19(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19) \ + sql_create_complete_19(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18) + +// --------------------------------------------------- +// End Create 19 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 20 +// --------------------------------------------------- +#define sql_create_basic_c_order_20(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, 0, 0, 0, 0, 0 ) + +#define sql_create_complete_20(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19, T20, I20, N20, O20) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19,\ + NAME##_##I20 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 ,\ + N20 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(20, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(20, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(20, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(20, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(20, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(20, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.manip << obj.obj->I20; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18] << obj.delem;\ + s << obj.manip << obj.obj->names[19]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I20;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[19];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, 0, 0, 0, 0, 0 ) + +#define sql_create_basic_20(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20) \ + sql_create_basic_c_order_20(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18, T20, I20, 19) + +#define sql_create_20(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20) \ + sql_create_complete_20(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18, T20, I20, #I20, 19) \ + +#define sql_create_c_order_20(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20) \ + sql_create_complete_20(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19, T20, I20, #I20, O20) + +#define sql_create_c_names_20(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19, T20, I20, N20) \ + sql_create_complete_20(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18, T20, I20, N20, 19) + +// --------------------------------------------------- +// End Create 20 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 21 +// --------------------------------------------------- +#define sql_create_basic_c_order_21(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, 0, 0, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, 0, 0, 0, 0 ) + +#define sql_create_complete_21(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19, T20, I20, N20, O20, T21, I21, N21, O21) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19,\ + NAME##_##I20,\ + NAME##_##I21 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, 0, 0, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, 0, 0, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 ,\ + N20 ,\ + N21 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(21, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(21, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(21, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(21, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(21, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(21, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.manip << obj.obj->I21; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18] << obj.delem;\ + s << obj.manip << obj.obj->names[19] << obj.delem;\ + s << obj.manip << obj.obj->names[20]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I21;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[19];\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[20];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, 0, 0, 0, 0 ) + +#define sql_create_basic_21(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21) \ + sql_create_basic_c_order_21(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18, T20, I20, 19, T21, I21, 20) + +#define sql_create_21(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21) \ + sql_create_complete_21(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18, T20, I20, #I20, 19, T21, I21, #I21, 20) \ + +#define sql_create_c_order_21(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21) \ + sql_create_complete_21(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19, T20, I20, #I20, O20, T21, I21, #I21, O21) + +#define sql_create_c_names_21(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19, T20, I20, N20, T21, I21, N21) \ + sql_create_complete_21(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18, T20, I20, N20, 19, T21, I21, N21, 20) + +// --------------------------------------------------- +// End Create 21 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 22 +// --------------------------------------------------- +#define sql_create_basic_c_order_22(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, 0, 0, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, 0, 0, 0 ) + +#define sql_create_complete_22(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19, T20, I20, N20, O20, T21, I21, N21, O21, T22, I22, N22, O22) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19,\ + NAME##_##I20,\ + NAME##_##I21,\ + NAME##_##I22 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, 0, 0, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, 0, 0, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 ,\ + N20 ,\ + N21 ,\ + N22 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(22, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(22, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(22, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(22, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(22, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(22, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.manip << obj.obj->I22; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18] << obj.delem;\ + s << obj.manip << obj.obj->names[19] << obj.delem;\ + s << obj.manip << obj.obj->names[20] << obj.delem;\ + s << obj.manip << obj.obj->names[21]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I22;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[19];\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[20];\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[21];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, 0, 0, 0 ) + +#define sql_create_basic_22(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22) \ + sql_create_basic_c_order_22(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18, T20, I20, 19, T21, I21, 20, T22, I22, 21) + +#define sql_create_22(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22) \ + sql_create_complete_22(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18, T20, I20, #I20, 19, T21, I21, #I21, 20, T22, I22, #I22, 21) \ + +#define sql_create_c_order_22(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22) \ + sql_create_complete_22(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19, T20, I20, #I20, O20, T21, I21, #I21, O21, T22, I22, #I22, O22) + +#define sql_create_c_names_22(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19, T20, I20, N20, T21, I21, N21, T22, I22, N22) \ + sql_create_complete_22(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18, T20, I20, N20, 19, T21, I21, N21, 20, T22, I22, N22, 21) + +// --------------------------------------------------- +// End Create 22 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 23 +// --------------------------------------------------- +#define sql_create_basic_c_order_23(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22, T23, I23, O23)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22;\ + T23 I23; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, 0, 0, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + s->I23 = static_cast(row.at(O23)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, 0, 0 ) + +#define sql_create_complete_23(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19, T20, I20, N20, O20, T21, I21, N21, O21, T22, I22, N22, O22, T23, I23, N23, O23) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19,\ + NAME##_##I20,\ + NAME##_##I21,\ + NAME##_##I22,\ + NAME##_##I23 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22;\ + T23 I23; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, 0, 0, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, 0, 0, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 ,\ + N20 ,\ + N21 ,\ + N22 ,\ + N23 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(23, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(23, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(23, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(23, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(23, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(23, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.manip << obj.obj->I22 << obj.delem;\ + s << obj.manip << obj.obj->I23; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18] << obj.delem;\ + s << obj.manip << obj.obj->names[19] << obj.delem;\ + s << obj.manip << obj.obj->names[20] << obj.delem;\ + s << obj.manip << obj.obj->names[21] << obj.delem;\ + s << obj.manip << obj.obj->names[22]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22 << obj.delem;\ + s << obj.obj->names[22] << obj.comp << obj.manip << obj.obj->I23; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I22;\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I23;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[19];\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[20];\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[21];\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[22];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22;\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[22] << obj.comp << obj.manip << obj.obj->I23;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + s->I23 = static_cast(row.at(O23));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, 0, 0 ) + +#define sql_create_basic_23(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23) \ + sql_create_basic_c_order_23(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18, T20, I20, 19, T21, I21, 20, T22, I22, 21, T23, I23, 22) + +#define sql_create_23(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23) \ + sql_create_complete_23(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18, T20, I20, #I20, 19, T21, I21, #I21, 20, T22, I22, #I22, 21, T23, I23, #I23, 22) \ + +#define sql_create_c_order_23(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22, T23, I23, O23) \ + sql_create_complete_23(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19, T20, I20, #I20, O20, T21, I21, #I21, O21, T22, I22, #I22, O22, T23, I23, #I23, O23) + +#define sql_create_c_names_23(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19, T20, I20, N20, T21, I21, N21, T22, I22, N22, T23, I23, N23) \ + sql_create_complete_23(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18, T20, I20, N20, 19, T21, I21, N21, 20, T22, I22, N22, 21, T23, I23, N23, 22) + +// --------------------------------------------------- +// End Create 23 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 24 +// --------------------------------------------------- +#define sql_create_basic_c_order_24(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22, T23, I23, O23, T24, I24, O24)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22;\ + T23 I23;\ + T24 I24; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, 0, 0)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + s->I23 = static_cast(row.at(O23));\ + s->I24 = static_cast(row.at(O24)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, 0 ) + +#define sql_create_complete_24(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19, T20, I20, N20, O20, T21, I21, N21, O21, T22, I22, N22, O22, T23, I23, N23, O23, T24, I24, N24, O24) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19,\ + NAME##_##I20,\ + NAME##_##I21,\ + NAME##_##I22,\ + NAME##_##I23,\ + NAME##_##I24 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22;\ + T23 I23;\ + T24 I24; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, 0, 0)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, 0, 0)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 ,\ + N20 ,\ + N21 ,\ + N22 ,\ + N23 ,\ + N24 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(24, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + if (i24) (*include)[23]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(24, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + if (i24 == NAME##_NULL) return;\ + (*include)[i24]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(24, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + if (i24) (*include)[23]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(24, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + if (i24 == NAME##_NULL) return;\ + (*include)[i24]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(24, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + if (i24) (*include)[23]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(24, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + if (i24 == NAME##_NULL) return;\ + (*include)[i24]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.manip << obj.obj->I22 << obj.delem;\ + s << obj.manip << obj.obj->I23 << obj.delem;\ + s << obj.manip << obj.obj->I24; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18] << obj.delem;\ + s << obj.manip << obj.obj->names[19] << obj.delem;\ + s << obj.manip << obj.obj->names[20] << obj.delem;\ + s << obj.manip << obj.obj->names[21] << obj.delem;\ + s << obj.manip << obj.obj->names[22] << obj.delem;\ + s << obj.manip << obj.obj->names[23]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22 << obj.delem;\ + s << obj.obj->names[22] << obj.comp << obj.manip << obj.obj->I23 << obj.delem;\ + s << obj.obj->names[23] << obj.comp << obj.manip << obj.obj->I24; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I22;\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I23;\ + before = true; \ + } \ + if ((*obj.include)[23]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I24;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[19];\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[20];\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[21];\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[22];\ + before = true; \ + } \ + if ((*obj.include)[23]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[23];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22;\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[22] << obj.comp << obj.manip << obj.obj->I23;\ + before = true; \ + } \ + if ((*obj.include)[23]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[23] << obj.comp << obj.manip << obj.obj->I24;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + s->I23 = static_cast(row.at(O23));\ + s->I24 = static_cast(row.at(O24));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, 0 ) + +#define sql_create_basic_24(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24) \ + sql_create_basic_c_order_24(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18, T20, I20, 19, T21, I21, 20, T22, I22, 21, T23, I23, 22, T24, I24, 23) + +#define sql_create_24(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24) \ + sql_create_complete_24(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18, T20, I20, #I20, 19, T21, I21, #I21, 20, T22, I22, #I22, 21, T23, I23, #I23, 22, T24, I24, #I24, 23) \ + +#define sql_create_c_order_24(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22, T23, I23, O23, T24, I24, O24) \ + sql_create_complete_24(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19, T20, I20, #I20, O20, T21, I21, #I21, O21, T22, I22, #I22, O22, T23, I23, #I23, O23, T24, I24, #I24, O24) + +#define sql_create_c_names_24(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19, T20, I20, N20, T21, I21, N21, T22, I22, N22, T23, I23, N23, T24, I24, N24) \ + sql_create_complete_24(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18, T20, I20, N20, 19, T21, I21, N21, 20, T22, I22, N22, 21, T23, I23, N23, 22, T24, I24, N24, 23) + +// --------------------------------------------------- +// End Create 24 +// --------------------------------------------------- + +// --------------------------------------------------- +// Begin Create 25 +// --------------------------------------------------- +#define sql_create_basic_c_order_25(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22, T23, I23, O23, T24, I24, O24, T25, I25, O25)\ + struct NAME; \ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22;\ + T23 I23;\ + T24 I24;\ + T25 I25; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, T25, I25)\ + }; \ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + s->I23 = static_cast(row.at(O23));\ + s->I24 = static_cast(row.at(O24));\ + s->I25 = static_cast(row.at(O25)); \ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);} \ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25 ) + +#define sql_create_complete_25(NAME, CMP, CONTR, T1, I1, N1, O1, T2, I2, N2, O2, T3, I3, N3, O3, T4, I4, N4, O4, T5, I5, N5, O5, T6, I6, N6, O6, T7, I7, N7, O7, T8, I8, N8, O8, T9, I9, N9, O9, T10, I10, N10, O10, T11, I11, N11, O11, T12, I12, N12, O12, T13, I13, N13, O13, T14, I14, N14, O14, T15, I15, N15, O15, T16, I16, N16, O16, T17, I17, N17, O17, T18, I18, N18, O18, T19, I19, N19, O19, T20, I20, N20, O20, T21, I21, N21, O21, T22, I22, N22, O22, T23, I23, N23, O23, T24, I24, N24, O24, T25, I25, N25, O25) \ + struct NAME; \ + enum NAME##_enum { \ + NAME##_##I1,\ + NAME##_##I2,\ + NAME##_##I3,\ + NAME##_##I4,\ + NAME##_##I5,\ + NAME##_##I6,\ + NAME##_##I7,\ + NAME##_##I8,\ + NAME##_##I9,\ + NAME##_##I10,\ + NAME##_##I11,\ + NAME##_##I12,\ + NAME##_##I13,\ + NAME##_##I14,\ + NAME##_##I15,\ + NAME##_##I16,\ + NAME##_##I17,\ + NAME##_##I18,\ + NAME##_##I19,\ + NAME##_##I20,\ + NAME##_##I21,\ + NAME##_##I22,\ + NAME##_##I23,\ + NAME##_##I24,\ + NAME##_##I25 \ + ,NAME##_NULL \ + }; \ + template \ + class NAME##_value_list { \ + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_##field_list {\ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */\ + public: \ + const NAME *obj; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) \ + : obj(o), delem(d), manip(m) {} \ + };\ + template \ + class NAME##_equal_list { \ + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */\ + public: \ + const NAME *obj;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public: \ + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) \ + : obj(o), delem(d), comp(c), manip(m) {}\ + };\ + template \ + class NAME##_cus_value_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_value_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_value_list () {if (del_vector) delete include;} \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25);\ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25); \ + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i)\ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_field_list { \ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_field_list&); */\ + public:\ + const NAME *obj; \ + std::vector *include; \ + bool del_vector; \ + mysqlpp::cchar *delem;\ + Manip manip;\ + public: \ + ~NAME##_cus_field_list () {if (del_vector) delete include;} \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25); \ + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), manip(m) {}\ + };\ + template \ + class NAME##_cus_equal_list {\ + /* friend std::ostream& operator << <> (std::ostream&, \ + const NAME##_cus_equal_list&); */\ + public:\ + const NAME *obj;\ + std::vector *include;\ + bool del_vector;\ + mysqlpp::cchar *delem;\ + mysqlpp::cchar *comp;\ + Manip manip;\ + public:\ + ~NAME##_##cus_equal_list () {if (del_vector) delete include;}\ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25); \ + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) \ + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {}\ + };\ + template int sql_compare_##NAME (const NAME &, const NAME &);\ + struct NAME { \ + T1 I1;\ + T2 I2;\ + T3 I3;\ + T4 I4;\ + T5 I5;\ + T6 I6;\ + T7 I7;\ + T8 I8;\ + T9 I9;\ + T10 I10;\ + T11 I11;\ + T12 I12;\ + T13 I13;\ + T14 I14;\ + T15 I15;\ + T16 I16;\ + T17 I17;\ + T18 I18;\ + T19 I19;\ + T20 I20;\ + T21 I21;\ + T22 I22;\ + T23 I23;\ + T24 I24;\ + T25 I25; \ + NAME () {} \ + NAME (const mysqlpp::Row &row);\ + void set (const mysqlpp::Row &row);\ + sql_compare_define_##CMP(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, T25, I25)\ + sql_construct_define_##CONTR(NAME, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, T25, I25)\ + static const char *names[];\ + static const char *_table;\ + static const char *& table() {return _table;}\ + NAME##_value_list value_list() const {\ + return value_list(",", mysqlpp::quote);}\ + NAME##_value_list value_list(mysqlpp::cchar *d) const {\ + return value_list(d, mysqlpp::quote);}\ + template \ + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_field_list field_list() const {\ + return field_list(",", mysqlpp::do_nothing);}\ + NAME##_field_list field_list(mysqlpp::cchar *d) const {\ + return field_list(d, mysqlpp::do_nothing);}\ + template \ + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; \ + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", \ + mysqlpp::cchar *c = " = ") const{\ + return equal_list(d, c, mysqlpp::quote);}\ + template \ + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; \ + /* cus_data */\ + NAME##_cus_value_list value_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_value_list value_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return value_list(",", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_value_list value_list(std::vector *i) const {\ + return value_list(",", mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const {\ + return value_list(",", mysqlpp::quote, sc);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return value_list(d, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return value_list(d, mysqlpp::quote, i);\ + }\ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return value_list(d, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const; \ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus field */\ + NAME##_cus_field_list field_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_field_list field_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return field_list(",", mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_field_list field_list(std::vector *i) const {\ + return field_list(",", mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const\ + {\ + return field_list(",", mysqlpp::do_nothing, sc);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return field_list(d, mysqlpp::do_nothing, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return field_list(d, mysqlpp::do_nothing, i);\ + }\ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return field_list(d, mysqlpp::do_nothing, sc);\ + }\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const; \ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const;\ + template \ + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + /* cus equal */\ + NAME##_cus_equal_list equal_list(bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_equal_list equal_list(NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return equal_list(",", " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_equal_list equal_list(std::vector *i) const {\ + return equal_list(",", " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const {\ + return equal_list(",", " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return equal_list(d, " = ", mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + std::vector *i) const {\ + return equal_list(d, " = ", mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, \ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, " = ", mysqlpp::quote, sc);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const {\ + return equal_list(d, c, mysqlpp::quote, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + std::vector *i) const {\ + return equal_list(d, c, mysqlpp::quote, i);\ + }\ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c,\ + mysqlpp::sql_cmp_type sc) const {\ + return equal_list(d, c, mysqlpp::quote, sc);\ + }\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + bool i1, bool i2 = false, bool i3 = false, bool i4 = false, bool i5 = false, bool i6 = false, bool i7 = false, bool i8 = false, bool i9 = false, bool i10 = false, bool i11 = false, bool i12 = false, bool i13 = false, bool i14 = false, bool i15 = false, bool i16 = false, bool i17 = false, bool i18 = false, bool i19 = false, bool i20 = false, bool i21 = false, bool i22 = false, bool i23 = false, bool i24 = false, bool i25 = false) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2 = NAME##_NULL, NAME##_enum i3 = NAME##_NULL, NAME##_enum i4 = NAME##_NULL, NAME##_enum i5 = NAME##_NULL, NAME##_enum i6 = NAME##_NULL, NAME##_enum i7 = NAME##_NULL, NAME##_enum i8 = NAME##_NULL, NAME##_enum i9 = NAME##_NULL, NAME##_enum i10 = NAME##_NULL, NAME##_enum i11 = NAME##_NULL, NAME##_enum i12 = NAME##_NULL, NAME##_enum i13 = NAME##_NULL, NAME##_enum i14 = NAME##_NULL, NAME##_enum i15 = NAME##_NULL, NAME##_enum i16 = NAME##_NULL, NAME##_enum i17 = NAME##_NULL, NAME##_enum i18 = NAME##_NULL, NAME##_enum i19 = NAME##_NULL, NAME##_enum i20 = NAME##_NULL, NAME##_enum i21 = NAME##_NULL, NAME##_enum i22 = NAME##_NULL, NAME##_enum i23 = NAME##_NULL, NAME##_enum i24 = NAME##_NULL, NAME##_enum i25 = NAME##_NULL) const; \ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + std::vector *i) const;\ + template \ + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + mysqlpp::sql_cmp_type sc) const;\ + }; \ + MYSQLPP_SSQLS_EXPAND(\ + const char *NAME::names[] = { \ + N1 ,\ + N2 ,\ + N3 ,\ + N4 ,\ + N5 ,\ + N6 ,\ + N7 ,\ + N8 ,\ + N9 ,\ + N10 ,\ + N11 ,\ + N12 ,\ + N13 ,\ + N14 ,\ + N15 ,\ + N16 ,\ + N17 ,\ + N18 ,\ + N19 ,\ + N20 ,\ + N21 ,\ + N22 ,\ + N23 ,\ + N24 ,\ + N25 \ + }; \ + const char *NAME::_table = #NAME ;\ + )\ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25) \ + { \ + delem = d;\ + manip = m;\ + del_vector = true;\ + obj = o; \ + include = new std::vector(25, false);\ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + if (i24) (*include)[23]=true;\ + if (i25) (*include)[24]=true;\ + } \ + template \ + NAME##_cus_value_list::NAME##_cus_value_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(25, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + if (i24 == NAME##_NULL) return;\ + (*include)[i24]=true;\ + if (i25 == NAME##_NULL) return;\ + (*include)[i25]=true;\ + }\ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25) {\ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(25, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + if (i24) (*include)[23]=true;\ + if (i25) (*include)[24]=true;\ + } \ + template \ + NAME##_cus_field_list::NAME##_cus_field_list\ + (const NAME *o, mysqlpp::cchar *d, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25) { \ + delem = d;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(25, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + if (i24 == NAME##_NULL) return;\ + (*include)[i24]=true;\ + if (i25 == NAME##_NULL) return;\ + (*include)[i25]=true;\ + }\ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(25, false); \ + if (i1) (*include)[0]=true;\ + if (i2) (*include)[1]=true;\ + if (i3) (*include)[2]=true;\ + if (i4) (*include)[3]=true;\ + if (i5) (*include)[4]=true;\ + if (i6) (*include)[5]=true;\ + if (i7) (*include)[6]=true;\ + if (i8) (*include)[7]=true;\ + if (i9) (*include)[8]=true;\ + if (i10) (*include)[9]=true;\ + if (i11) (*include)[10]=true;\ + if (i12) (*include)[11]=true;\ + if (i13) (*include)[12]=true;\ + if (i14) (*include)[13]=true;\ + if (i15) (*include)[14]=true;\ + if (i16) (*include)[15]=true;\ + if (i17) (*include)[16]=true;\ + if (i18) (*include)[17]=true;\ + if (i19) (*include)[18]=true;\ + if (i20) (*include)[19]=true;\ + if (i21) (*include)[20]=true;\ + if (i22) (*include)[21]=true;\ + if (i23) (*include)[22]=true;\ + if (i24) (*include)[23]=true;\ + if (i25) (*include)[24]=true;\ + } \ + template \ + NAME##_cus_equal_list::NAME##_cus_equal_list\ + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25) { \ + delem = d;\ + comp = c;\ + manip = m;\ + del_vector = true; \ + obj = o; \ + include = new std::vector(25, false); \ + if (i1 == NAME##_NULL) return;\ + (*include)[i1]=true;\ + if (i2 == NAME##_NULL) return;\ + (*include)[i2]=true;\ + if (i3 == NAME##_NULL) return;\ + (*include)[i3]=true;\ + if (i4 == NAME##_NULL) return;\ + (*include)[i4]=true;\ + if (i5 == NAME##_NULL) return;\ + (*include)[i5]=true;\ + if (i6 == NAME##_NULL) return;\ + (*include)[i6]=true;\ + if (i7 == NAME##_NULL) return;\ + (*include)[i7]=true;\ + if (i8 == NAME##_NULL) return;\ + (*include)[i8]=true;\ + if (i9 == NAME##_NULL) return;\ + (*include)[i9]=true;\ + if (i10 == NAME##_NULL) return;\ + (*include)[i10]=true;\ + if (i11 == NAME##_NULL) return;\ + (*include)[i11]=true;\ + if (i12 == NAME##_NULL) return;\ + (*include)[i12]=true;\ + if (i13 == NAME##_NULL) return;\ + (*include)[i13]=true;\ + if (i14 == NAME##_NULL) return;\ + (*include)[i14]=true;\ + if (i15 == NAME##_NULL) return;\ + (*include)[i15]=true;\ + if (i16 == NAME##_NULL) return;\ + (*include)[i16]=true;\ + if (i17 == NAME##_NULL) return;\ + (*include)[i17]=true;\ + if (i18 == NAME##_NULL) return;\ + (*include)[i18]=true;\ + if (i19 == NAME##_NULL) return;\ + (*include)[i19]=true;\ + if (i20 == NAME##_NULL) return;\ + (*include)[i20]=true;\ + if (i21 == NAME##_NULL) return;\ + (*include)[i21]=true;\ + if (i22 == NAME##_NULL) return;\ + (*include)[i22]=true;\ + if (i23 == NAME##_NULL) return;\ + (*include)[i23]=true;\ + if (i24 == NAME##_NULL) return;\ + (*include)[i24]=true;\ + if (i25 == NAME##_NULL) return;\ + (*include)[i25]=true;\ + }\ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { \ + s << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.manip << obj.obj->I22 << obj.delem;\ + s << obj.manip << obj.obj->I23 << obj.delem;\ + s << obj.manip << obj.obj->I24 << obj.delem;\ + s << obj.manip << obj.obj->I25; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { \ + s << obj.manip << obj.obj->names[0] << obj.delem;\ + s << obj.manip << obj.obj->names[1] << obj.delem;\ + s << obj.manip << obj.obj->names[2] << obj.delem;\ + s << obj.manip << obj.obj->names[3] << obj.delem;\ + s << obj.manip << obj.obj->names[4] << obj.delem;\ + s << obj.manip << obj.obj->names[5] << obj.delem;\ + s << obj.manip << obj.obj->names[6] << obj.delem;\ + s << obj.manip << obj.obj->names[7] << obj.delem;\ + s << obj.manip << obj.obj->names[8] << obj.delem;\ + s << obj.manip << obj.obj->names[9] << obj.delem;\ + s << obj.manip << obj.obj->names[10] << obj.delem;\ + s << obj.manip << obj.obj->names[11] << obj.delem;\ + s << obj.manip << obj.obj->names[12] << obj.delem;\ + s << obj.manip << obj.obj->names[13] << obj.delem;\ + s << obj.manip << obj.obj->names[14] << obj.delem;\ + s << obj.manip << obj.obj->names[15] << obj.delem;\ + s << obj.manip << obj.obj->names[16] << obj.delem;\ + s << obj.manip << obj.obj->names[17] << obj.delem;\ + s << obj.manip << obj.obj->names[18] << obj.delem;\ + s << obj.manip << obj.obj->names[19] << obj.delem;\ + s << obj.manip << obj.obj->names[20] << obj.delem;\ + s << obj.manip << obj.obj->names[21] << obj.delem;\ + s << obj.manip << obj.obj->names[22] << obj.delem;\ + s << obj.manip << obj.obj->names[23] << obj.delem;\ + s << obj.manip << obj.obj->names[24]; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1 << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2 << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3 << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4 << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5 << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6 << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7 << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8 << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9 << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10 << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11 << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12 << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13 << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14 << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15 << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16 << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17 << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18 << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19 << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20 << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21 << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22 << obj.delem;\ + s << obj.obj->names[22] << obj.comp << obj.manip << obj.obj->I23 << obj.delem;\ + s << obj.obj->names[23] << obj.comp << obj.manip << obj.obj->I24 << obj.delem;\ + s << obj.obj->names[24] << obj.comp << obj.manip << obj.obj->I25; \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I22;\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I23;\ + before = true; \ + } \ + if ((*obj.include)[23]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I24;\ + before = true; \ + } \ + if ((*obj.include)[24]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->I25;\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.manip << obj.obj->names[0];\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[1];\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[2];\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[3];\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[4];\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[5];\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[6];\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[7];\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[8];\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[9];\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[10];\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[11];\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[12];\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[13];\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[14];\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[15];\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[16];\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[17];\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[18];\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[19];\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[20];\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[21];\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[22];\ + before = true; \ + } \ + if ((*obj.include)[23]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[23];\ + before = true; \ + } \ + if ((*obj.include)[24]) { \ + if (before) s << obj.delem;\ + s << obj.manip << obj.obj->names[24];\ + } \ + return s; \ + } \ + template \ + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { \ + bool before = false; \ + if ((*obj.include)[0]) { \ + s << obj.obj->names[0] << obj.comp << obj.manip << obj.obj->I1;\ + before = true; \ + } \ + if ((*obj.include)[1]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[1] << obj.comp << obj.manip << obj.obj->I2;\ + before = true; \ + } \ + if ((*obj.include)[2]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[2] << obj.comp << obj.manip << obj.obj->I3;\ + before = true; \ + } \ + if ((*obj.include)[3]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[3] << obj.comp << obj.manip << obj.obj->I4;\ + before = true; \ + } \ + if ((*obj.include)[4]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[4] << obj.comp << obj.manip << obj.obj->I5;\ + before = true; \ + } \ + if ((*obj.include)[5]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[5] << obj.comp << obj.manip << obj.obj->I6;\ + before = true; \ + } \ + if ((*obj.include)[6]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[6] << obj.comp << obj.manip << obj.obj->I7;\ + before = true; \ + } \ + if ((*obj.include)[7]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[7] << obj.comp << obj.manip << obj.obj->I8;\ + before = true; \ + } \ + if ((*obj.include)[8]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[8] << obj.comp << obj.manip << obj.obj->I9;\ + before = true; \ + } \ + if ((*obj.include)[9]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[9] << obj.comp << obj.manip << obj.obj->I10;\ + before = true; \ + } \ + if ((*obj.include)[10]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[10] << obj.comp << obj.manip << obj.obj->I11;\ + before = true; \ + } \ + if ((*obj.include)[11]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[11] << obj.comp << obj.manip << obj.obj->I12;\ + before = true; \ + } \ + if ((*obj.include)[12]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[12] << obj.comp << obj.manip << obj.obj->I13;\ + before = true; \ + } \ + if ((*obj.include)[13]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[13] << obj.comp << obj.manip << obj.obj->I14;\ + before = true; \ + } \ + if ((*obj.include)[14]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[14] << obj.comp << obj.manip << obj.obj->I15;\ + before = true; \ + } \ + if ((*obj.include)[15]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[15] << obj.comp << obj.manip << obj.obj->I16;\ + before = true; \ + } \ + if ((*obj.include)[16]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[16] << obj.comp << obj.manip << obj.obj->I17;\ + before = true; \ + } \ + if ((*obj.include)[17]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[17] << obj.comp << obj.manip << obj.obj->I18;\ + before = true; \ + } \ + if ((*obj.include)[18]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[18] << obj.comp << obj.manip << obj.obj->I19;\ + before = true; \ + } \ + if ((*obj.include)[19]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[19] << obj.comp << obj.manip << obj.obj->I20;\ + before = true; \ + } \ + if ((*obj.include)[20]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[20] << obj.comp << obj.manip << obj.obj->I21;\ + before = true; \ + } \ + if ((*obj.include)[21]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[21] << obj.comp << obj.manip << obj.obj->I22;\ + before = true; \ + } \ + if ((*obj.include)[22]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[22] << obj.comp << obj.manip << obj.obj->I23;\ + before = true; \ + } \ + if ((*obj.include)[23]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[23] << obj.comp << obj.manip << obj.obj->I24;\ + before = true; \ + } \ + if ((*obj.include)[24]) { \ + if (before) s << obj.delem;\ + s << obj.obj->names[24] << obj.comp << obj.manip << obj.obj->I25;\ + } \ + return s; \ + } \ + template \ + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_value_list (this, d, m); \ + } \ + template \ + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { \ + return NAME##_field_list (this, d, m); \ + } \ + template \ + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { \ + return NAME##_equal_list (this, d, c, m); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25) const {\ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25) const { \ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + bool i1, bool i2, bool i3, bool i4, bool i5, bool i6, bool i7, bool i8, bool i9, bool i10, bool i11, bool i12, bool i13, bool i14, bool i15, bool i16, bool i17, bool i18, bool i19, bool i20, bool i21, bool i22, bool i23, bool i24, bool i25) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25) const { \ + return NAME##_cus_value_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25); \ + } \ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25) const {\ + return NAME##_cus_field_list (this, d, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25); \ + } \ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, \ + NAME##_enum i1, NAME##_enum i2, NAME##_enum i3, NAME##_enum i4, NAME##_enum i5, NAME##_enum i6, NAME##_enum i7, NAME##_enum i8, NAME##_enum i9, NAME##_enum i10, NAME##_enum i11, NAME##_enum i12, NAME##_enum i13, NAME##_enum i14, NAME##_enum i15, NAME##_enum i16, NAME##_enum i17, NAME##_enum i18, NAME##_enum i19, NAME##_enum i20, NAME##_enum i21, NAME##_enum i22, NAME##_enum i23, NAME##_enum i24, NAME##_enum i25) const { \ + return NAME##_cus_equal_list (this, d, c, m, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23, i24, i25); \ + } \ + template \ + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_value_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_field_list (this, d, m, i);\ + }\ + template \ + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m,\ + std::vector *i) const {\ + return NAME##_cus_equal_list (this, d, c, m, i);\ + }\ + template \ + inline NAME##_cus_value_list \ + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, value, NUM);\ + }\ + template \ + inline NAME##_cus_field_list \ + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_def_##CMP (NAME, field, NUM);\ + }\ + template \ + inline NAME##_cus_equal_list \ + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const {\ + sql_compare_type_defe_##CMP (NAME, equal, NUM);\ + }\ + template \ + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { \ + s->I1 = static_cast(row.at(O1));\ + s->I2 = static_cast(row.at(O2));\ + s->I3 = static_cast(row.at(O3));\ + s->I4 = static_cast(row.at(O4));\ + s->I5 = static_cast(row.at(O5));\ + s->I6 = static_cast(row.at(O6));\ + s->I7 = static_cast(row.at(O7));\ + s->I8 = static_cast(row.at(O8));\ + s->I9 = static_cast(row.at(O9));\ + s->I10 = static_cast(row.at(O10));\ + s->I11 = static_cast(row.at(O11));\ + s->I12 = static_cast(row.at(O12));\ + s->I13 = static_cast(row.at(O13));\ + s->I14 = static_cast(row.at(O14));\ + s->I15 = static_cast(row.at(O15));\ + s->I16 = static_cast(row.at(O16));\ + s->I17 = static_cast(row.at(O17));\ + s->I18 = static_cast(row.at(O18));\ + s->I19 = static_cast(row.at(O19));\ + s->I20 = static_cast(row.at(O20));\ + s->I21 = static_cast(row.at(O21));\ + s->I22 = static_cast(row.at(O22));\ + s->I23 = static_cast(row.at(O23));\ + s->I24 = static_cast(row.at(O24));\ + s->I25 = static_cast(row.at(O25));\ + } \ + inline NAME::NAME (const mysqlpp::Row &row) \ + {populate_##NAME(this, row);}\ + inline void NAME::set (const mysqlpp::Row &row)\ + {populate_##NAME(this, row);}\ + sql_COMPARE__##CMP(NAME, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25 ) + +#define sql_create_basic_25(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, T25, I25) \ + sql_create_basic_c_order_25(NAME, CMP, CONTR, T1, I1, 0, T2, I2, 1, T3, I3, 2, T4, I4, 3, T5, I5, 4, T6, I6, 5, T7, I7, 6, T8, I8, 7, T9, I9, 8, T10, I10, 9, T11, I11, 10, T12, I12, 11, T13, I13, 12, T14, I14, 13, T15, I15, 14, T16, I16, 15, T17, I17, 16, T18, I18, 17, T19, I19, 18, T20, I20, 19, T21, I21, 20, T22, I22, 21, T23, I23, 22, T24, I24, 23, T25, I25, 24) + +#define sql_create_25(NAME, CMP, CONTR, T1, I1, T2, I2, T3, I3, T4, I4, T5, I5, T6, I6, T7, I7, T8, I8, T9, I9, T10, I10, T11, I11, T12, I12, T13, I13, T14, I14, T15, I15, T16, I16, T17, I17, T18, I18, T19, I19, T20, I20, T21, I21, T22, I22, T23, I23, T24, I24, T25, I25) \ + sql_create_complete_25(NAME, CMP, CONTR, T1, I1, #I1, 0, T2, I2, #I2, 1, T3, I3, #I3, 2, T4, I4, #I4, 3, T5, I5, #I5, 4, T6, I6, #I6, 5, T7, I7, #I7, 6, T8, I8, #I8, 7, T9, I9, #I9, 8, T10, I10, #I10, 9, T11, I11, #I11, 10, T12, I12, #I12, 11, T13, I13, #I13, 12, T14, I14, #I14, 13, T15, I15, #I15, 14, T16, I16, #I16, 15, T17, I17, #I17, 16, T18, I18, #I18, 17, T19, I19, #I19, 18, T20, I20, #I20, 19, T21, I21, #I21, 20, T22, I22, #I22, 21, T23, I23, #I23, 22, T24, I24, #I24, 23, T25, I25, #I25, 24) \ + +#define sql_create_c_order_25(NAME, CMP, CONTR, T1, I1, O1, T2, I2, O2, T3, I3, O3, T4, I4, O4, T5, I5, O5, T6, I6, O6, T7, I7, O7, T8, I8, O8, T9, I9, O9, T10, I10, O10, T11, I11, O11, T12, I12, O12, T13, I13, O13, T14, I14, O14, T15, I15, O15, T16, I16, O16, T17, I17, O17, T18, I18, O18, T19, I19, O19, T20, I20, O20, T21, I21, O21, T22, I22, O22, T23, I23, O23, T24, I24, O24, T25, I25, O25) \ + sql_create_complete_25(NAME, CMP, CONTR, T1, I1, #I1, O1, T2, I2, #I2, O2, T3, I3, #I3, O3, T4, I4, #I4, O4, T5, I5, #I5, O5, T6, I6, #I6, O6, T7, I7, #I7, O7, T8, I8, #I8, O8, T9, I9, #I9, O9, T10, I10, #I10, O10, T11, I11, #I11, O11, T12, I12, #I12, O12, T13, I13, #I13, O13, T14, I14, #I14, O14, T15, I15, #I15, O15, T16, I16, #I16, O16, T17, I17, #I17, O17, T18, I18, #I18, O18, T19, I19, #I19, O19, T20, I20, #I20, O20, T21, I21, #I21, O21, T22, I22, #I22, O22, T23, I23, #I23, O23, T24, I24, #I24, O24, T25, I25, #I25, O25) + +#define sql_create_c_names_25(NAME, CMP, CONTR, T1, I1, N1, T2, I2, N2, T3, I3, N3, T4, I4, N4, T5, I5, N5, T6, I6, N6, T7, I7, N7, T8, I8, N8, T9, I9, N9, T10, I10, N10, T11, I11, N11, T12, I12, N12, T13, I13, N13, T14, I14, N14, T15, I15, N15, T16, I16, N16, T17, I17, N17, T18, I18, N18, T19, I19, N19, T20, I20, N20, T21, I21, N21, T22, I22, N22, T23, I23, N23, T24, I24, N24, T25, I25, N25) \ + sql_create_complete_25(NAME, CMP, CONTR, T1, I1, N1, 0, T2, I2, N2, 1, T3, I3, N3, 2, T4, I4, N4, 3, T5, I5, N5, 4, T6, I6, N6, 5, T7, I7, N7, 6, T8, I8, N8, 7, T9, I9, N9, 8, T10, I10, N10, 9, T11, I11, N11, 10, T12, I12, N12, 11, T13, I13, N13, 12, T14, I14, N14, 13, T15, I15, N15, 14, T16, I16, N16, 15, T17, I17, N17, 16, T18, I18, N18, 17, T19, I19, N19, 18, T20, I20, N20, 19, T21, I21, N21, 20, T22, I22, N22, 21, T23, I23, N23, 22, T24, I24, N24, 23, T25, I25, N25, 24) + +// --------------------------------------------------- +// End Create 25 +// --------------------------------------------------- + diff --git a/code/meosdb/mysql++/custom.h b/code/meosdb/mysql++/custom.h new file mode 100644 index 0000000..8adc461 --- /dev/null +++ b/code/meosdb/mysql++/custom.h @@ -0,0 +1,98 @@ + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// This file is generated by the Perl script custom.pl. Please do +// not modify this file directly. Change the script instead. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef MYSQLPP_CUSTOM_H +#define MYSQLPP_CUSTOM_H + +#include "common.h" +#include "tiny_int.h" + +#include + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +# error Please run the MySQL++ script lib/custom.pl with the -v compatibility flag. +#endif + +#ifdef MYSQLPP_SSQLS_NO_STATICS +# define MYSQLPP_SSQLS_EXPAND(...) +#else +# define MYSQLPP_SSQLS_EXPAND(...) __VA_ARGS__ +#endif + +namespace mysqlpp { + +enum sql_dummy_type {sql_dummy}; + +inline int sql_cmp(const std::string &a, const std::string &b) { + return a.compare(b); +} + +inline int sql_cmp(char a,char b) { + return a-b; +} + +inline int sql_cmp(unsigned char a,unsigned char b) { + return a-b; +} + +inline int sql_cmp(tiny_int a,tiny_int b) { + return a-b; +} + +inline int sql_cmp(int a,int b) { + return a-b; +} + +inline int sql_cmp(unsigned int a,unsigned int b) { + return a-b; +} + +inline int sql_cmp(short int a,short int b) { + return a-b; +} + +inline int sql_cmp(unsigned short int a,unsigned short int b) { + return a-b; +} + +inline int sql_cmp(unsigned long a,unsigned long b) { + return a-b; +} + +inline int sql_cmp(long a,long b) { + return a-b; +} + +inline int sql_cmp(double a,double b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; +} + +inline int sql_cmp(float a,float b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; +} + +inline int sql_cmp(longlong a,longlong b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; +} + +inline int sql_cmp(ulonglong a,ulonglong b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; +} + +#include "custom-macros.h" + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/custom.pl b/code/meosdb/mysql++/custom.pl new file mode 100644 index 0000000..1136721 --- /dev/null +++ b/code/meosdb/mysql++/custom.pl @@ -0,0 +1,924 @@ +#!/usr/bin/perl -w + +######################################################################## +# custom.pl - Generates custom.h and custom-macros.h, as these files +# contain many near-duplicate classes, varying only in the number of +# SQL table columns they support. +# +# Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by +# MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. +# Others may also hold copyrights on code in this file. See the CREDITS +# file in the top directory of the distribution for details. +# +# This file is part of MySQL++. +# +# MySQL++ 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 of the License, or +# (at your option) any later version. +# +# MySQL++ 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 MySQL++; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA +######################################################################## + + +# This is the limit on the number of SSQLS data members. Higher values +# will make custom-macros.h exponentially larger, increase compile +# times, and possibly even expose limits in your compiler. Increase it +# only if you must. +my $max_data_members = 25; + + +# No user-serviceable parts below. + +use strict; +use Getopt::Std; + +our ($opt_v); +getopts('v') or die "usage: custom.pl [-v]\n"; + +open (OUT0, ">custom.h"); +open (OUT, ">custom-macros.h"); + +print OUT0 << "---"; + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// This file is generated by the Perl script custom.pl. Please do +// not modify this file directly. Change the script instead. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef MYSQLPP_CUSTOM_H +#define MYSQLPP_CUSTOM_H + +#include "common.h" +#include "tiny_int.h" + +#include +--- + +my ($suppress_statics_start, $suppress_statics_end) = ('', ''); +unless ($opt_v) { + print OUT0 << "---"; + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +# error Please run the MySQL++ script lib/custom.pl with the -v compatibility flag. +#endif + +#ifdef MYSQLPP_SSQLS_NO_STATICS +# define MYSQLPP_SSQLS_EXPAND(...) +#else +# define MYSQLPP_SSQLS_EXPAND(...) __VA_ARGS__ +#endif + +--- + $suppress_statics_start = 'MYSQLPP_SSQLS_EXPAND('; + $suppress_statics_end = ')'; +} + +print OUT0 << "---"; +namespace mysqlpp { + +enum sql_dummy_type {sql_dummy}; + +inline int sql_cmp(const std::string &a, const std::string &b) { + return a.compare(b); +} +--- + +my @types = ("char", "unsigned char", "tiny_int", "int", "unsigned int", + "short int", "unsigned short int", "unsigned long", "long"); +foreach my $type (@types) { + print OUT0 << "---"; + +inline int sql_cmp($type a,$type b) { + return a-b; +} +--- +} + +@types = ("double", "float"); +foreach my $type (@types) { + print OUT0 << "---"; + +inline int sql_cmp($type a,$type b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; +} +--- +} + +@types = ("longlong", "ulonglong"); +foreach my $type (@types) { + print OUT0 << "---"; + +inline int sql_cmp($type a,$type b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; +} +--- +} + +print OUT0 << "---"; + +#include "custom-macros.h" + +} // end namespace mysqlpp + +#endif + +--- + +print OUT << "---"; + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// This file is generated by the Perl script custom.pl. Please do +// not modify this file directly. Change the script instead. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// --------------------------------------------------- +// Begin Mandatory Compare +// --------------------------------------------------- + +#define sql_compare_define(NAME) \\ + bool operator == (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other) == 0;} \\ + bool operator != (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other) != 0;} \\ + bool operator > (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other) > 0;} \\ + bool operator < (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other) < 0;} \\ + bool operator >= (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other) >= 0;} \\ + bool operator <= (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other) <= 0;} \\ + int cmp (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other);} \\ + int compare (const NAME &other) const \\ + {return sql_compare_##NAME(*this,other);} +--- + +my ($parm0, $parm1); + +foreach my $j (1..$max_data_members) { + $parm0 .= "T$j, C$j"; + $parm0 .= ", " unless $j == $max_data_members; + $parm1 .= "C$j"; + $parm1 .= ", " unless $j == $max_data_members; +} + +print OUT << "---"; + +#define sql_compare_define_0(NAME, $parm0) + +#define sql_construct_define_0(NAME, $parm0) + +#define sql_COMPARE__0(NAME, $parm1) + +#define sql_compare_type_def_0(NAME, WHAT, NUM) \\ + sql_compare_type_def_##NUM (NAME, WHAT, NUM) + +#define sql_compare_type_defe_0(NAME, WHAT, NUM) \\ + sql_compare_type_defe_##NUM (NAME, WHAT, NUM) + +// --------------------------------------------------- +// End Mandatory Compare +// --------------------------------------------------- +--- + + +foreach my $i (1..$max_data_members) { + my ($compr, $define, $compp, $set, $parm2); + $compr = ""; $parm2 = ""; $define = ""; + $compr = " int cmp; \\\n" unless $i == 1; + $compp = ""; + $set = ""; + foreach my $j (1..$i) { + if ($j != $i) { + $compr .= " cmp = mysqlpp::sql_cmp(x.C$j , y.C$j ); \\\n"; + $compr .= " if (cmp) return cmp; \\\n"; + } + + $compr .= " return mysqlpp::sql_cmp(x.C$j , y.C$j );" if $j == $i; + $parm2 .= "const T$j &p$j"; + $parm2 .= ", " unless $j == $i; + $define.= "C$j (p$j)"; + $define.= ", " unless $j == $i; + $set .= " C$j = p$j;\\\n"; + $compp .= "true"; + $compp .= ", " unless $j == $i; + } + print OUT << "---"; + +// --------------------------------------------------- +// Begin Compare $i +// --------------------------------------------------- + +#define sql_compare_define_$i(NAME, $parm0) \\ + NAME ($parm2) : $define {} \\ + void set ($parm2) { \\ +$set \\ + } \\ + sql_compare_define(NAME) + +#define sql_construct_define_$i(NAME, $parm0) \\ + void set ($parm2) { \\ +$set \\ + } \\ + NAME ($parm2) : $define {} + +#define sql_compare_type_def_$i(NAME, WHAT, NUM) \\ + return WHAT##_list(d, m, $compp) + +#define sql_compare_type_defe_$i(NAME, WHAT, NUM) \\ + return WHAT##_list(d, c, m, $compp) + +#define sql_COMPARE__$i(NAME, $parm1) \\ + template \\ + int sql_compare_##NAME (const NAME &x, const NAME &y) { \\ +$compr \\ + } \\ + template \\ + int compare (const NAME &x, const NAME &y) { \\ +$compr \\ + } + +// --------------------------------------------------- +// End Compare $i +// --------------------------------------------------- + +--- +} + +print OUT << "---"; +--- + + +foreach my $i (1..$max_data_members) { + my $parm_complete = ""; + my $parm_order = ""; my $parm_order2c = ""; + my $parm_simple = ""; my $parm_simple2c = ""; + my $parm_simple_b = ""; my $parm_simple2c_b = ""; + my $parm_names = ""; my $parm_names2c = ""; + my $defs = ""; my $popul = ""; my $parmc = ""; my $parmC = ""; + my $value_list = ""; my $field_list = ""; my $equal_list = ""; + my $value_list_cus = ""; my $cus_field_list = ""; my $cus_equal_list = ""; + my $create_bool = ""; my $create_list = ""; + my $cusparms1 = ""; my $cusparms2 = ""; my $cusparmsv = ""; + my $cusparms11 = ""; my $cusparms22 = ""; + my $names = "";my $enums = ""; + foreach my $j (1 .. $i) { + $parm_complete .= "T$j, I$j, N$j, O$j"; + $parm_complete .= ", " unless $j == $i; + $parm_order .= "T$j, I$j, O$j"; + $parm_order .= ", " unless $j == $i; + $parm_order2c .= "T$j, I$j, #I$j, O$j"; + $parm_order2c .= ", " unless $j == $i; + $parm_names .= "T$j, I$j, N$j"; + $parm_names .= ", " unless $j == $i; + $parm_names2c .= "T$j, I$j, N$j, ". ($j-1); + $parm_names2c .= ", " unless $j == $i; + $parm_simple .= "T$j, I$j"; + $parm_simple .= ", " unless $j == $i; + $parm_simple2c .= "T$j, I$j, #I$j, ". ($j-1); + $parm_simple2c .= ", " unless $j == $i; + $parm_simple_b .= "T$j, I$j"; + $parm_simple_b .= ", " unless $j == $i; + $parm_simple2c_b .= "T$j, I$j, ". ($j-1); + $parm_simple2c_b .= ", " unless $j == $i; + $defs .= " T$j I$j;"; + $defs .= "\n" unless $j == $i; + $popul .= " s->I$j = static_cast(row.at(O$j));"; + $popul .= "\n" unless $j == $i; + $names .= " N$j "; + $names .= ",\n" unless $j == $i; + $enums .= " NAME##_##I$j"; + $enums .= ",\n" unless $j == $i; + $field_list .= " s << obj.manip << obj.obj->names[".($j-1)."]"; + $field_list .= " << obj.delem;\n" unless $j == $i; + $value_list .= " s << obj.manip << obj.obj->I$j"; + $value_list .= " << obj.delem;\n" unless $j == $i; + $create_bool .= " if (i$j) (*include)[".($j-1)."]=true;\n"; + $create_list .= " if (i$j == NAME##_NULL) return;\n" unless $i == 1; + $create_list .= " (*include)[i$j]=true;\n"; + + $value_list_cus .= " if ((*obj.include)[".($j-1)."]) { \n"; + $value_list_cus .= " if (before) s << obj.delem;\n" unless $j == 1; + $value_list_cus .= " s << obj.manip << obj.obj->I$j;\n"; + $value_list_cus .= " before = true; \n" unless $j == $i; + $value_list_cus .= " } \n"; + + $cus_field_list .= " if ((*obj.include)[".($j-1)."]) { \n"; + $cus_field_list .= " if (before) s << obj.delem;\n" unless $j == 1; + $cus_field_list .= " s << obj.manip << obj.obj->names[".($j-1)."];\n"; + $cus_field_list .= " before = true; \n" unless $j == $i; + $cus_field_list .= " } \n"; + + $cus_equal_list .= " if ((*obj.include)[".($j-1)."]) { \n"; + $cus_equal_list .= " if (before) s << obj.delem;\n" unless $j == 1; + $cus_equal_list .= " s << obj.obj->names[".($j-1)."] << obj.comp"; + $cus_equal_list .= " << obj.manip << obj.obj->I$j;\n"; + $cus_equal_list .= " before = true; \n" unless $j == $i; + $cus_equal_list .= " } \n"; + + $equal_list .= " s << obj.obj->names[".($j-1)."] << obj.comp"; + $equal_list .= " << obj.manip << obj.obj->I$j"; + $equal_list .= " << obj.delem;\n" unless $j == $i; + $cusparms1 .= "bool i$j" if $j == 1; + $cusparms1 .= "bool i$j = false" unless $j == 1; + $cusparms1 .= ", " unless $j == $i; + $cusparms11 .= "bool i$j" ; + $cusparms11 .= ", " unless $j == $i; + $cusparms2 .= "NAME##_enum i$j" if $j == 1; + $cusparms2 .= "NAME##_enum i$j = NAME##_NULL" unless $j == 1; + $cusparms2 .= ", " unless $j == $i; + $cusparms22 .= "NAME##_enum i$j"; + $cusparms22 .= ", " unless $j == $i; + $cusparmsv .= "i$j"; + $cusparmsv .= ", " unless $j == $i; + $parmC .= "T$j, I$j"; + $parmC .= ", " unless $j == $max_data_members; + $parmc .= "I$j"; + $parmc .= ", " unless $j == $max_data_members; + } + foreach my $j ($i+1 .. $max_data_members) { + $parmC .= "0, 0"; + $parmC .= ", " unless $j == $max_data_members; + $parmc .= "0"; + $parmc .= ", " unless $j == $max_data_members; + } + + print OUT << "---"; +// --------------------------------------------------- +// Begin Create $i +// --------------------------------------------------- +--- + my $out = <<"---"; +#define sql_create_basic_c_order_$i(NAME, CMP, CONTR, $parm_order) + + struct NAME; + + template int sql_compare_##NAME (const NAME &, const NAME &); + + struct NAME { +$defs + NAME () {} + NAME (const mysqlpp::Row &row); + sql_compare_define_##CMP(NAME, $parmC) + }; + + template + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { +$popul + } + + inline NAME::NAME (const mysqlpp::Row &row) + {populate_##NAME(this, row);} + + sql_COMPARE__##CMP(NAME, $parmc ) +--- + print OUT &prepare($out); + + $out = <<"---"; +#define sql_create_complete_$i(NAME, CMP, CONTR, $parm_complete) + struct NAME; + + enum NAME##_enum { +$enums + ,NAME##_NULL + }; + + template + class NAME##_value_list { + /*friend std::ostream& operator << <> (std::ostream&, const NAME##_value_list&); */ + public: + const NAME *obj; + mysqlpp::cchar *delem; + Manip manip; + public: + NAME##_value_list (const NAME *o, mysqlpp::cchar *d, Manip m) + : obj(o), delem(d), manip(m) {} + }; + + template + class NAME##_##field_list { + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_field_list&); */ + public: + const NAME *obj; + mysqlpp::cchar *delem; + Manip manip; + public: + NAME##_field_list (const NAME *o, mysqlpp::cchar *d, Manip m) + : obj(o), delem(d), manip(m) {} + }; + + template + class NAME##_equal_list { + /* friend std::ostream& operator << <> (std::ostream&, const NAME##_equal_list&); */ + public: + const NAME *obj; + mysqlpp::cchar *delem; + mysqlpp::cchar *comp; + Manip manip; + public: + NAME##_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) + : obj(o), delem(d), comp(c), manip(m) {} + }; + + template + class NAME##_cus_value_list { + /* friend std::ostream& operator << <> (std::ostream&, + const NAME##_cus_value_list&); */ + public: + const NAME *obj; + std::vector *include; + bool del_vector; + mysqlpp::cchar *delem; + Manip manip; + public: + ~NAME##_cus_value_list () {if (del_vector) delete include;} + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms11); + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms22); + NAME##_cus_value_list (const NAME *o, mysqlpp::cchar *d, Manip m ,std::vector* i) + : obj(o), include(i), del_vector(false), delem(d), manip(m) {} + }; + + template + class NAME##_cus_field_list { + /* friend std::ostream& operator << <> (std::ostream&, + const NAME##_cus_field_list&); */ + public: + const NAME *obj; + std::vector *include; + bool del_vector; + mysqlpp::cchar *delem; + Manip manip; + public: + ~NAME##_cus_field_list () {if (del_vector) delete include;} + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms11); + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms22); + NAME##_cus_field_list (const NAME *o, mysqlpp::cchar *d, Manip m, std::vector *i) + : obj(o), include(i), del_vector(false), delem(d), manip(m) {} + }; + + template + class NAME##_cus_equal_list { + /* friend std::ostream& operator << <> (std::ostream&, + const NAME##_cus_equal_list&); */ + public: + const NAME *obj; + std::vector *include; + bool del_vector; + mysqlpp::cchar *delem; + mysqlpp::cchar *comp; + Manip manip; + public: + ~NAME##_##cus_equal_list () {if (del_vector) delete include;} + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, $cusparms11); + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, $cusparms22); + NAME##_##cus_equal_list (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, std::vector *i) + : obj(o), include(i), del_vector(false), delem(d), comp(c), manip(m) {} + }; + + template int sql_compare_##NAME (const NAME &, const NAME &); + + struct NAME { +$defs + NAME () {} + NAME (const mysqlpp::Row &row); + void set (const mysqlpp::Row &row); + sql_compare_define_##CMP(NAME, $parmC) + sql_construct_define_##CONTR(NAME, $parmC) + static const char *names[]; + static const char *_table; + static const char *& table() {return _table;} + + NAME##_value_list value_list() const { + return value_list(",", mysqlpp::quote);} + NAME##_value_list value_list(mysqlpp::cchar *d) const { + return value_list(d, mysqlpp::quote);} + template + NAME##_value_list value_list(mysqlpp::cchar *d, Manip m) const; + + NAME##_field_list field_list() const { + return field_list(",", mysqlpp::do_nothing);} + NAME##_field_list field_list(mysqlpp::cchar *d) const { + return field_list(d, mysqlpp::do_nothing);} + template + NAME##_field_list field_list(mysqlpp::cchar *d, Manip m) const; + + NAME##_equal_list equal_list(mysqlpp::cchar *d = ",", + mysqlpp::cchar *c = " = ") const{ + return equal_list(d, c, mysqlpp::quote);} + template + NAME##_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const; + + /* cus_data */ + + NAME##_cus_value_list value_list($cusparms1) const { + return value_list(",", mysqlpp::quote, $cusparmsv); + } + NAME##_cus_value_list value_list($cusparms2) const { + return value_list(",", mysqlpp::quote, $cusparmsv); + } + NAME##_cus_value_list value_list(std::vector *i) const { + return value_list(",", mysqlpp::quote, i); + } + NAME##_cus_value_list value_list(mysqlpp::sql_cmp_type sc) const { + return value_list(",", mysqlpp::quote, sc); + } + + NAME##_cus_value_list value_list(mysqlpp::cchar *d, $cusparms1) const { + return value_list(d, mysqlpp::quote, $cusparmsv); + } + NAME##_cus_value_list value_list(mysqlpp::cchar *d, $cusparms2) const { + return value_list(d, mysqlpp::quote, $cusparmsv); + } + NAME##_cus_value_list value_list(mysqlpp::cchar *d, + std::vector *i) const { + return value_list(d, mysqlpp::quote, i); + } + NAME##_cus_value_list value_list(mysqlpp::cchar *d, + mysqlpp::sql_cmp_type sc) const { + return value_list(d, mysqlpp::quote, sc); + } + + template + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, + $cusparms1) const; + template + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, + $cusparms2) const; + template + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, + std::vector *i) const; + template + NAME##_cus_value_list value_list(mysqlpp::cchar *d, Manip m, + mysqlpp::sql_cmp_type sc) const; + /* cus field */ + + NAME##_cus_field_list field_list($cusparms1) const { + return field_list(",", mysqlpp::do_nothing, $cusparmsv); + } + NAME##_cus_field_list field_list($cusparms2) const { + return field_list(",", mysqlpp::do_nothing, $cusparmsv); + } + NAME##_cus_field_list field_list(std::vector *i) const { + return field_list(",", mysqlpp::do_nothing, i); + } + NAME##_cus_field_list field_list(mysqlpp::sql_cmp_type sc) const + { + return field_list(",", mysqlpp::do_nothing, sc); + } + + NAME##_cus_field_list field_list(mysqlpp::cchar *d, + $cusparms1) const { + return field_list(d, mysqlpp::do_nothing, $cusparmsv); + } + NAME##_cus_field_list field_list(mysqlpp::cchar *d, + $cusparms2) const { + return field_list(d, mysqlpp::do_nothing, $cusparmsv); + } + NAME##_cus_field_list field_list(mysqlpp::cchar *d, + std::vector *i) const { + return field_list(d, mysqlpp::do_nothing, i); + } + NAME##_cus_field_list field_list(mysqlpp::cchar *d, + mysqlpp::sql_cmp_type sc) const { + return field_list(d, mysqlpp::do_nothing, sc); + } + + template + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, + $cusparms1) const; + template + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, + $cusparms2) const; + template + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, + std::vector *i) const; + template + NAME##_cus_field_list field_list(mysqlpp::cchar *d, Manip m, + mysqlpp::sql_cmp_type sc) const; + + /* cus equal */ + + NAME##_cus_equal_list equal_list($cusparms1) const { + return equal_list(",", " = ", mysqlpp::quote, $cusparmsv); + } + NAME##_cus_equal_list equal_list($cusparms2) const { + return equal_list(",", " = ", mysqlpp::quote, $cusparmsv); + } + NAME##_cus_equal_list equal_list(std::vector *i) const { + return equal_list(",", " = ", mysqlpp::quote, i); + } + NAME##_cus_equal_list equal_list(mysqlpp::sql_cmp_type sc) const { + return equal_list(",", " = ", mysqlpp::quote, sc); + } + + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, $cusparms1) const { + return equal_list(d, " = ", mysqlpp::quote, $cusparmsv); + } + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, $cusparms2) const { + return equal_list(d, " = ", mysqlpp::quote, $cusparmsv); + } + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, + std::vector *i) const { + return equal_list(d, " = ", mysqlpp::quote, i); + } + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, + mysqlpp::sql_cmp_type sc) const { + return equal_list(d, " = ", mysqlpp::quote, sc); + } + + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, + $cusparms1) const { + return equal_list(d, c, mysqlpp::quote, $cusparmsv); + } + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, + $cusparms2) const { + return equal_list(d, c, mysqlpp::quote, $cusparmsv); + } + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, + std::vector *i) const { + return equal_list(d, c, mysqlpp::quote, i); + } + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, + mysqlpp::sql_cmp_type sc) const { + return equal_list(d, c, mysqlpp::quote, sc); + } + + template + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + $cusparms1) const; + template + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + $cusparms2) const; + template + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + std::vector *i) const; + template + NAME##_cus_equal_list equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + mysqlpp::sql_cmp_type sc) const; + }; + $suppress_statics_start + const char *NAME::names[] = { +$names + }; + const char *NAME::_table = #NAME ; + $suppress_statics_end + + template + NAME##_cus_value_list::NAME##_cus_value_list + (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms11) + { + delem = d; + manip = m; + del_vector = true; + obj = o; + include = new std::vector($i, false); +$create_bool + } + + template + NAME##_cus_value_list::NAME##_cus_value_list + (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms22) { + delem = d; + manip = m; + del_vector = true; + obj = o; + include = new std::vector($i, false); +$create_list + } + + template + NAME##_cus_field_list::NAME##_cus_field_list + (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms11) { + delem = d; + manip = m; + del_vector = true; + obj = o; + include = new std::vector($i, false); +$create_bool + } + + template + NAME##_cus_field_list::NAME##_cus_field_list + (const NAME *o, mysqlpp::cchar *d, Manip m, $cusparms22) { + delem = d; + manip = m; + del_vector = true; + obj = o; + include = new std::vector($i, false); +$create_list + } + + template + NAME##_cus_equal_list::NAME##_cus_equal_list + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, $cusparms11) { + delem = d; + comp = c; + manip = m; + del_vector = true; + obj = o; + include = new std::vector($i, false); +$create_bool + } + + template + NAME##_cus_equal_list::NAME##_cus_equal_list + (const NAME *o, mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, $cusparms22) { + delem = d; + comp = c; + manip = m; + del_vector = true; + obj = o; + include = new std::vector($i, false); +$create_list + } + + template + std::ostream& operator << (std::ostream& s, const NAME##_value_list& obj) { +$value_list; + return s; + } + + template + std::ostream& operator << (std::ostream& s, const NAME##_field_list& obj) { +$field_list; + return s; + } + + template + std::ostream& operator << (std::ostream& s, const NAME##_equal_list& obj) { +$equal_list; + return s; + } + + template + std::ostream& operator << (std::ostream& s, const NAME##_cus_value_list& obj) { + bool before = false; +$value_list_cus + return s; + } + + template + std::ostream& operator << (std::ostream& s, const NAME##_cus_field_list& obj) { + bool before = false; +$cus_field_list + return s; + } + + template + std::ostream& operator << (std::ostream& s, const NAME##_cus_equal_list& obj) { + bool before = false; +$cus_equal_list + return s; + } + + template + inline NAME##_value_list NAME::value_list(mysqlpp::cchar *d, Manip m) const { + return NAME##_value_list (this, d, m); + } + + template + inline NAME##_field_list NAME::field_list(mysqlpp::cchar *d, Manip m) const { + return NAME##_field_list (this, d, m); + } + + template + inline NAME##_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m) const { + return NAME##_equal_list (this, d, c, m); + } + + template + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m, + $cusparms11) const { + return NAME##_cus_value_list (this, d, m, $cusparmsv); + } + + template + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m, + $cusparms11) const { + return NAME##_cus_field_list (this, d, m, $cusparmsv); + } + + template + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + $cusparms11) const { + return NAME##_cus_equal_list (this, d, c, m, $cusparmsv); + } + + template + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m, + $cusparms22) const { + return NAME##_cus_value_list (this, d, m, $cusparmsv); + } + + template + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m, + $cusparms22) const { + return NAME##_cus_field_list (this, d, m, $cusparmsv); + } + + template + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + $cusparms22) const { + return NAME##_cus_equal_list (this, d, c, m, $cusparmsv); + } + + template + inline NAME##_cus_value_list NAME::value_list(mysqlpp::cchar *d, Manip m, + std::vector *i) const { + return NAME##_cus_value_list (this, d, m, i); + } + + template + inline NAME##_cus_field_list NAME::field_list(mysqlpp::cchar *d, Manip m, + std::vector *i) const { + return NAME##_cus_field_list (this, d, m, i); + } + + template + inline NAME##_cus_equal_list NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, + std::vector *i) const { + return NAME##_cus_equal_list (this, d, c, m, i); + } + + template + inline NAME##_cus_value_list + NAME::value_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const { + sql_compare_type_def_##CMP (NAME, value, NUM); + } + + template + inline NAME##_cus_field_list + NAME::field_list(mysqlpp::cchar *d, Manip m, mysqlpp::sql_cmp_type /*sc*/) const { + sql_compare_type_def_##CMP (NAME, field, NUM); + } + + template + inline NAME##_cus_equal_list + NAME::equal_list(mysqlpp::cchar *d, mysqlpp::cchar *c, Manip m, mysqlpp::sql_cmp_type /*sc*/) const { + sql_compare_type_defe_##CMP (NAME, equal, NUM); + } + + template + void populate_##NAME (NAME *s, const mysqlpp::Row &row) { +$popul + } + + inline NAME::NAME (const mysqlpp::Row &row) + {populate_##NAME(this, row);} + inline void NAME::set (const mysqlpp::Row &row) + {populate_##NAME(this, row);} + + sql_COMPARE__##CMP(NAME, $parmc ) + +--- +print OUT &prepare($out); + +# +# short cut defs +# + +print OUT << "---"; +#define sql_create_basic_$i(NAME, CMP, CONTR, $parm_simple_b) \\ + sql_create_basic_c_order_$i(NAME, CMP, CONTR, $parm_simple2c_b) + +#define sql_create_$i(NAME, CMP, CONTR, $parm_simple) \\ + sql_create_complete_$i(NAME, CMP, CONTR, $parm_simple2c) \\ + +#define sql_create_c_order_$i(NAME, CMP, CONTR, $parm_order) \\ + sql_create_complete_$i(NAME, CMP, CONTR, $parm_order2c) + +#define sql_create_c_names_$i(NAME, CMP, CONTR, $parm_names) \\ + sql_create_complete_$i(NAME, CMP, CONTR, $parm_names2c) + +// --------------------------------------------------- +// End Create $i +// --------------------------------------------------- + +--- + +} + + +sub prepare { + local $_ = $_[0]; + s/\n+$//; + s/\n[\n ]*\n/\n/g; + s/\n+/\\\n/g; + $_ .= "\n\n"; + return $_; +} + diff --git a/code/meosdb/mysql++/datetime.cpp b/code/meosdb/mysql++/datetime.cpp new file mode 100644 index 0000000..9e63b27 --- /dev/null +++ b/code/meosdb/mysql++/datetime.cpp @@ -0,0 +1,219 @@ +/*********************************************************************** + datetime.cpp - Implements date and time classes compatible with MySQL's + various date and time column types. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#define MYSQLPP_NOT_HEADER +#include "common.h" + +#include "datetime.h" + +#include + +#include + +using namespace std; + +namespace mysqlpp { + +std::ostream& operator <<(std::ostream& os, const Date& d) +{ + char fill = os.fill('0'); + ios::fmtflags flags = os.setf(ios::right); + os << setw(4) << d.year << '-' + << setw(2) << d.month << '-' + << setw(2) << d.day; + os.flags(flags); + os.fill(fill); + return os; +} + + +std::ostream& operator <<(std::ostream& os, const Time& t) +{ + char fill = os.fill('0'); + ios::fmtflags flags = os.setf(ios::right); + os << setw(2) << t.hour << ':' + << setw(2) << t.minute << ':' + << setw(2) << t.second; + os.flags(flags); + os.fill(fill); + return os; +} + + +std::ostream& operator <<(std::ostream& os, const DateTime& dt) +{ + operator <<(os, Date(dt)); + os << ' '; + return operator <<(os, Time(dt)); +} + + +cchar* Date::convert(cchar* str) +{ + char num[5]; + + num[0] = *str++; + num[1] = *str++; + num[2] = *str++; + num[3] = *str++; + num[4] = 0; + year = short(strtol(num, 0, 10)); + if (*str == '-') str++; + + num[0] = *str++; + num[1] = *str++; + num[2] = 0; + month = short(strtol(num, 0, 10)); + if (*str == '-') str++; + + num[0] = *str++; + num[1] = *str++; + num[2] = 0; + day = short(strtol(num, 0, 10)); + + return str; +} + + +cchar* Time::convert(cchar* str) +{ + char num[5]; + + num[0] = *str++; + num[1] = *str++; + num[2] = 0; + hour = short(strtol(num,0,10)); + if (*str == ':') str++; + + num[0] = *str++; + num[1] = *str++; + num[2] = 0; + minute = short(strtol(num,0,10)); + if (*str == ':') str++; + + num[0] = *str++; + num[1] = *str++; + num[2] = 0; + second = short(strtol(num,0,10)); + + return str; +} + + +cchar* DateTime::convert(cchar* str) +{ + Date d; + str = d.convert(str); + year = d.year; + month = d.month; + day = d.day; + + if (*str == ' ') ++str; + + Time t; + str = t.convert(str); + hour = t.hour; + minute = t.minute; + second = t.second; + + return str; +} + + +short int Date::compare(const Date& other) const +{ + if (year != other.year) return year - other.year; + if (month != other.month) return month - other.month; + return day - other.day; +} + + +short int Time::compare(const Time& other) const +{ + if (hour != other.hour) return hour - other.hour; + if (minute != other.minute) return minute - other.minute; + return second - other.second; +} + + +short int DateTime::compare(const DateTime& other) const +{ + Date d(*this), od(other); + Time t(*this), ot(other); + + if (int x = d.compare(od)) { + return x; + } + else { + return t.compare(ot); + } +} + +DateTime::operator time_t() const +{ + struct tm tm; + tm.tm_sec = second; + tm.tm_min = minute; + tm.tm_hour = hour; + tm.tm_mday = day; + tm.tm_mon = month - (tiny_int)1; + tm.tm_year = year - 1900; + tm.tm_isdst = -1; + + return mktime(&tm); +}; + +DateTime::DateTime(time_t t) +{ + struct tm tm; +#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(_STLP_VERSION) && \ + !defined(_STLP_VERSION_STR) + // Use thread-safe localtime() replacement included with VS2005 and + // up, but only when using native RTL, not STLport. + localtime_s(&tm, &t); +#elif defined(HAVE_LOCALTIME_R) + // Detected POSIX thread-safe localtime() replacement. + localtime_r(&t, &tm); +#else + // No explicitly thread-safe localtime() replacement found. This + // may still be thread-safe, as some C libraries take special steps + // within localtime() to get thread safety. For example, thread- + // local storage (TLS) in some Windows compilers. + memcpy(&tm, localtime(&t), sizeof(tm)); +#endif + + year = tm.tm_year + 1900; + month = tm.tm_mon + 1; + day = tm.tm_mday; + hour = tm.tm_hour; + minute = tm.tm_min; + second = tm.tm_sec; +} + +} // end namespace mysqlpp + + diff --git a/code/meosdb/mysql++/datetime.h b/code/meosdb/mysql++/datetime.h new file mode 100644 index 0000000..0d10efd --- /dev/null +++ b/code/meosdb/mysql++/datetime.h @@ -0,0 +1,384 @@ +/// \file datetime.h +/// \brief Declares classes to add MySQL-compatible date and time +/// types to C++'s type system. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_DATETIME_H +#define MYSQLPP_DATETIME_H + +#include "common.h" + +#include "coldata.h" +#include "stream2string.h" +#include "tiny_int.h" + +#include +#include +#include + +namespace mysqlpp { + +/// \brief Base class template for MySQL++ date and time classes. +/// +/// This template primarily defines the comparison operators, which are +/// all implemented in terms of compare(). Each subclass implements that +/// as a protected method, because these operators are the only +/// supported comparison method. +/// +/// This template also defines interfaces for converting the object to +/// a string form, which a subclass must define. +template struct DTbase +{ + /// \brief Destroy object + virtual ~DTbase() { } + + /// \brief Return a copy of the item in C++ string form + operator std::string() const + { + return stream2string(*this); + } + + /// \brief Compare this object to another of the same type + /// + /// Returns < 0 if this object is "before" the other, 0 of they are + /// equal, and > 0 if this object is "after" the other. + MYSQLPP_EXPORT virtual short compare(const T& other) const = 0; + + /// \brief Returns true if "other" is equal to this object + bool operator ==(const T& other) const + { + return !compare(other); + } + + /// \brief Returns true if "other" is not equal to this object + bool operator !=(const T& other) const + { + return compare(other); + } + + /// \brief Returns true if "other" is less than this object + bool operator <(const T& other) const + { + return compare(other) < 0; + } + + /// \brief Returns true if "other" is less than or equal to this object + bool operator <=(const T& other) const + { + return compare(other) <= 0; + } + + /// \brief Returns true if "other" is greater than this object + bool operator >(const T& other) const + { + return compare(other) > 0; + } + + /// \brief Returns true if "other" is greater than or equal to this object + bool operator >=(const T& other) const + { + return compare(other) >= 0; + } +}; + + +/// \brief C++ form of MySQL's DATETIME type. +/// +/// Objects of this class can be inserted into streams, and +/// initialized from MySQL DATETIME strings. +struct DateTime : public DTbase +{ + /// \brief the year + /// + /// No surprises; the year 2005 is stored as the integer 2005. + short int year; + + /// \brief the month, 1-12 + tiny_int month; + + /// \brief the day, 1-31 + tiny_int day; + + /// \brief hour, 0-23 + tiny_int hour; + + /// \brief minute, 0-59 + tiny_int minute; + + /// \brief second, 0-59 + tiny_int second; + + /// \brief Default constructor + DateTime() : + DTbase(), + year(0), + month(0), + day(0), + hour(0), + minute(0), + second(0) + { + } + + /// \brief Initialize object as a copy of another Date + DateTime(const DateTime& other) : + DTbase(), + year(other.year), + month(other.month), + day(other.day), + hour(other.hour), + minute(other.minute), + second(other.second) + { + } + + /// \brief Initialize object from a MySQL date-and-time string + /// + /// String must be in the HH:MM:SS format. It doesn't have to be + /// zero-padded. + DateTime(cchar* str) { convert(str); } + + /// \brief Initialize object from a MySQL date-and-time string + /// + /// \sa DateTime(cchar*) + DateTime(const ColData& str) + { + convert(str.c_str()); + } + + /// \brief Initialize object from a MySQL date-and-time string + /// + /// \sa DateTime(cchar*) + DateTime(const std::string& str) + { + convert(str.c_str()); + } + + /// \brief Initialize object from a time_t + DateTime(time_t t); + + /// \brief Compare this datetime to another. + /// + /// Returns < 0 if this datetime is before the other, 0 of they are + /// equal, and > 0 if this datetime is after the other. + /// + /// This method is protected because it is merely the engine used + /// by the various operators in DTbase. + MYSQLPP_EXPORT short compare(const DateTime& other) const; + + /// \brief Parse a MySQL date and time string into this object. + MYSQLPP_EXPORT cchar* convert(cchar*); + + /// Convert to time_t + operator time_t() const; +}; + + +/// \brief Inserts a DateTime object into a C++ stream in a +/// MySQL-compatible format. +/// +/// The date and time are inserted into the stream, in that order, +/// with a space between them. +/// +/// \param os stream to insert date and time into +/// \param dt date/time object to insert into stream +MYSQLPP_EXPORT std::ostream& operator <<(std::ostream& os, + const DateTime& dt); + + +/// \brief C++ form of MySQL's DATE type. +/// +/// Objects of this class can be inserted into streams, and +/// initialized from MySQL DATE strings. +struct Date : public DTbase +{ + /// \brief the year + /// + /// No surprises; the year 2005 is stored as the integer 2005. + short int year; + + /// \brief the month, 1-12 + tiny_int month; + + /// \brief the day, 1-31 + tiny_int day; + + /// \brief Default constructor + Date() : year(0), month(0), day(0) { } + + /// \brief Initialize object + Date(short int y, tiny_int m, tiny_int d) : + DTbase(), + year(y), + month(m), + day(d) + { + } + + /// \brief Initialize object as a copy of another Date + Date(const Date& other) : + DTbase(), + year(other.year), + month(other.month), + day(other.day) + { + } + + /// \brief Initialize object from date part of date/time object + Date(const DateTime& other) : + DTbase(), + year(other.year), + month(other.month), + day(other.day) + { + } + + /// \brief Initialize object from a MySQL date string + /// + /// String must be in the YYYY-MM-DD format. It doesn't have to be + /// zero-padded. + Date(cchar* str) { convert(str); } + + /// \brief Initialize object from a MySQL date string + /// + /// \sa Date(cchar*) + Date(const ColData& str) { convert(str.c_str()); } + + /// \brief Initialize object from a MySQL date string + /// + /// \sa Date(cchar*) + Date(const std::string& str) + { + convert(str.c_str()); + } + + /// \brief Compare this date to another. + /// + /// Returns < 0 if this date is before the other, 0 of they are + /// equal, and > 0 if this date is after the other. + MYSQLPP_EXPORT short int compare(const Date& other) const; + + /// \brief Parse a MySQL date string into this object. + MYSQLPP_EXPORT cchar* convert(cchar*); +}; + +/// \brief Inserts a Date object into a C++ stream +/// +/// The format is YYYY-MM-DD, zero-padded. +/// +/// \param os stream to insert date into +/// \param d date to insert into stream +MYSQLPP_EXPORT std::ostream& operator <<(std::ostream& os, + const Date& d); + + +/// \brief C++ form of MySQL's TIME type. +/// +/// Objects of this class can be inserted into streams, and +/// initialized from MySQL TIME strings. +struct Time : public DTbasequote manipulator, except that +/// it doesn't escape special SQL characters. + +enum quote_only_type0 +{ + quote_only ///< insert into a std::ostream to single-quote next item +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +struct quote_only_type1 +{ + std::ostream* ostr; + quote_only_type1(std::ostream* o) : + ostr(o) + { + } +}; + + +inline quote_only_type1 operator <<(std::ostream& o, + quote_only_type0 /* esc */) +{ + return quote_only_type1(&o); +} + + +struct quote_only_type2 +{ + SQLQueryParms* qparms; + quote_only_type2(SQLQueryParms* p) : + qparms(p) + { + } +}; + + +inline quote_only_type2 operator <<(SQLQueryParms& p, + quote_only_type0 /* esc */) +{ + return quote_only_type2(&p); +} + +MYSQLPP_EXPORT SQLQueryParms& operator <<(quote_only_type2 p, + SQLString& in); + + +template +inline std::ostream& operator <<(quote_only_type1 o, const T& in) +{ + return *o.ostr << in; +} + + +template <> +inline std::ostream& operator <<(quote_only_type1 o, + const std::string& in) +{ + return *o.ostr << '\'' << in << '\''; +} + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(quote_only_type1 o, + const ColData_Tmpl& in); + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(quote_only_type1 o, + const ColData_Tmpl& in); + + +template <> +inline std::ostream& operator <<(quote_only_type1 o, + const Date& in) +{ + return *o.ostr << '\'' << in << '\''; +} + + +template <> +inline std::ostream& operator <<(quote_only_type1 o, + const Time& in) +{ + return *o.ostr << '\'' << in << '\''; +} + + +template <> +inline std::ostream& operator <<(quote_only_type1 o, + const DateTime& in) +{ + return *o.ostr << '\'' << in << '\''; +} + + +template +inline std::ostream& operator <<(quote_only_type1 o, const Set& in) +{ + return *o.ostr << '\'' << in << '\''; +} + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \enum quote_double_only_type0 +/// \anchor quote_double_manip +/// +/// The 'double_quote_only' manipulator. +/// +/// Similar to quote_only manipulator, +/// except that it uses double quotes instead of single quotes. + +enum quote_double_only_type0 +{ + quote_double_only ///< insert into a std::ostream to double-quote next item +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +struct quote_double_only_type1 +{ + std::ostream* ostr; + quote_double_only_type1(std::ostream* o) : + ostr(o) + { + } +}; + + +inline quote_double_only_type1 operator <<( + std::ostream& o, quote_double_only_type0 /* esc */) +{ + return quote_double_only_type1(&o); +} + + +struct quote_double_only_type2 +{ + SQLQueryParms *qparms; + quote_double_only_type2(SQLQueryParms* p) : + qparms(p) + { + } +}; + + +inline quote_double_only_type2 operator <<( + SQLQueryParms& p, quote_double_only_type0 /* esc */) +{ + return quote_double_only_type2(&p); +} + + +MYSQLPP_EXPORT SQLQueryParms& operator <<(quote_double_only_type2 p, + SQLString& in); + + +template +inline std::ostream& operator <<(quote_double_only_type1 o, const T& in) +{ + return *o.ostr << in; +} + + +template <> +inline std::ostream& operator <<( + quote_double_only_type1 o, const std::string& in) +{ + return *o.ostr << '"' << in << '"'; +} + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(quote_double_only_type1 o, + const ColData_Tmpl& in); + + +template <> +MYSQLPP_EXPORT std::ostream & operator <<(quote_double_only_type1 o, + const ColData_Tmpl& in); + + +template <> +inline std::ostream& operator <<( + quote_double_only_type1 o, const Date& in) +{ + return *o.ostr << '"' << in << '"'; +} + + +template <> +inline std::ostream& operator <<( + quote_double_only_type1 o, const Time& in) +{ + return *o.ostr << '"' << in << '"'; +} + + +template <> +inline std::ostream& operator <<( + quote_double_only_type1 o, const DateTime& in) +{ + return *o.ostr << '"' << in << '"'; +} + + +template +inline std::ostream& operator <<(quote_double_only_type1 o, + const Set& in) +{ + return *o.ostr << '"' << in << '"'; +} + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \enum escape_type0 +/// The 'escape' manipulator. +/// +/// Calls mysql_escape_string() in the MySQL C API on the following +/// argument to prevent any special SQL characters from being +/// interpreted. + +enum escape_type0 { escape }; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +struct escape_type1 +{ + std::ostream* ostr; + escape_type1(std::ostream* o) : + ostr(o) + { + } +}; + + +inline escape_type1 operator <<(std::ostream& o, + escape_type0 /*esc */) +{ + return escape_type1(&o); +} + + +struct escape_type2 +{ + SQLQueryParms *qparms; + escape_type2(SQLQueryParms* p) : + qparms(p) + { + } +}; + + +inline escape_type2 operator <<(SQLQueryParms& p, + escape_type0 /*esc */) +{ + return escape_type2(&p); +} + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \brief Inserts a SQLString into a stream, escaping special SQL +/// characters +/// +/// We actually only do the escaping if in.is_string is set but +/// in.dont_escape is not. If that is not the case, we insert the +/// string data directly. + +MYSQLPP_EXPORT SQLQueryParms& operator <<(escape_type2 p, + SQLString& in); + + +/// \brief Inserts any type T into a stream that has an operator<< +/// defined for it. +/// +/// Does not actually escape that data! Use one of the other forms of +/// operator<< for the escape manipulator if you need escaping. This +/// template exists to catch cases like inserting an \c int after the +/// escape manipulator: you don't actually want escaping in this +/// instance. + +template +inline std::ostream& operator <<(escape_type1 o, const T& in) +{ + return *o.ostr << in; +} + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(escape_type1 o, + const std::string& in); + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(escape_type1 o, + const char* const& in); + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(escape_type1 o, + const ColData_Tmpl& in); + + +template <> +MYSQLPP_EXPORT std::ostream& operator <<(escape_type1 o, + const ColData_Tmpl& in); + + +/// \brief Inserts a C string into a stream, escaping special SQL +/// characters. +/// +/// This version exists solely to handle constness problems. We force +/// everything to the completely-const version: operator<<(escape_type1, +/// const char* const&). + +template <> +inline std::ostream& operator <<(escape_type1 o, + char* const& in) +{ + return operator <<(o, const_cast(in)); +} + + +/// \brief Inserts an array of char into a stream, escaping special SQL +/// characters. + +inline std::ostream& operator <<(escape_type1 o, + char in[]) +{ + return operator <<(o, static_cast(in)); +} + +inline std::ostream& operator <<(escape_type1 o, + const char in[]) +{ + return operator <<(o, const_cast(in)); +} + + +/// \enum do_nothing_type0 +/// \anchor do_nothing_manip +/// +/// The 'do_nothing' manipulator. +/// +/// Does exactly what it says: nothing. Used as a dummy manipulator when +/// you are required to use some manipulator but don't want anything to +/// be done to the following item. When used with SQLQueryParms it will +/// make sure that it does not get formatted in any way, overriding any +/// setting set by the template query. + +enum do_nothing_type0 +{ + do_nothing ///< insert into a std::ostream to override manipulation of next item +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +struct do_nothing_type1 +{ + std::ostream* ostr; + do_nothing_type1(std::ostream* o) : + ostr(o) + { + } +}; + + +inline do_nothing_type1 operator <<(std::ostream& o, + do_nothing_type0 /*esc */) +{ + return do_nothing_type1(&o); +} + + +template +inline std::ostream& operator <<(do_nothing_type1 o, const T& in) +{ + return *o.ostr << in; +} + + +struct do_nothing_type2 +{ + SQLQueryParms *qparms; + do_nothing_type2(SQLQueryParms* p) : + qparms(p) + { + } +}; + + +inline do_nothing_type2 operator <<(SQLQueryParms& p, + do_nothing_type0 /* esc */) +{ + return do_nothing_type2(&p); +} + + +MYSQLPP_EXPORT SQLQueryParms& operator <<(do_nothing_type2 p, + SQLString& in); + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \enum ignore_type0 +/// \anchor ignore_manip +/// +/// The 'ignore' manipulator. +/// +/// Only valid when used with SQLQueryParms. It's a dummy manipulator +/// like the do_nothing manipulator, +/// except that it will not override formatting set by the template +/// query. It is simply ignored. + +enum ignore_type0 +{ + ignore ///< insert into a std::ostream as a dummy manipulator +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +struct ignore_type2 +{ + SQLQueryParms* qparms; + ignore_type2(SQLQueryParms* p) : + qparms(p) + { + } +}; + + +inline ignore_type2 operator <<(SQLQueryParms& p, + ignore_type0 /* esc*/) +{ + return ignore_type2(&p); +} + + +MYSQLPP_EXPORT SQLQueryParms& operator <<(ignore_type2 p, + SQLString& in); + +#endif // !defined(DOXYGEN_IGNORE) + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/myset.cpp b/code/meosdb/mysql++/myset.cpp new file mode 100644 index 0000000..e460496 --- /dev/null +++ b/code/meosdb/mysql++/myset.cpp @@ -0,0 +1,35 @@ +/*********************************************************************** + myset.cpp - Implements the Set template. (Not to be confused with + std::set, which this template wraps.) + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "myset.h" + +namespace mysqlpp { + +template class Set >; + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/myset.h b/code/meosdb/mysql++/myset.h new file mode 100644 index 0000000..3058fa8 --- /dev/null +++ b/code/meosdb/mysql++/myset.h @@ -0,0 +1,157 @@ +/// \file myset.h +/// \brief Declares templates for generating custom containers used +/// elsewhere in the library. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_MYSET_H +#define MYSQLPP_MYSET_H + +#include "common.h" + +#include "coldata.h" +#include "stream2string.h" + +#include +#include +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +template +class MYSQLPP_EXPORT SetInsert +{ +public: + SetInsert(T* o) : object_(o) { } + void operator ()(const key_type& data) { object_->insert(data); } + +private: + T* object_; +}; + +template +inline SetInsert< std::set > set_insert(std::set* o) +{ + return SetInsert< std::set >(o); +} + +template +void set2container(const char* str, Insert insert); + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \brief A special std::set derivative for holding MySQL data sets. + +template > +class MYSQLPP_EXPORT Set : public Container +{ +public: + /// \brief Default constructor + Set() {}; + + /// \brief Create object from a comma-separated list of values + Set(const char* str) + { + set2container(str, set_insert(this)); + } + + /// \brief Create object from a comma-separated list of values + Set(const std::string& str) + { + set2container(str.c_str(), set_insert(this)); + } + + /// \brief Create object from a comma-separated list of values + Set(const ColData& str) + { + set2container(str.c_str(), set_insert(this)); + } + + /// \brief Insert this set's data into a C++ stream in + /// comma-separated format. + std::ostream& out_stream(std::ostream& s) const + { + typename Container::const_iterator i = Container::begin(); + typename Container::const_iterator e = Container::end(); + + while (true) { + s << *i; + if (++i == e) { + break; + } + s << ","; + } + + return s; + } + + /// \brief Convert this set's data to a string containing + /// comma-separated items. + operator std::string() { return stream2string(*this); } +}; + + +/// \brief Inserts a Set object into a C++ stream +template +inline std::ostream& operator <<(std::ostream& s, + const Set& d) +{ + return d.out_stream(s); +} + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +template +void set2container(const char* str, Insert insert) +{ + while (1) { + MutableColData s(""); + while (*str != ',' && *str) { + s += *str; + str++; + } + + insert(s); + + if (!*str) { + break; + } + + str++; + } +} + +#endif // !defined(DOXYGEN_IGNORE) + + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/mysql++.cpp b/code/meosdb/mysql++/mysql++.cpp new file mode 100644 index 0000000..101bb39 --- /dev/null +++ b/code/meosdb/mysql++/mysql++.cpp @@ -0,0 +1,38 @@ +/*********************************************************************** + mysql++.cpp - Implements functions dealing with the library itself, + as opposed to individual features of the library. + + Copyright (c) 2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "mysql++.h" + +namespace mysqlpp { + +unsigned int +get_library_version() +{ + return MYSQLPP_HEADER_VERSION; +} + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/mysql++.h b/code/meosdb/mysql++/mysql++.h new file mode 100644 index 0000000..04625a4 --- /dev/null +++ b/code/meosdb/mysql++/mysql++.h @@ -0,0 +1,140 @@ +/// \file mysql++.h +/// \brief The main MySQL++ header file. +/// +/// This file brings in all MySQL++ headers except for custom.h and +/// custom-macros.h which are a strictly optional feature of MySQL++. +/// +/// There is no point in trying to optimize which headers you include, +/// because the MySQL++ headers are so intertwined. You can only get +/// trivial compile time benefits, at the expense of clarity. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_MYSQLPP_H +#define MYSQLPP_MYSQLPP_H + +/// \brief Encode MySQL++ library version number. +/// +/// This macro takes major, minor and bugfix numbers (e.g. 1, 2, and 3) +/// and encodes them like 0x010203. +#define MYSQLPP_VERSION(major, minor, bugfix) \ + (((major) << 16) | ((minor) << 8) | (bugfix)) + +/// \brief Get the library version number that mysql++.h comes from +/// +/// MySQL++ Version number that the mysql++.h header file comes from, +/// encoded by MYSQLPP_VERSION macro. Compare this value to what +/// mysqlpp_lib_version() returns in order to ensure that your program +/// is using header files from the same version of MySQL++ as the +/// actual library you're linking to. +#define MYSQLPP_HEADER_VERSION MYSQLPP_VERSION(2, 3, 2) + +// This #include order gives the fewest redundancies in the #include +// dependency chain. +#include "connection.h" +#include "query.h" +#include "sql_types.h" + +namespace mysqlpp { + +/// \brief Get the current MySQL++ library version number +/// +/// MySQL++ version number that the program is actually linked to, +/// encoded by MYSQLPP_VERSION macro. Compare this value to the +/// MYSQLPP_HEADER_VERSION constant in order to ensure that your +/// program is using header files from the same version of MySQL++ as +/// the actual library you're linking to. +MYSQLPP_EXPORT unsigned int get_library_version(); + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_MYSQLPP_H) + + +/** + \mainpage MySQL++ Reference Manual + + \section getting_started Getting Started + + The best place to get started is the + user manual. It provides + a guide to the example programs and more. + + + \section classes Major Classes + + In MySQL++, the main user-facing classes are mysqlpp::Connection, + mysqlpp::Query, mysqlpp::Result, and mysqlpp::Row. + + In addition, MySQL++ has a mechanism called Specialized SQL + Structures (SSQLS), which allow you to create C++ structures + that parallel the definition of the tables in your database + schema. These let you manipulate the data in your database using + native C++ data structures. Programs using this feature often + include very little SQL code, because MySQL++ can generate most + of what you need automatically when using SSQLSes. There is a + whole chapter in the user manual on how to use this feature of + the library, plus a section in the user manual's tutorial chapter + to introduce it. It's possible to use MySQL++ effectively without + using SSQLS, but it sure makes some things a lot easier. + + + \section files Major Files + + The only two header files your program ever needs to include + are mysql++.h, and optionally custom.h. (The latter implements + the SSQLS mechanism.) All of the other files are used within + the library only. + + + \section user_questions If You Have Questions... + + If you want to email someone to ask questions about this library, + we greatly prefer that you send mail to the MySQL++ mailing list, + which you can subscribe to here: http://lists.mysql.com/plusplus + + That mailing list is archived, so if you have questions, do a + search to see if the question has been asked before. + + You may find people's individual email addresses in various + files within the MySQL++ distribution. Please do not send mail + to them unless you are sending something that is inherently + personal. Questions that are about MySQL++ usage may well be + ignored if you send them to our personal email accounts. Those of + us still active in MySQL++ development monitor the mailing list, + so you aren't getting any extra "coverage" by sending messages + to those addresses in addition to the mailing list. + + + \section licensing Licensing + + MySQL++ is licensed under the GNU Lesser General Public License, + which you should have received with the distribution package in + a file called "LGPL" or "LICENSE". You can also view it here: + http://www.gnu.org/licenses/lgpl.html or receive a copy by + writing to Free Software Foundation, Inc., 51 Franklin Street, + Fifth Floor, Boston, MA 02110-1301, USA. +*/ + diff --git a/code/meosdb/mysql++/mysql++.h.in b/code/meosdb/mysql++/mysql++.h.in new file mode 100644 index 0000000..65395a5 --- /dev/null +++ b/code/meosdb/mysql++/mysql++.h.in @@ -0,0 +1,140 @@ +/// \file mysql++.h +/// \brief The main MySQL++ header file. +/// +/// This file brings in all MySQL++ headers except for custom.h and +/// custom-macros.h which are a strictly optional feature of MySQL++. +/// +/// There is no point in trying to optimize which headers you include, +/// because the MySQL++ headers are so intertwined. You can only get +/// trivial compile time benefits, at the expense of clarity. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_MYSQLPP_H +#define MYSQLPP_MYSQLPP_H + +/// \brief Encode MySQL++ library version number. +/// +/// This macro takes major, minor and bugfix numbers (e.g. 1, 2, and 3) +/// and encodes them like 0x010203. +#define MYSQLPP_VERSION(major, minor, bugfix) \ + (((major) << 16) | ((minor) << 8) | (bugfix)) + +/// \brief Get the library version number that mysql++.h comes from +/// +/// MySQL++ Version number that the mysql++.h header file comes from, +/// encoded by MYSQLPP_VERSION macro. Compare this value to what +/// mysqlpp_lib_version() returns in order to ensure that your program +/// is using header files from the same version of MySQL++ as the +/// actual library you're linking to. +#define MYSQLPP_HEADER_VERSION MYSQLPP_VERSION(@MYSQLPP_VERSION_MAJOR@, @MYSQLPP_VERSION_MINOR@, @MYSQLPP_VERSION_BUGFIX@) + +// This #include order gives the fewest redundancies in the #include +// dependency chain. +#include "connection.h" +#include "query.h" +#include "sql_types.h" + +namespace mysqlpp { + +/// \brief Get the current MySQL++ library version number +/// +/// MySQL++ version number that the program is actually linked to, +/// encoded by MYSQLPP_VERSION macro. Compare this value to the +/// MYSQLPP_HEADER_VERSION constant in order to ensure that your +/// program is using header files from the same version of MySQL++ as +/// the actual library you're linking to. +MYSQLPP_EXPORT unsigned int get_library_version(); + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_MYSQLPP_H) + + +/** + \mainpage MySQL++ Reference Manual + + \section getting_started Getting Started + + The best place to get started is the + user manual. It provides + a guide to the example programs and more. + + + \section classes Major Classes + + In MySQL++, the main user-facing classes are mysqlpp::Connection, + mysqlpp::Query, mysqlpp::Result, and mysqlpp::Row. + + In addition, MySQL++ has a mechanism called Specialized SQL + Structures (SSQLS), which allow you to create C++ structures + that parallel the definition of the tables in your database + schema. These let you manipulate the data in your database using + native C++ data structures. Programs using this feature often + include very little SQL code, because MySQL++ can generate most + of what you need automatically when using SSQLSes. There is a + whole chapter in the user manual on how to use this feature of + the library, plus a section in the user manual's tutorial chapter + to introduce it. It's possible to use MySQL++ effectively without + using SSQLS, but it sure makes some things a lot easier. + + + \section files Major Files + + The only two header files your program ever needs to include + are mysql++.h, and optionally custom.h. (The latter implements + the SSQLS mechanism.) All of the other files are used within + the library only. + + + \section user_questions If You Have Questions... + + If you want to email someone to ask questions about this library, + we greatly prefer that you send mail to the MySQL++ mailing list, + which you can subscribe to here: http://lists.mysql.com/plusplus + + That mailing list is archived, so if you have questions, do a + search to see if the question has been asked before. + + You may find people's individual email addresses in various + files within the MySQL++ distribution. Please do not send mail + to them unless you are sending something that is inherently + personal. Questions that are about MySQL++ usage may well be + ignored if you send them to our personal email accounts. Those of + us still active in MySQL++ development monitor the mailing list, + so you aren't getting any extra "coverage" by sending messages + to those addresses in addition to the mailing list. + + + \section licensing Licensing + + MySQL++ is licensed under the GNU Lesser General Public License, + which you should have received with the distribution package in + a file called "LGPL" or "LICENSE". You can also view it here: + http://www.gnu.org/licenses/lgpl.html or receive a copy by + writing to Free Software Foundation, Inc., 51 Franklin Street, + Fifth Floor, Boston, MA 02110-1301, USA. +*/ + diff --git a/code/meosdb/mysql++/noexceptions.h b/code/meosdb/mysql++/noexceptions.h new file mode 100644 index 0000000..ee6bdbc --- /dev/null +++ b/code/meosdb/mysql++/noexceptions.h @@ -0,0 +1,138 @@ +/// \file noexceptions.h +/// \brief Declares interface that allows exceptions to be optional +/// +/// A class may inherit from OptionalExceptions, which will add to it +/// a mechanism by which a user can tell objects of that class to +/// suppress exceptions. (They are enabled by default.) This module +/// also declares a NoExceptions class, objects of which take a +/// reference to any class derived from OptionalExceptions. The +/// NoExceptions constructor calls the method that disables exceptions, +/// and the destructor reverts them to the previous state. One uses +/// the NoExceptions object within a scope to suppress exceptions in +/// that block, without having to worry about reverting the setting when +/// the block exits. + +/*********************************************************************** + Copyright (c) 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_NOEXCEPTIONS_H +#define MYSQLPP_NOEXCEPTIONS_H + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT NoExceptions; +#endif + +/// \brief Interface allowing a class to have optional exceptions. +/// +/// A class derives from this one to acquire a standard interface for +/// disabling exceptions, possibly only temporarily. By default, +/// exceptions are enabled. + +class MYSQLPP_EXPORT OptionalExceptions +{ +public: + /// \brief Default constructor + /// + /// \param e if true, exceptions are enabled (this is the default) + OptionalExceptions(bool e = true) : + exceptions_(e) + { + } + + /// \brief Destroy object + virtual ~OptionalExceptions() { } + + /// \brief Enable exceptions from the object + void enable_exceptions() { exceptions_ = true; } + + /// \brief Disable exceptions from the object + void disable_exceptions() { exceptions_ = false; } + + /// \brief Returns true if exceptions are enabled + bool throw_exceptions() const { return exceptions_; } + +protected: + /// \brief Sets the exception state to a particular value + /// + /// This method is protected because it is only intended for use by + /// subclasses' copy constructors and the like. + void set_exceptions(bool e) { exceptions_ = e; } + + /// \brief Declare NoExceptions to be our friend so it can access + /// our protected functions. + friend class NoExceptions; + +private: + bool exceptions_; +}; + + +/// \brief Disable exceptions in an object derived from +/// OptionalExceptions. +/// +/// This class was designed to be created on the stack, taking a +/// reference to a subclass of OptionalExceptions. (We call that our +/// "associate" object.) On creation, we save that object's current +/// exception state, and disable exceptions. On destruction, we restore +/// our associate's previous state. + +class MYSQLPP_EXPORT NoExceptions +{ +public: + /// \brief Constructor + /// + /// Takes a reference to an OptionalExceptions derivative, + /// saves that object's current exception state, and disables + /// exceptions. + NoExceptions(OptionalExceptions& a) : + assoc_(a), + exceptions_were_enabled_(a.throw_exceptions()) + { + assoc_.disable_exceptions(); + } + + /// \brief Destructor + /// + /// Restores our associate object's previous exception state. + ~NoExceptions() + { + assoc_.set_exceptions(exceptions_were_enabled_); + } + +private: + OptionalExceptions& assoc_; + bool exceptions_were_enabled_; + + // Hidden assignment operator and copy ctor, because we should not + // be copied. + NoExceptions(const NoExceptions&); + NoExceptions& operator=(const NoExceptions&); +}; + +} // end namespace mysqlpp + +#endif // MYSQLPP_NOEXCEPTIONS_H + diff --git a/code/meosdb/mysql++/null.h b/code/meosdb/mysql++/null.h new file mode 100644 index 0000000..ac453e9 --- /dev/null +++ b/code/meosdb/mysql++/null.h @@ -0,0 +1,278 @@ +/// \file null.h +/// \brief Declares classes that implement SQL "null" semantics within +/// C++'s type system. +/// +/// This is required because C++'s own NULL type is not semantically +/// the same as SQL nulls. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_NULL_H +#define MYSQLPP_NULL_H + +#include "exceptions.h" + +#include + +namespace mysqlpp { + + +/// \brief The type of the global mysqlpp::null object. +/// +/// This class is for internal use only. Normal code should use +/// Null instead. +class MYSQLPP_EXPORT null_type +{ +public: +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + template operator Type() + { + throw BadNullConversion(); + return Type(); + } +#endif // !defined(DOXYGEN_IGNORE) +}; + +/// \brief Global 'null' instance. Use wherever you need a SQL null. +/// (As opposed to a C++ language null pointer or null character.) +const null_type null = null_type(); + + +/// \brief Class for objects that define SQL null in terms of +/// MySQL++'s null_type. +/// +/// Returns a null_type instance when you ask what null is, and is +/// "(NULL)" when you insert it into a C++ stream. +/// +/// Used for the behavior parameter for template Null +struct NullisNull +{ +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + static null_type null_is() { return null_type(); } + + static std::ostream& null_ostr(std::ostream& o) + { + o << "(NULL)"; + return o; + } +#endif // !defined(DOXYGEN_IGNORE) +}; + + +/// \brief Class for objects that define SQL null as 0. +/// +/// Returns 0 when you ask what null is, and is zero when you insert it +/// into a C++ stream. +/// +/// Used for the behavior parameter for template Null +struct NullisZero +{ +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + static int null_is() { return 0; } + + static std::ostream& null_ostr(std::ostream& o) + { + o << 0; + return o; + } +#endif // !defined(DOXYGEN_IGNORE) +}; + +/// \brief Class for objects that define SQL null as a blank C string. +/// +/// Returns "" when you ask what null is, and is empty when you insert +/// it into a C++ stream. +/// +/// Used for the behavior parameter for template Null +struct NullisBlank +{ +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + static const char *null_is() { return ""; } + + static std::ostream& null_ostr(std::ostream& o) + { + o << ""; + return o; + } +#endif // !defined(DOXYGEN_IGNORE) +}; + + +/// \brief Class for holding data from a SQL column with the NULL +/// attribute. +/// +/// This template is necessary because there is nothing in the C++ type +/// system with the same semantics as SQL's null. In SQL, a column can +/// have the optional 'NULL' attribute, so there is a difference in +/// type between, say an \c int column that can be null and one that +/// cannot be. C++'s NULL constant does not have these features. +/// +/// It's important to realize that this class doesn't hold nulls, +/// it holds data that \e can \e be null. It can hold a non-null +/// value, you can then assign null to it (using MySQL++'s global +/// \c null object), and then assign a regular value to it again; the +/// object will behave as you expect throughout this process. +/// +/// Because one of the template parameters is a C++ type, the typeid() +/// for a null \c int is different than for a null \c string, to pick +/// two random examples. See type_info.cpp for the table SQL types that +/// can be null. +template class Null +{ +public: + /// \brief The object's value, when it is not SQL null + Type data; + + /// \brief If set, this object is considered equal to SQL null. + /// + /// This flag affects how the Type() and << operators work. + bool is_null; + + /// \brief Type of the data stored in this object, when it is not + /// equal to SQL null. + typedef Type value_type; + + /// \brief Default constructor + /// + /// "data" member is left uninitialized by this ctor, because we + /// don't know what to initialize it to. + Null() : + is_null(false) + { + } + + /// \brief Initialize the object with a particular value. + /// + /// The object is marked as "not null" if you use this ctor. This + /// behavior exists because the class doesn't encode nulls, but + /// rather data which \e can \e be null. The distinction is + /// necessary because 'NULL' is an optional attribute of SQL + /// columns. + Null(const Type& x) : + data(x), + is_null(false) + { + } + + /// \brief Construct a Null equal to SQL null + /// + /// This is typically used with the global \c null object. (Not to + /// be confused with C's NULL type.) You can say something like... + /// \code + /// Null foo = null; + /// \endcode + /// ...to get a null \c int. + Null(const null_type& n) : + is_null(true) + { + } + + /// \brief Converts this object to Type + /// + /// If is_null is set, returns whatever we consider that null "is", + /// according to the Behavior parameter you used when instantiating + /// this template. See NullisNull, NullisZero and NullisBlank. + /// + /// Otherwise, just returns the 'data' member. + operator Type&() + { + if (is_null) + return data = Behavior::null_is(); + else + return data; + } + + /// \brief Assign a value to the object. + /// + /// This marks the object as "not null" as a side effect. + Null& operator =(const Type& x) + { + data = x; + is_null = false; + return *this; + } + + /// \brief Assign SQL null to this object. + /// + /// This just sets the is_null flag; the data member is not + /// affected until you call the Type() operator on it. + Null& operator =(const null_type& n) + { + is_null = true; + return *this; + } +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +// Specialization the Null template for \c void +template <> class Null +{ +public: + bool is_null; + typedef void value_type; + + Null() : + is_null(false) + { + } + + Null(const null_type&) : + is_null(true) + { + } + + Null& operator =(const null_type&) + { + is_null = true; + return *this; + } +}; + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \brief Inserts null-able data into a C++ stream if it is not +/// actually null. Otherwise, insert something appropriate for null +/// data. +template +inline std::ostream& operator <<(std::ostream& o, + const Null& n) +{ + if (n.is_null) + return Behavior::null_ostr(o); + else + return o << n.data; +} + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/qparms.cpp b/code/meosdb/mysql++/qparms.cpp new file mode 100644 index 0000000..aa6d91c --- /dev/null +++ b/code/meosdb/mysql++/qparms.cpp @@ -0,0 +1,69 @@ +/*********************************************************************** + qparms.cpp - Implements the SQLQuery class. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "qparms.h" + +#include "query.h" + +using namespace std; + +namespace mysqlpp { + +SQLString& +SQLQueryParms::operator [](const char* str) +{ + if (parent_) { + return operator [](parent_->parsed_nums_[str]); + } + throw ObjectNotInitialized("SQLQueryParms object has no parent!"); +} + +const SQLString& +SQLQueryParms::operator[] (const char* str) const +{ + if (parent_) { + return operator [](parent_->parsed_nums_[str]); + } + throw ObjectNotInitialized("SQLQueryParms object has no parent!"); +} + +SQLQueryParms +SQLQueryParms::operator +(const SQLQueryParms& other) const +{ + if (other.size() <= size()) { + return *this; + } + SQLQueryParms New = *this; + size_t i; + for (i = size(); i < other.size(); i++) { + New.push_back(other[i]); + } + + return New; +} + + +} // end namespace mysqlpp diff --git a/code/meosdb/mysql++/qparms.h b/code/meosdb/mysql++/qparms.h new file mode 100644 index 0000000..1569f6e --- /dev/null +++ b/code/meosdb/mysql++/qparms.h @@ -0,0 +1,255 @@ +/// \file qparms.h +/// \brief Declares the template query parameter-related stuff. +/// +/// The classes defined in this file are used by class Query when it +/// parses a template query: they hold information that it finds in the +/// template, so it can assemble a SQL statement later on demand. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_QPARMS_H +#define MYSQLPP_QPARMS_H + +#include "sql_string.h" + +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Query; +#endif + +/// \brief This class holds the parameter values for filling +/// template queries. +class MYSQLPP_EXPORT SQLQueryParms : public std::vector +{ +public: + /// \brief Abbreviation so some of the declarations below don't + /// span many lines. + typedef const SQLString& ss; + + /// \brief Default constructor + SQLQueryParms() : + parent_(0), + processing_(false) + { + } + + /// \brief Create object + /// + /// \param p pointer to the query object these parameters are tied + /// to + SQLQueryParms(Query* p) : + parent_(p), + processing_(false) + { + } + + /// \brief Returns true if we are bound to a query object. + /// + /// Basically, this tells you which of the two ctors were called. + bool bound() + { + return parent_ != 0; + } + + /// \brief Clears the list + void clear() + { + erase(begin(), end()); + } + + /// \brief Access element number n + SQLString& operator [](size_type n) + { + if (n >= size()) + insert(end(), (n + 1) - size(), ""); + return std::vector::operator [](n); + } + + /// \brief Access element number n + const SQLString& operator [](size_type n) const + { + return std::vector::operator [](n); + } + + /// \brief Access the value of the element with a key of str. + SQLString& operator [](const char *str); + + /// \brief Access the value of the element with a key of str. + const SQLString& operator [](const char *str) const; + + /// \brief Adds an element to the list + SQLQueryParms& operator <<(const SQLString& str) + { + push_back(str); + return *this; + } + + /// \brief Adds an element to the list + SQLQueryParms& operator +=(const SQLString& str) + { + push_back(str); + return *this; + } + + /// \brief Build a composite of two parameter lists + /// + /// If this list is (a, b) and \c other is (c, d, e, f, g), then + /// the returned list will be (a, b, e, f, g). That is, all of this + /// list's parameters are in the returned list, plus any from the + /// other list that are in positions beyond what exist in this list. + /// + /// If the two lists are the same length or this list is longer than + /// the \c other list, a copy of this list is returned. + SQLQueryParms operator +( + const SQLQueryParms& other) const; + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + void set(ss a) + { + clear(); + *this << a; + } + void set(ss a, ss b) + { + clear(); + *this << a << b; + } + void set(ss a, ss b, ss c) + { + clear(); + *this << a << b << c; + } + void set(ss a, ss b, ss c, ss d) + { + clear(); + *this << a << b << c << d; + } + void set(ss a, ss b, ss c, ss d, ss e) + { + clear(); + *this << a << b << c << d << e; + } + void set(ss a, ss b, ss c, ss d, ss e, ss f) + { + clear(); + *this << a << b << c << d << e << f; + } + void set(ss a, ss b, ss c, ss d, ss e, ss f, ss g) + { + clear(); + *this << a << b << c << d << e << f << g; + } + void set(ss a, ss b, ss c, ss d, ss e, ss f, ss g, ss h) + { + clear(); + *this << a << b << c << d << e << f << g << h; + } + void set(ss a, ss b, ss c, ss d, ss e, ss f, ss g, ss h, ss i) + { + clear(); + *this << a << b << c << d << e << f << g << h << i; + } + void set(ss a, ss b, ss c, ss d, ss e, ss f, ss g, ss h, ss i, ss j) + { + clear(); + *this << a << b << c << d << e << f << g << h << i << j; + } + void set(ss a, ss b, ss c, ss d, ss e, ss f, ss g, ss h, ss i, ss j, ss k) + { + clear(); + *this << a << b << c << d << e << f << g << h << i << j << k; + } +#endif // !defined(DOXYGEN_IGNORE) + + /// \brief Set the template query parameters. + /// + /// Sets parameter 0 to a, parameter 1 to b, etc. There are + /// overloaded versions of this function that take anywhere from + /// one to a dozen parameters. + void set(ss a, ss b, ss c, ss d, ss e, ss f, ss g, + ss h, ss i, ss j, ss k, ss l) + { + clear(); + *this << a << b << c << d << e << f << g << h << i << j << k << l; + } + +private: + friend class Query; + + Query* parent_; + bool processing_; ///< true if we're building a query string +}; + + +/// \brief Used within Query to hold elements for parameterized +/// queries. +/// +/// Each element has three parts: +/// +/// The concept behind the \c before variable needs a little explaining. +/// When a template query is parsed, each parameter is parsed into one +/// of these SQLParseElement objects, but the non-parameter parts of the +/// template also have to be stored somewhere. MySQL++ chooses to +/// attach the text leading up to a parameter to that parameter. So, +/// the \c before string is simply the text copied literally into the +/// finished query before we insert a value for the parameter. +/// +/// The \c option character is currently one of 'q', 'Q', 'r', 'R' or +/// ' '. See the "Template Queries" chapter in the user manual for +/// details. +/// +/// The position value (\c num) allows a template query to have its +/// parameters in a different order than in the Query method call. +/// An example of how this can be helpful is in the "Template Queries" +/// chapter of the user manual. + +struct SQLParseElement +{ + /// \brief Create object + /// + /// \param b the 'before' value + /// \param o the 'option' value + /// \param n the 'num' value + SQLParseElement(std::string b, char o, signed char n) : + before(b), + option(o), + num(n) + { + } + + std::string before; ///< string inserted before the parameter + char option; ///< the parameter option, or blank if none + signed char num; ///< the parameter position to use +}; + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_QPARMS_H) + diff --git a/code/meosdb/mysql++/query.cpp b/code/meosdb/mysql++/query.cpp new file mode 100644 index 0000000..85f8bd9 --- /dev/null +++ b/code/meosdb/mysql++/query.cpp @@ -0,0 +1,656 @@ +/*********************************************************************** + query.cpp - Implements the Query class. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "query.h" + +#include "autoflag.h" +#include "connection.h" + +namespace mysqlpp { + +Query::Query(Connection* c, bool te) : +#if defined(_MSC_VER) && !defined(_STLP_VERSION) && !defined(_STLP_VERSION_STR) +// prevents a double-init memory leak in native VC++ RTL (not STLport!) +std::ostream(std::_Noinit), +#else +std::ostream(0), +#endif +OptionalExceptions(te), +Lockable(false), +def(this), +conn_(c), +success_(false) +{ + init(&sbuffer_); + success_ = true; +} + +Query::Query(const Query& q) : +#if defined(_MSC_VER) && !defined(_STLP_VERSION) && !defined(_STLP_VERSION_STR) +// ditto above +std::ostream(std::_Noinit), +#else +std::ostream(0), +#endif +OptionalExceptions(q.throw_exceptions()), +Lockable(q.locked()), +def(q.def), +conn_(q.conn_), +success_(q.success_) +{ + init(&sbuffer_); +} + + +Query& +Query::operator=(const Query& rhs) +{ + set_exceptions(rhs.throw_exceptions()); + set_lock(rhs.locked()); + def = rhs.def; + conn_ = rhs.conn_; + success_ = rhs.success_; + + return *this; +} + + +my_ulonglong +Query::affected_rows() const +{ + return conn_->affected_rows(); +} + + +std::string +Query::error() +{ + return conn_->error(); +} + + +bool +Query::exec(const std::string& str) +{ + success_ = !mysql_real_query(&conn_->mysql_, str.data(), + static_cast(str.length())); + if (!success_ && throw_exceptions()) { + throw BadQuery(error()); + } + else { + return success_; + } +} + + +ResNSel +Query::execute(const SQLString& str) +{ + if ((parse_elems_.size() == 2) && !def.processing_) { + // We're a template query and we haven't gone through this path + // before, so take str to be a lone parameter for the query. + // We will come back through this function with a completed + // query, but the processing_ flag will be reset, allowing us to + // take the 'else' path, avoiding an infinite loop. + AutoFlag<> af(def.processing_); + return execute(SQLQueryParms() << str); + } + else { + // Take str to be the entire query string + return execute(str.data(), str.length()); + } +} + + +ResNSel +Query::execute(const char* str) +{ + return execute(SQLString(str)); +} + + +ResNSel +Query::execute(const char* str, size_t len) +{ + if (lock()) { + success_ = false; + if (throw_exceptions()) { + throw LockFailed(); + } + else { + return ResNSel(); + } + } + + success_ = !mysql_real_query(&conn_->mysql_, str, len); + + unlock(); + if (success_) { + return ResNSel(conn_); + } + else if (throw_exceptions()) { + throw BadQuery(error()); + } + else { + return ResNSel(); + } +} + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +ResNSel +Query::execute(SQLQueryParms& p) +{ + return execute(str(p, parse_elems_.size() ? DONT_RESET : RESET_QUERY)); +} + +#endif // !defined(DOXYGEN_IGNORE) + + +std::string +Query::info() +{ + return conn_->info(); +} + + +my_ulonglong +Query::insert_id() +{ + return conn_->insert_id(); +} + + +bool +Query::lock() +{ + return conn_->lock(); +} + + +bool +Query::more_results() +{ +#if MYSQL_VERSION_ID > 41000 // only in MySQL v4.1 + + return mysql_more_results(&conn_->mysql_); +#else + return false; +#endif +} + + +void +Query::parse() +{ + std::string str = ""; + char num[4]; + std::string name; + char *s, *s0; + s0 = s = preview_char(); + while (*s) { + if (*s == '%') { + // Following might be a template parameter declaration... + s++; + if (*s == '%') { + // Doubled percent sign, so insert literal percent sign. + str += *s++; + } + else if (isdigit(*s)) { + // Number following percent sign, so it signifies a + // positional parameter. First step: find position + // value, up to 3 digits long. + num[0] = *s; + s++; + if (isdigit(*s)) { + num[1] = *s; + num[2] = 0; + s++; + if (isdigit(*s)) { + num[2] = *s; + num[3] = 0; + s++; + } + else { + num[2] = 0; + } + } + else { + num[1] = 0; + } + signed char n = atoi(num); + + // Look for option character following position value. + char option = ' '; + if (*s == 'q' || *s == 'Q' || *s == 'r' || *s == 'R') { + option = *s++; + } + + // Is it a named parameter? + if (*s == ':') { + // Save all alphanumeric and underscore characters + // following colon as parameter name. + s++; + for (/* */; isalnum(*s) || *s == '_'; ++s) { + name += *s; + } + + // Eat trailing colon, if it's present. + if (*s == ':') { + s++; + } + + // Update maps that translate parameter name to + // number and vice versa. + if (n >= static_cast(parsed_names_.size())) { + parsed_names_.insert(parsed_names_.end(), + static_cast::size_type>( + n + 1) - parsed_names_.size(), + std::string()); + } + parsed_names_[n] = name; + parsed_nums_[name] = n; + } + + // Finished parsing parameter; save it. + parse_elems_.push_back(SQLParseElement(str, option, n)); + str = ""; + name = ""; + } + else { + // Insert literal percent sign, because sign didn't + // precede a valid parameter string; this allows users + // to play a little fast and loose with the rules, + // avoiding a double percent sign here. + str += '%'; + } + } + else { + // Regular character, so just copy it. + str += *s++; + } + } + + parse_elems_.push_back(SQLParseElement(str, ' ', -1)); + delete[] s0; +} + + +SQLString* +Query::pprepare(char option, SQLString& S, bool replace) +{ + if (S.processed) { + return &S; + } + + if (option == 'r' || (option == 'q' && S.is_string)) { + char *s = new char[S.size() * 2 + 1]; + mysql_real_escape_string(&conn_->mysql_, s, S.data(), + static_cast(S.size())); + SQLString *ss = new SQLString("'"); + *ss += s; + *ss += "'"; + delete[] s; + + if (replace) { + S = *ss; + S.processed = true; + delete ss; + return &S; + } + else { + return ss; + } + } + else if (option == 'R' || (option == 'Q' && S.is_string)) { + SQLString *ss = new SQLString("'" + S + "'"); + + if (replace) { + S = *ss; + S.processed = true; + delete ss; + return &S; + } + else { + return ss; + } + } + else { + if (replace) { + S.processed = true; + } + return &S; + } +} + + +char* +Query::preview_char() +{ + const std::string& str(sbuffer_.str()); + char* s = new char[str.size() + 1]; + memcpy(s, str.data(), str.size()); + s[str.size()] = '\0'; + return s; +} + + +void +Query::proc(SQLQueryParms& p) +{ + sbuffer_.str(""); + + for (std::vector::iterator i = parse_elems_.begin(); + i != parse_elems_.end(); ++i) { + MYSQLPP_QUERY_THISPTR << i->before; + int num = i->num; + if (num >= 0) { + SQLQueryParms* c; + if (size_t(num) < p.size()) { + c = &p; + } + else if (size_t(num) < def.size()) { + c = &def; + } + else { + *this << " ERROR"; + throw BadParamCount( + "Not enough parameters to fill the template."); + } + + SQLString& param = (*c)[num]; + SQLString* ss = pprepare(i->option, param, c->bound()); + MYSQLPP_QUERY_THISPTR << *ss; + if (ss != ¶m) { + // pprepare() returned a new string object instead of + // updating param in place, so we need to delete it. + delete ss; + } + } + } +} + +void +Query::reset() +{ + seekp(0); + clear(); + sbuffer_.str(""); + + parse_elems_.clear(); + def.clear(); +} + + +Result +Query::store(const SQLString& str) +{ + if ((parse_elems_.size() == 2) && !def.processing_) { + // We're a template query and we haven't gone through this path + // before, so take str to be a lone parameter for the query. + // We will come back through this function with a completed + // query, but the processing_ flag will be reset, allowing us to + // take the 'else' path, avoiding an infinite loop. + AutoFlag<> af(def.processing_); + return store(SQLQueryParms() << str); + } + else { + // Take str to be the entire query string + return store(str.data(), str.length()); + } +} + + +Result +Query::store(const char* str) +{ + return store(SQLString(str)); +} + + +Result +Query::store(const char* str, size_t len) +{ + if (lock()) { + success_ = false; + if (throw_exceptions()) { + throw LockFailed(); + } + else { + return Result(); + } + } + + + if (success_ = !mysql_real_query(&conn_->mysql_, str, len)) { + MYSQL_RES* res = mysql_store_result(&conn_->mysql_); + if (res) { + unlock(); + return Result(res, throw_exceptions()); + } + else { + success_ = false; + } + } + unlock(); + + // One of the MySQL API calls failed, but it's not an error if we + // just get an empty result set. It happens when store()ing a query + // that doesn't always return results. While it's better to use + // exec*() in that situation, it's legal to call store() instead, + // and sometimes you have no choice. For example, if the SQL comes + // from outside the program so you can't predict whether there will + // be results. + if (conn_->errnum() && throw_exceptions()) { + throw BadQuery(error()); + } + else { + return Result(); + } +} + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +Result +Query::store(SQLQueryParms& p) +{ + return store(str(p, parse_elems_.size() ? DONT_RESET : RESET_QUERY)); +} + +#endif // !defined(DOXYGEN_IGNORE) + + +Result +Query::store_next() +{ +#if MYSQL_VERSION_ID > 41000 // only in MySQL v4.1 + + if (lock()) { + if (throw_exceptions()) { + throw LockFailed(); + } + else { + return Result(); + } + } + + int ret; + if ((ret = mysql_next_result(&conn_->mysql_)) == 0) { + // There are more results, so return next result set. + MYSQL_RES* res = mysql_store_result(&conn_->mysql_); + unlock(); + if (res) { + return Result(res, throw_exceptions()); + } + else { + // Result set is null, but throw an exception only i it is + // null because of some error. If not, it's just an empty + // result set, which is harmless. We return an empty result + // set if exceptions are disabled, as well. + if (conn_->errnum() && throw_exceptions()) { + throw BadQuery(error()); + } + else { + return Result(); + } + } + } + else { + // No more results, or some other error occurred. + unlock(); + if (throw_exceptions()) { + if (ret > 0) { + throw BadQuery(error()); + } + else { + throw EndOfResultSets(); + } + } + else { + return Result(); + } + } +#else + return store(); +#endif // MySQL v4.1+ +} + + +std::string +Query::str(SQLQueryParms& p) +{ + if (!parse_elems_.empty()) { + proc(p); + } + + return sbuffer_.str(); +} + + +std::string +Query::str(SQLQueryParms& p, query_reset r) +{ + std::string tmp = str(p); + if (r == RESET_QUERY) { + reset(); + } + return tmp; +} + + +bool +Query::success() +{ + return success_ && conn_->success(); +} + + +void +Query::unlock() +{ + conn_->unlock(); +} + + +ResUse +Query::use(const SQLString& str) +{ + if ((parse_elems_.size() == 2) && !def.processing_) { + // We're a template query and we haven't gone through this path + // before, so take str to be a lone parameter for the query. + // We will come back through this function with a completed + // query, but the processing_ flag will be reset, allowing us to + // take the 'else' path, avoiding an infinite loop. + AutoFlag<> af(def.processing_); + return use(SQLQueryParms() << str); + } + else { + // Take str to be the entire query string + return use(str.data(), str.length()); + } +} + + +ResUse +Query::use(const char* str) +{ + return use(SQLString(str)); +} + + +ResUse +Query::use(const char* str, size_t len) +{ + if (lock()) { + success_ = false; + if (throw_exceptions()) { + throw LockFailed(); + } + else { + return ResUse(); + } + } + + if (success_ = !mysql_real_query(&conn_->mysql_, str, len)) { + MYSQL_RES* res = mysql_use_result(&conn_->mysql_); + if (res) { + unlock(); + return ResUse(res, conn_, throw_exceptions()); + } + } + unlock(); + + // One of the MySQL API calls failed, but it's not an error if we + // just get an empty result set. It happens when use()ing a query + // that doesn't always return results. While it's better to use + // exec*() in that situation, it's legal to call use() instead, and + // sometimes you have no choice. For example, if the SQL comes + // from outside the program so you can't predict whether there will + // be results. + if (conn_->errnum() && throw_exceptions()) { + throw BadQuery(error()); + } + else { + return ResUse(); + } +} + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +ResUse +Query::use(SQLQueryParms& p) +{ + return use(str(p, parse_elems_.size() ? DONT_RESET : RESET_QUERY)); +} + +#endif // !defined(DOXYGEN_IGNORE) + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/query.h b/code/meosdb/mysql++/query.h new file mode 100644 index 0000000..2ceaba2 --- /dev/null +++ b/code/meosdb/mysql++/query.h @@ -0,0 +1,930 @@ +/// \file query.h +/// \brief Defines a class for building and executing SQL queries. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2006 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_QUERY_H +#define MYSQLPP_QUERY_H + +#include "common.h" + +#include "lockable.h" +#include "noexceptions.h" +#include "qparms.h" +#include "querydef.h" +#include "result.h" +#include "row.h" +#include "sql_string.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_EXT_SLIST +# include +#else +# if defined(HAVE_STD_SLIST) || defined(HAVE_GLOBAL_SLIST) +# include +# endif +#endif + +/// \def MYSQLPP_QUERY_THISPTR +/// \brief Helper macro used inside MySQL++ to work around a VC++ 2003 bug +/// +/// This macro returns '*this', either directly or upcast to Query's +/// base class to work around an error in the overloaded operator +/// lookup logic in VC++ 2003. For an explanation of the problem, see: +/// http://groups.google.com/group/microsoft.public.vc.stl/browse_thread/thread/9a68d84644e64f15 +#if defined(_MSC_VER) && (_MSC_VER < 1400) +# define MYSQLPP_QUERY_THISPTR dynamic_cast(*this) +#else +# define MYSQLPP_QUERY_THISPTR *this +#endif + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Connection; +#endif + +/// \brief Used for indicating whether a query object should auto-reset +enum query_reset { DONT_RESET, RESET_QUERY }; + +/// \brief A class for building and executing SQL queries. +/// +/// This class is derived from SQLQuery. It adds to that a tie between +/// the query object and a MySQL++ +/// \link mysqlpp::Connection Connection \endlink object, so that +/// the query can be sent to the MySQL server we're connected to. +/// +/// One does not generally create Query objects directly. Instead, call +/// mysqlpp::Connection::query() to get one tied to that connection. +/// +/// There are several ways to build and execute SQL queries with this +/// class. +/// +/// The way most like other database libraries is to pass a SQL +/// statement to one of the +/// \link mysqlpp::Query::execute() exec*(), \endlink +/// \link mysqlpp::Query::store() store*(), \endlink or use() methods +/// taking a C or C++ string. The query is executed immediately, and +/// any results returned. +/// +/// For more complicated queries, you can use Query's stream interface. +/// You simply build up a query using the Query instance as you would +/// any other C++ stream object. When the query string is complete, you +/// call the overloaded version of \c exec*(), \c store*() or \c use() +/// that takes no parameters, which executes the built query and returns +/// any results. +/// +/// If you are using the library's Specialized SQL Structures feature, +/// Query has several special functions for generating common SQL +/// queries from those structures. For instance, it offers the +/// \link mysqlpp::Query::insert() insert() \endlink method, which +/// builds an INSERT query to add the contents of the SSQLS to the +/// database. As with the stream interface, these methods only build +/// the query string; call one of the parameterless methods mentioned +/// previously to actually execute the query. +/// +/// Finally, you can build "template queries". This is something like +/// C's \c printf() function, in that you insert a specially-formatted +/// query string into the object which contains placeholders for data. +/// You call the parse() method to tell the Query object that the query +/// string contains placeholders. Once that's done, you can call any of +/// the many overloaded methods that take a number of SQLStrings (up to +/// 25 by default) or any type that can be converted to SQLString, and +/// those parameters will be inserted into the placeholders. When you +/// call one of the parameterless functions the execute the query, the +/// final query string is assembled and sent to the server. +/// +/// See the user manual for more details about these options. + +class MYSQLPP_EXPORT Query : public std::ostream, + public OptionalExceptions, public Lockable +{ +public: + /// \brief Create a new query object attached to a connection. + /// + /// This is the constructor used by mysqlpp::Connection::query(). + /// + /// \param c connection the finished query should be sent out on + /// \param te if true, throw exceptions on errors + Query(Connection* c, bool te = true); + + /// \brief Create a new query object as a copy of another. + /// + /// This is \b not a traditional copy ctor! Its only purpose is to + /// make it possible to assign the return of Connection::query() + /// to an empty Query object. In particular, the stream buffer and + /// template query stuff will be empty in the copy, regardless of + /// what values they have in the original. + Query(const Query& q); + + /// \brief Assign another query's state to this object + /// + /// The same caveats apply to this operator as apply to the copy + /// ctor. + Query& operator=(const Query& rhs); + + /// \brief Get the last error message that was set. + /// + /// This class has an internal error message string, but if it + /// isn't set, we return the last error message that happened + /// on the connection we're bound to instead. + std::string error(); + + /// \brief Returns true if the last operation succeeded + /// + /// Returns true if the last query succeeded, and the associated + /// Connection object's success() method also returns true. If + /// either object is unhappy, this method returns false. + bool success(); + + /// \brief Treat the contents of the query string as a template + /// query. + /// + /// This method sets up the internal structures used by all of the + /// other members that accept template query parameters. See the + /// "Template Queries" chapter in the user manual for more + /// information. + void parse(); + + /// \brief Reset the query object so that it can be reused. + /// + /// This erases the query string and the contents of the parameterized + /// query element list. + void reset(); + + /// \brief Return the query string currently in the buffer. + std::string preview() { return str(def); } + + /// \brief Return the query string currently in the buffer with + /// template query parameter substitution. + /// + /// \param arg0 the value to substitute for the first template query + /// parameter + std::string preview(const SQLString& arg0) + { return preview(SQLQueryParms() << arg0); } + + /// \brief Return the query string currently in the buffer. + std::string preview(SQLQueryParms& p) { return str(p); } + + /// \brief Get built query as a null-terminated C++ string + std::string str() { return str(def); } + + /// \brief Get built query as a null-terminated C++ string with + /// template query parameter substitution. + /// + /// \param arg0 the value to substitute for the first template query + /// parameter + std::string str(const SQLString& arg0) + { return preview(SQLQueryParms() << arg0); } + + /// \brief Get built query as a null-terminated C++ string + /// + /// \param r if equal to \c RESET_QUERY, query object is cleared + /// after this call + std::string str(query_reset r) { return str(def, r); } + + /// \brief Get built query as a null-terminated C++ string + /// + /// \param p template query parameters to use, overriding the ones + /// this object holds, if any + std::string str(SQLQueryParms& p); + + /// \brief Get built query as a null-terminated C++ string + /// + /// \param p template query parameters to use, overriding the ones + /// this object holds, if any + /// \param r if equal to \c RESET_QUERY, query object is cleared + /// after this call + std::string str(SQLQueryParms& p, query_reset r); + + /// \brief Execute a query + /// + /// Same as execute(), except that it only returns a flag indicating + /// whether the query succeeded or not. It is basically a thin + /// wrapper around the C API function \c mysql_real_query(). + /// + /// \param str the query to execute + /// + /// \return true if query was executed successfully + /// + /// \sa execute(), store(), storein(), and use() + bool exec(const std::string& str); + + /// \brief Execute built-up query + /// + /// Use one of the execute() overloads if you don't expect the + /// server to return a result set. For instance, a DELETE query. + /// The returned ResNSel object contains status information from + /// the server, such as whether the query succeeded, and if so how + /// many rows were affected. + /// + /// This overloaded version of execute() simply executes the query + /// that you have built up in the object in some way. (For instance, + /// via the insert() method, or by using the object's stream + /// interface.) + /// + /// \return ResNSel status information about the query + /// + /// \sa exec(), store(), storein(), and use() + ResNSel execute() { return execute(def); } + + /// \brief Execute query in a C++ string, or substitute string into + /// a template query and execute it. + /// + /// \param str If the object represents a compiled template query, + /// substitutes this string in for the first parameter. Otherwise, + /// takes the string as a complete SQL query and executes it. + ResNSel execute(const SQLString& str); + + /// \brief Execute query in a C string + /// + /// Executes the query immediately, and returns the results. + ResNSel execute(const char* str); + + /// \brief Execute query in a known-length string of characters. + /// This can include null characters. + /// + /// Executes the query immediately, and returns the results. + ResNSel execute(const char* str, size_t len); + + /// \brief Execute a query that can return a result set + /// + /// Use one of the use() overloads if memory efficiency is + /// important. They return an object that can walk through + /// the result records one by one, without fetching the entire + /// result set from the server. This is superior to store() + /// when there are a large number of results; store() would have to + /// allocate a large block of memory to hold all those records, + /// which could cause problems. + /// + /// A potential downside of this method is that MySQL database + /// resources are tied up until the result set is completely + /// consumed. Do your best to walk through the result set as + /// expeditiously as possible. + /// + /// The name of this method comes from the MySQL C API function + /// that initiates the retrieval process, \c mysql_use_result(). + /// This method is implemented in terms of that function. + /// + /// This function has the same set of overloads as execute(). + /// + /// \return ResUse object that can walk through result set serially + /// + /// \sa exec(), execute(), store() and storein() + ResUse use() { return use(def); } + + /// \brief Execute query in a C++ string + /// + /// Executes the query immediately, and returns an object that + /// lets you walk through the result set one row at a time, in + /// sequence. This is more memory-efficient than store(). + ResUse use(const SQLString& str); + + /// \brief Execute query in a C string + /// + /// Executes the query immediately, and returns an object that + /// lets you walk through the result set one row at a time, in + /// sequence. This is more memory-efficient than store(). + ResUse use(const char* str); + + /// \brief Execute query in a known-length C string + /// + /// Executes the query immediately, and returns an object that + /// lets you walk through the result set one row at a time, in + /// sequence. This is more memory-efficient than store(). + ResUse use(const char* str, size_t len); + + /// \brief Execute a query that can return a result set + /// + /// Use one of the store() overloads to execute a query and retrieve + /// the entire result set into memory. This is useful if you + /// actually need all of the records at once, but if not, consider + /// using one of the use() methods instead, which returns the results + /// one at a time, so they don't allocate as much memory as store(). + /// + /// You must use store(), storein() or use() for \c SELECT, \c SHOW, + /// \c DESCRIBE and \c EXPLAIN queries. You can use these functions + /// with other query types, but since they don't return a result + /// set, exec() and execute() are more efficient. + /// + /// The name of this method comes from the MySQL C API function it + /// is implemented in terms of, \c mysql_store_result(). + /// + /// This function has the same set of overloads as execute(). + /// + /// \return Result object containing entire result set + /// + /// \sa exec(), execute(), storein(), and use() + Result store() { return store(def); } + + /// \brief Execute query in a C++ string + /// + /// Executes the query immediately, and returns an object that + /// contains the entire result set. This is less memory-efficient + /// than use(), but it lets you have random access to the results. + Result store(const SQLString& str); + + /// \brief Execute query in a C string + /// + /// Executes the query immediately, and returns an object that + /// contains the entire result set. This is less memory-efficient + /// than use(), but it lets you have random access to the results. + Result store(const char* str); + + /// \brief Execute query in a known-length C string + /// + /// Executes the query immediately, and returns an object that + /// contains the entire result set. This is less memory-efficient + /// than use(), but it lets you have random access to the results. + Result store(const char* str, size_t len); + + /// \brief Execute a query, and call a functor for each returned row + /// + /// This method wraps a use() query, calling the given functor for + /// every returned row. It is analogous to STL's for_each() + /// algorithm, but instead of iterating over some range within a + /// container, it iterates over a result set produced by a query. + /// + /// \param query the query string + /// \param fn the functor called for each row + /// \return a copy of the passed functor + template + Function for_each(const SQLString& query, Function fn) + { + mysqlpp::ResUse res = use(query); + if (res) { + mysqlpp::NoExceptions ne(res); + while (mysqlpp::Row row = res.fetch_row()) { + fn(row); + } + } + + return fn; + } + + /// \brief Execute the query, and call a functor for each returned row + /// + /// Just like for_each(const SQLString&, Function), but it uses + /// the query string held by the Query object already + /// + /// \param fn the functor called for each row + /// \return a copy of the passed functor + template + Function for_each(Function fn) + { + mysqlpp::ResUse res = use(); + if (res) { + mysqlpp::NoExceptions ne(res); + while (mysqlpp::Row row = res.fetch_row()) { + fn(row); + } + } + + return fn; + } + + /// \brief Run a functor for every row in a table + /// + /// Just like for_each(Function), except that it builds a + /// "select * from TABLE" query using the SQL table name from + /// the SSQLS instance you pass. + /// + /// \param ssqls the SSQLS instance to get a table name from + /// \param fn the functor called for each row + /// + /// \return a copy of the passed functor + template + Function for_each(const SSQLS& ssqls, Function fn) + { + SQLString query("select * from "); + query += ssqls._table; + mysqlpp::ResUse res = use(query); + if (res) { + mysqlpp::NoExceptions ne(res); + while (mysqlpp::Row row = res.fetch_row()) { + fn(row); + } + } + + return fn; + } + + /// \brief Execute a query, conditionally storing each row in a + /// container + /// + /// This method wraps a use() query, calling the given functor for + /// every returned row, and storing the results in the given + /// sequence container if the functor returns true. + /// + /// This is analogous to the STL copy_if() algorithm, except that + /// the source rows come from a database query instead of another + /// container. (copy_if() isn't a standard STL algorithm, but only + /// due to an oversight by the standardization committee.) This + /// fact may help you to remember the order of the parameters: the + /// container is the destination, the query is the source, and the + /// functor is the predicate; it's just like an STL algorithm. + /// + /// \param seq the destination container; needs a push_back() method + /// \param query the query string + /// \param fn the functor called for each row + /// \return a copy of the passed functor + template + Function store_if(Sequence& seq, const SQLString& query, Function fn) + { + mysqlpp::ResUse res = use(query); + if (res) { + mysqlpp::NoExceptions ne(res); + while (mysqlpp::Row row = res.fetch_row()) { + if (fn(row)) { + seq.push_back(row); + } + } + } + + return fn; + } + + /// \brief Pulls every row in a table, conditionally storing each + /// one in a container + /// + /// Just like store_if(Sequence&, const SQLString&, Function), but + /// it uses the SSQLS instance to construct a "select * from TABLE" + /// query, using the table name field in the SSQLS. + /// + /// \param seq the destination container; needs a push_back() method + /// \param ssqls the SSQLS instance to get a table name from + /// \param fn the functor called for each row + /// \return a copy of the passed functor + template + Function store_if(Sequence& seq, const SSQLS& ssqls, Function fn) + { + SQLString query("select * from "); + query += ssqls._table; + mysqlpp::ResUse res = use(query); + if (res) { + mysqlpp::NoExceptions ne(res); + while (mysqlpp::Row row = res.fetch_row()) { + if (fn(row)) { + seq.push_back(row); + } + } + } + + return fn; + } + + /// \brief Execute the query, conditionally storing each row in a + /// container + /// + /// Just like store_if(Sequence&, const SQLString&, Function), but + /// it uses the query string held by the Query object already + /// + /// \param seq the destination container; needs a push_back() method + /// \param fn the functor called for each row + /// \return a copy of the passed functor + template + Function store_if(Sequence& seq, Function fn) + { + mysqlpp::ResUse res = use(); + if (res) { + mysqlpp::NoExceptions ne(res); + while (mysqlpp::Row row = res.fetch_row()) { + if (fn(row)) { + seq.push_back(row); + } + } + } + + return fn; + } + + /// \brief Return next result set, when processing a multi-query + /// + /// There are two cases where you'd use this function instead of + /// the regular store() functions. + /// + /// First, when handling the result of executing multiple queries + /// at once. (See this + /// page in the MySQL documentation for details.) + /// + /// Second, when calling a stored procedure, MySQL can return the + /// result as a set of results. + /// + /// In either case, you must consume all results before making + /// another MySQL query, even if you don't care about the remaining + /// results or result sets. + /// + /// As the MySQL documentation points out, you must set the + /// MYSQL_OPTION_MULTI_STATEMENTS_ON flag on the connection in order + /// to use this feature. See Connection::set_option(). + /// + /// Multi-queries only exist in MySQL v4.1 and higher. Therefore, + /// this function just wraps store() when built against older API + /// libraries. + /// + /// \return Result object containing the next result set. + Result store_next(); + + /// \brief Return whether more results are waiting for a multi-query + /// or stored procedure response. + /// + /// If this function returns true, you must call store_next() to + /// fetch the next result set before you can execute more queries. + /// + /// Wraps mysql_more_results() in the MySQL C API. That function + /// only exists in MySQL v4.1 and higher. Therefore, this function + /// always returns false when built against older API libraries. + /// + /// \return true if another result set exists + bool more_results(); + + /// \brief Execute a query, storing the result set in an STL + /// sequence container. + /// + /// This function works much like store() from the caller's + /// perspective, because it returns the entire result set at once. + /// It's actually implemented in terms of use(), however, so that + /// memory for the result set doesn't need to be allocated twice. + /// + /// There are many overloads for this function, pretty much the same + /// as for execute(), except that there is a Container parameter at + /// the front of the list. So, you can pass a container and a query + /// string, or a container and template query parameters. + /// + /// \param con any STL sequence container, such as \c std::vector + /// \param r whether the query automatically resets after being used + /// + /// \sa exec(), execute(), store(), and use() + template + void storein_sequence(Sequence& con, query_reset r = RESET_QUERY) + { + storein_sequence(con, def, r); + } + + /// \brief Execute a query, storing the result set in an STL + /// associative container. + /// + /// The same thing as storein_sequence(), except that it's used with + /// associative STL containers, such as \c std::set. Other than + /// that detail, that method's comments apply equally well to this + /// one. + template + void storein_set(Set& con, query_reset r = RESET_QUERY) + { + storein_set(con, def, r); + } + + /// \brief Execute a query, and store the entire result set + /// in an STL container. + /// + /// This is a set of specialized template functions that call either + /// storein_sequence() or storein_set(), depending on the type of + /// container you pass it. It understands \c std::vector, \c deque, + /// \c list, \c slist (a common C++ library extension), \c set, + /// and \c multiset. + /// + /// Like the functions it wraps, this is actually an overloaded set + /// of functions. See the other functions' documentation for details. + /// + /// Use this function if you think you might someday switch your + /// program from using a set-associative container to a sequence + /// container for storing result sets, or vice versa. + /// + /// See exec(), execute(), store(), and use() for alternative + /// query execution mechanisms. + template + void storein(Container& con, query_reset r = RESET_QUERY) + { + storein(con, def, r); + } + + /// \brief Specialization of storein_sequence() for \c std::vector + template + void storein(std::vector& con, const char* s) + { + storein_sequence(con, s); + } + + /// \brief Specialization of storein_sequence() for \c std::deque + template + void storein(std::deque& con, const char* s) + { + storein_sequence(con, s); + } + + /// \brief Specialization of storein_sequence() for \c std::list + template + void storein(std::list& con, const char* s) + { + storein_sequence(con, s); + } + +#if defined(HAVE_EXT_SLIST) + /// \brief Specialization of storein_sequence() for g++ STL + /// extension \c slist + template + void storein(__gnu_cxx::slist& con, const char* s) + { + storein_sequence(con, s); + } +#elif defined(HAVE_GLOBAL_SLIST) + /// \brief Specialization of storein_sequence() for STL + /// extension \c slist + /// + /// This is primarily for older versions of g++, which put \c slist + /// in the global namespace. This is a common language extension, + /// so this may also work for other compilers. + template + void storein(slist& con, const char* s) + { + storein_sequence(con, s); + } +#elif defined(HAVE_STD_SLIST) + /// \brief Specialization of storein_sequence() for STL + /// extension \c slist + /// + /// This is for those benighted compilers that include an \c slist + /// implementation, but erroneously put it in the \c std namespace! + template + void storein(std::slist& con, const char* s) + { + storein_sequence(con, s); + } +#endif + + /// \brief Specialization of storein_set() for \c std::set + template + void storein(std::set& con, const char* s) + { + storein_set(con, s); + } + + /// \brief Specialization of storein_set() for \c std::multiset + template + void storein(std::multiset& con, const char* s) + { + storein_set(con, s); + } + + /// \brief Replace an existing row's data with new data. + /// + /// This function builds an UPDATE SQL query using the new row data + /// for the SET clause, and the old row data for the WHERE clause. + /// One uses it with MySQL++'s Specialized SQL Structures mechanism. + /// + /// \param o old row + /// \param n new row + /// + /// \sa insert(), replace() + template + Query& update(const T& o, const T& n) + { + reset(); + + // Cast required for VC++ 2003 due to error in overloaded operator + // lookup logic. For an explanation of the problem, see: + // http://groups-beta.google.com/group/microsoft.public.vc.stl/browse_thread/thread/9a68d84644e64f15 + MYSQLPP_QUERY_THISPTR << std::setprecision(16) << + "UPDATE " << o.table() << " SET " << n.equal_list() << + " WHERE " << o.equal_list(" AND ", sql_use_compare); + return *this; + } + + /// \brief Insert a new row. + /// + /// This function builds an INSERT SQL query. One uses it with + /// MySQL++'s Specialized SQL Structures mechanism. + /// + /// \param v new row + /// + /// \sa replace(), update() + template + Query& insert(const T& v) + { + reset(); + + MYSQLPP_QUERY_THISPTR << std::setprecision(16) << + "INSERT INTO " << v.table() << " (" << + v.field_list() << ") VALUES (" << + v.value_list() << ')'; + return *this; + } + + /// \brief Insert multiple new rows. + /// + /// Builds an INSERT SQL query using items from a range within an + /// STL container. Insert the entire contents of the container by + /// using the begin() and end() iterators of the container as + /// parameters to this function. + /// + /// \param first iterator pointing to first element in range to + /// insert + /// \param last iterator pointing to one past the last element to + /// insert + /// + /// \sa replace(), update() + template + Query& insert(Iter first, Iter last) + { + reset(); + if (first == last) { + return *this; // empty set! + } + + MYSQLPP_QUERY_THISPTR << std::setprecision(16) << + "INSERT INTO " << first->table() << " (" << + first->field_list() << ") VALUES (" << + first->value_list() << ')'; + + Iter it = first + 1; + while (it != last) { + MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')'; + ++it; + } + + return *this; + } + + /// \brief Insert new row unless there is an existing row that + /// matches on a unique index, in which case we replace it. + /// + /// This function builds a REPLACE SQL query. One uses it with + /// MySQL++'s Specialized SQL Structures mechanism. + /// + /// \param v new row + /// + /// \sa insert(), update() + template + Query& replace(const T& v) + { + reset(); + + MYSQLPP_QUERY_THISPTR << std::setprecision(16) << + "REPLACE INTO " << v.table() << " (" << + v.field_list() << ") VALUES (" << v.value_list() << ')'; + return *this; + } + + /// \brief Return true if the last query was successful + operator bool() { return success(); } + + /// \brief Return true if the last query failed + bool operator !() { return !success(); } + +#if !defined(DOXYGEN_IGNORE) + // Declare the remaining overloads. These are hidden down here partly + // to keep the above code clear, but also so that we may hide them + // from Doxygen, which gets confused by macro instantiations that look + // like method declarations. + mysql_query_define0(std::string, preview) + mysql_query_define0(std::string, str) + mysql_query_define1(ResNSel, execute) + mysql_query_define1(Result, store) + mysql_query_define1(ResUse, use) + mysql_query_define2(storein_sequence) + mysql_query_define2(storein_set) + mysql_query_define2(storein) +#endif // !defined(DOXYGEN_IGNORE) + + /// \brief The default template parameters + /// + /// Used for filling in parameterized queries. + SQLQueryParms def; + +private: + friend class SQLQueryParms; + + /// \brief Connection to send queries through + Connection* conn_; + + /// \brief If true, last query succeeded + bool success_; + + /// \brief List of template query parameters + std::vector parse_elems_; + + /// \brief Maps template parameter position values to the + /// corresponding parameter name. + std::vector parsed_names_; + + /// \brief Maps template parameter names to their position value. + std::map parsed_nums_; + + /// \brief String buffer for storing assembled query + std::stringbuf sbuffer_; + + //// Internal support functions + my_ulonglong affected_rows() const; + my_ulonglong insert_id(); + std::string info(); + char* preview_char(); + + /// \brief Process a parameterized query list. + void proc(SQLQueryParms& p); + + // Locking mechanism + bool lock(); + void unlock(); + + SQLString* pprepare(char option, SQLString& S, bool replace = true); +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +template +void Query::storein_sequence(Seq& seq, SQLQueryParms& p, query_reset r) +{ + r = parse_elems_.size() ? DONT_RESET : RESET_QUERY; + storein_sequence(seq, str(p, r).c_str()); +} + + +template +void Query::storein_sequence(Sequence& con, const char* s) +{ + ResUse result = use(s); + while (1) { + MYSQL_ROW d = mysql_fetch_row(result.raw_result()); + if (!d) + break; + Row row(d, &result, mysql_fetch_lengths(result.raw_result()), + true); + if (!row) + break; + con.push_back(typename Sequence::value_type(row)); + } +} + + +template +void Query::storein_set(Set& sett, SQLQueryParms& p, query_reset r) +{ + r = parse_elems_.size() ? DONT_RESET : RESET_QUERY; + storein_set(sett, str(p, r).c_str()); +} + + +template +void Query::storein_set(Set& con, const char* s) +{ + ResUse result = use(s); + while (1) { + MYSQL_ROW d = mysql_fetch_row(result.raw_result()); + if (!d) + return; + Row row(d, &result, mysql_fetch_lengths(result.raw_result()), + true); + if (!row) + break; + con.insert(typename Set::value_type(row)); + } +} + + +template +void Query::storein(T& con, SQLQueryParms& p, query_reset r) +{ + r = parse_elems_.size() ? DONT_RESET : RESET_QUERY; + storein(con, str(p, r).c_str()); +} + + +#endif // !defined(DOXYGEN_IGNORE) + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/querydef.h b/code/meosdb/mysql++/querydef.h new file mode 100644 index 0000000..b0a8ae9 --- /dev/null +++ b/code/meosdb/mysql++/querydef.h @@ -0,0 +1,118 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// This file is generated by the Perl script querydef.pl. Please do +// not modify this file directly. Change the script instead. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef MYSQLPP_QUERYDEF_H +#define MYSQLPP_QUERYDEF_H + +#define mysql_query_define0(RETURN, FUNC) \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1) \ + { return FUNC(SQLQueryParms() << arg0 << arg1); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21, const SQLString& arg22) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21 << arg22); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21, const SQLString& arg22, const SQLString& arg23) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21 << arg22 << arg23); } \ + RETURN FUNC(const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21, const SQLString& arg22, const SQLString& arg23, const SQLString& arg24) \ + { return FUNC(SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21 << arg22 << arg23 << arg24); } \ + +#define mysql_query_define1(RETURN, FUNC) \ + RETURN FUNC(SQLQueryParms& p); \ + mysql_query_define0(RETURN, FUNC) + +#define mysql_query_define2(FUNC) \ + template void FUNC(T& container, const char* str); \ + template void FUNC(T& container, SQLQueryParms& p, \ + query_reset r = RESET_QUERY); \ + template void FUNC(T& container, const SQLString& arg0) \ + { FUNC(container, SQLQueryParms() << arg0); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21, const SQLString& arg22) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21 << arg22); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21, const SQLString& arg22, const SQLString& arg23) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21 << arg22 << arg23); } \ + template void FUNC(T& container, const SQLString& arg0, const SQLString& arg1, const SQLString& arg2, const SQLString& arg3, const SQLString& arg4, const SQLString& arg5, const SQLString& arg6, const SQLString& arg7, const SQLString& arg8, const SQLString& arg9, const SQLString& arg10, const SQLString& arg11, const SQLString& arg12, const SQLString& arg13, const SQLString& arg14, const SQLString& arg15, const SQLString& arg16, const SQLString& arg17, const SQLString& arg18, const SQLString& arg19, const SQLString& arg20, const SQLString& arg21, const SQLString& arg22, const SQLString& arg23, const SQLString& arg24) \ + { FUNC(container, SQLQueryParms() << arg0 << arg1 << arg2 << arg3 << arg4 << arg5 << arg6 << arg7 << arg8 << arg9 << arg10 << arg11 << arg12 << arg13 << arg14 << arg15 << arg16 << arg17 << arg18 << arg19 << arg20 << arg21 << arg22 << arg23 << arg24); } \ + +#endif // !defined(MYSQLPP_QUERYDEF_H) diff --git a/code/meosdb/mysql++/querydef.pl b/code/meosdb/mysql++/querydef.pl new file mode 100644 index 0000000..4bbfeae --- /dev/null +++ b/code/meosdb/mysql++/querydef.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl -w + +######################################################################## +# querydef.pl - Generates querydef.h, which defines a number of macros +# used in query.h that differ only in the number of arguments. That +# number limits the number of parameters a MySQL++ template query can +# accept. This value can be changed from its default, below. +# +# Copyright (c) 2006-2007 by Educational Technology Resources, Inc. +# Others may also hold copyrights on code in this file. See the CREDITS +# file in the top directory of the distribution for details. +# +# This file is part of MySQL++. +# +# MySQL++ 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 of the License, or +# (at your option) any later version. +# +# MySQL++ 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 MySQL++; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA +######################################################################## + + +# The number of parameters a template query can accept. Make this value +# larger only at need, as it adds code to the library proportionally. +# You should not reduce this value if programs you did not write may +# link to the library, as that would constitute an ABI breakage. +my $max_parameters = 25; + + +# No user-serviceable parts below. + +use strict; + +open (OUT, ">querydef.h"); + +print OUT << "---"; +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// This file is generated by the Perl script querydef.pl. Please do +// not modify this file directly. Change the script instead. +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef MYSQLPP_QUERYDEF_H +#define MYSQLPP_QUERYDEF_H + +--- + +## Build mysql_query_define0 macro +print OUT "#define mysql_query_define0(RETURN, FUNC) \\\n"; +for (my $i = 1; $i < $max_parameters; ++$i) { + print OUT "\tRETURN FUNC("; + for (my $j = 0; $j < $i + 1; ++$j) { + print OUT 'const SQLString& arg', $j; + print OUT ', ' unless $j == $i; + } + print OUT ") \\\n"; + + print OUT "\t\t{ return FUNC(SQLQueryParms()"; + for (my $j = 0; $j < $i + 1; ++$j) { + print OUT ' << arg', $j; + } + print OUT "); } \\\n"; +} + +## Add mysql_query_define1 macro +print OUT << "---"; + +#define mysql_query_define1(RETURN, FUNC) \\ + RETURN FUNC(SQLQueryParms& p); \\ + mysql_query_define0(RETURN, FUNC) +--- + +## Add mysql_query_define2 macro +print OUT << "---"; + +#define mysql_query_define2(FUNC) \\ + template void FUNC(T& container, const char* str); \\ + template void FUNC(T& container, SQLQueryParms& p, \\ + query_reset r = RESET_QUERY); \\ +--- +for (my $i = 0; $i < $max_parameters; ++$i) { + print OUT "\ttemplate void FUNC(T& container"; + for (my $j = 0; $j < $i + 1; ++$j) { + print OUT ', const SQLString& arg', $j; + } + print OUT ") \\\n"; + print OUT "\t\t{ FUNC(container, SQLQueryParms()"; + for (my $j = 0; $j < $i + 1; ++$j) { + print OUT ' << arg', $j; + } + print OUT "); } \\\n"; +} + +## That's all, folks! +print OUT "\n#endif // !defined(MYSQLPP_QUERYDEF_H)\n"; + diff --git a/code/meosdb/mysql++/resiter.h b/code/meosdb/mysql++/resiter.h new file mode 100644 index 0000000..fdaa582 --- /dev/null +++ b/code/meosdb/mysql++/resiter.h @@ -0,0 +1,278 @@ +/// \file resiter.h +/// \brief Declares templates for adapting existing classes to +/// be iteratable random-access containers. +/// +/// The file name seems to tie it to the mysqlpp::Result class, which +/// is so adapted, but these templates are also used to adapt the +/// mysqlpp::Fields and mysqlpp::Row classes. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_RESITER_H +#define MYSQLPP_RESITER_H + +#include "common.h" + +#include + +namespace mysqlpp { + +template class subscript_iterator; + +/// \brief A base class that one derives from to become a random +/// access container, which can be accessed with subscript notation. +/// +/// OnType must have the member functions \c operator[](SizeType) and +// \c size() defined for it. + +template +class const_subscript_container +{ +public: + typedef const_subscript_container this_type; ///< this object's type + typedef subscript_iterator iterator; ///< mutable iterator type + typedef iterator const_iterator; ///< constant iterator type + typedef const std::reverse_iterator + reverse_iterator; ///< mutable reverse iterator type + typedef const std::reverse_iterator + const_reverse_iterator; ///< const reverse iterator type + + typedef ValueType value_type; ///< type of data stored in container + typedef value_type& reference; ///< reference to value_type + typedef value_type& const_reference;///< const ref to value_type + typedef value_type* pointer; ///< pointer to value_type + typedef value_type* const_pointer; ///< const pointer to value_type + + typedef DiffType difference_type; ///< for index differences + typedef SizeType size_type; ///< for returned sizes + + /// \brief Destroy object + virtual ~const_subscript_container() { } + + /// \brief Return count of elements in container + virtual size_type size() const = 0; + + /// \brief Return element at given index in container + virtual ReturnType at(SizeType i) const = 0; + + /// \brief Return maximum number of elements that can be stored + /// in container without resizing. + size_type max_size() const { return size(); } + + /// \brief Returns true if container is empty + bool empty() const { return size() == 0; } + + /// \brief Return iterator pointing to first element in the + /// container + iterator begin() const { return iterator(this, 0); } + + /// \brief Return iterator pointing to one past the last element + /// in the container + iterator end() const { return iterator(this, size()); } + + /// \brief Return reverse iterator pointing to first element in the + /// container + reverse_iterator rbegin() const { return reverse_iterator(end()); } + + /// \brief Return reverse iterator pointing to one past the last + /// element in the container + reverse_iterator rend() const { return reverse_iterator(begin()); } +}; + + +/// \brief Iterator that can be subscripted. +/// +/// This is the type of iterator used by the const_subscript_container +/// template. + +template +class subscript_iterator : public std::iterator +{ +public: + /// \brief Default constructor + subscript_iterator() { } + + /// \brief Create iterator given the container and a position + /// within it. + subscript_iterator(OnType* what, SizeType pos) + { + d_ = what; + i_ = pos; + } + + /// \brief Return true if given iterator points to the same + /// container and the same position within the container. + bool operator ==(const subscript_iterator& j) const + { + return (d_ == j.d_ && i_ == j.i_); + } + + /// \brief Return true if given iterator is different from this + /// one, but points to the same container. + bool operator !=(const subscript_iterator& j) const + { + return (d_ == j.d_ && i_ != j.i_); + } + + /// \brief Return true if the given iterator points to the same + /// container as this one, and that this iterator's position is + /// less than the given iterator's. + bool operator <(const subscript_iterator& j) const + { + return (d_ == j.d_ && i_ < j.i_); + } + + /// \brief Return true if the given iterator points to the same + /// container as this one, and that this iterator's position is + /// greater than the given iterator's. + bool operator >(const subscript_iterator & j) const + { + return (d_ == j.d_ && i_ > j.i_); + } + + /// \brief Return true if the given iterator points to the same + /// container as this one, and that this iterator's position is + /// less than or equal to the given iterator's. + bool operator <=(const subscript_iterator & j) const + { + return (d_ == j.d_ && i_ <= j.i_); + } + + /// \brief Return true if the given iterator points to the same + /// container as this one, and that this iterator's position is + /// greater than or equal to the given iterator's. + bool operator >=(const subscript_iterator & j) const + { + return (d_ == j.d_ && i_ >= j.i_); + } + + /// \brief Dereference the iterator, returning a copy of the + /// pointed-to element within the container. + ReturnType operator *() const { return d_->at(i_); } + + /// \brief Return a copy of the element at the given position + /// within the container. + ReturnType operator [](SizeType n) const { return d_->at(n); } + + /// \brief Move the iterator to the next element, returning an + /// iterator to that element + subscript_iterator& operator ++() { ++i_; return *this; } + + /// \brief Move the iterator to the next element, returning an + /// iterator to the element we were pointing at before the change + subscript_iterator operator ++(int) + { + subscript_iterator tmp = *this; + ++i_; + return tmp; + } + + /// \brief Move the iterator to the previous element, returning an + /// iterator to that element + subscript_iterator& operator --() + { + --i_; + return *this; + } + + /// \brief Move the iterator to the previous element, returning an + /// iterator to the element we were pointing at before the change + subscript_iterator operator --(int) + { + subscript_iterator tmp = *this; + --i_; + return tmp; + } + + /// \brief Advance iterator position by \c n + subscript_iterator& operator +=(SizeType n) + { + i_ += n; + return *this; + } + + /// \brief Return an iterator \c n positions beyond this one + subscript_iterator operator +(SizeType n) const + { + subscript_iterator tmp = *this; + tmp.i_ += n; + return tmp; + } + + /// \brief Move iterator position back by \c n + subscript_iterator& operator -=(SizeType n) + { + i_ -= n; + return *this; + } + + /// \brief Return an iterator \c n positions before this one + subscript_iterator operator -(SizeType n) const + { + subscript_iterator tmp = *this; + tmp.i_ -= n; + return tmp; + } + + /// \brief Return an iterator \c n positions before this one + DiffType operator -(const subscript_iterator& j) const + { + if (d_ == j.d_) { + return static_cast(i_) - j.i_; + } + return 0; + } + +private: + SizeType i_; + OnType* d_; +}; + + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +template +inline subscript_iterator +operator +(SizeType x, + const subscript_iterator & y) +{ + return y + x; +} + +#endif // !defined(DOXYGEN_IGNORE) + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/result.cpp b/code/meosdb/mysql++/result.cpp new file mode 100644 index 0000000..42bf0db --- /dev/null +++ b/code/meosdb/mysql++/result.cpp @@ -0,0 +1,239 @@ +/*********************************************************************** + result.cpp - Implements the Result, ResNSel, and ResUse classes. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "result.h" + +#include "connection.h" + +namespace mysqlpp { + +ResNSel::ResNSel(Connection* q) : +success(q->success()), +insert_id(q->insert_id()), +rows(q->affected_rows()), +info(q->info()) +{ +} + + +ResUse::ResUse(MYSQL_RES* result, Connection* c, bool te) : +OptionalExceptions(te), +conn_(c), +initialized_(false), +names_(0), +types_(0), +fields_(this) +{ + if (!result) { + result_ = 0; + types_ = 0; + names_ = 0; + return; + } + result_ = result; + names_ = new FieldNames(this); + if (names_) { + types_ = new FieldTypes(this); + } + table_ = fields(0).table; + initialized_ = true; +} + + +ResUse::~ResUse() +{ + purge(); +} + + +void +ResUse::copy(const ResUse& other) +{ + if (initialized_) { + purge(); + } + + set_exceptions(other.throw_exceptions()); + + if (!other.result_) { + result_ = 0; + types_ = 0; + names_ = 0; + initialized_ = other.initialized_; + return; + } + + result_ = other.result_; + fields_ = Fields(this); + + if (other.names_) { + names_ = new FieldNames(*other.names_); + } + else { + names_ = 0; + } + + if (other.types_) { + types_ = new FieldTypes(*other.types_); + } + else { + types_ = 0; + } + + table_ = other.table_; + + conn_ = other.conn_; + initialized_ = true; +} + + +int +ResUse::field_num(const std::string& i) const +{ + if (!names_) { + names_ = new FieldNames(this); + } + + size_t index = (*names_)[i]; + if ((index >= names_->size()) && throw_exceptions()) { + throw BadFieldName(i.c_str()); + } + + return int(index); +} + + +std::string& +ResUse::field_name(int i) +{ + if (!names_) { + names_ = new FieldNames(this); + } + return (*names_)[i]; +} + + +const std::string& +ResUse::field_name(int i) const +{ + if (!names_) { + names_ = new FieldNames(this); + } + return (*names_)[i]; +} + + +FieldNames& +ResUse::field_names() +{ + if (!names_) { + names_ = new FieldNames(this); + } + return *names_; +} + + +const FieldNames& +ResUse::field_names() const +{ + if (!names_) { + names_ = new FieldNames(this); + } + return *names_; +} + + +void +ResUse::reset_field_names() +{ + delete names_; + names_ = 0; + names_ = new FieldNames(this); +} + + +mysql_type_info& +ResUse::field_type(int i) +{ + if (!types_) { + types_ = new FieldTypes(this); + } + return (*types_)[i]; +} + + +const mysql_type_info& +ResUse::field_type(int i) const +{ + if (!types_) { + types_ = new FieldTypes(this); + } + return (*types_)[i]; +} + + +FieldTypes& +ResUse::field_types() +{ + if (!types_) { + types_ = new FieldTypes(this); + } + return *types_; +} + + +const FieldTypes& +ResUse::field_types() const +{ + if (!types_) { + types_ = new FieldTypes(this); + } + return *types_; +} + + +void +ResUse::reset_field_types() +{ + delete types_; + types_ = 0; + types_ = new FieldTypes(this); +} + + +ResUse& +ResUse::operator =(const ResUse& other) +{ + if (this == &other) { + return *this; + } + copy(other); + other.result_ = 0; + return *this; +} + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/result.h b/code/meosdb/mysql++/result.h new file mode 100644 index 0000000..99f2aa2 --- /dev/null +++ b/code/meosdb/mysql++/result.h @@ -0,0 +1,472 @@ +/// \file result.h +/// \brief Declares classes for holding SQL query result sets. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_RESULT_H +#define MYSQLPP_RESULT_H + +#include "common.h" + +#include "exceptions.h" +#include "fields.h" +#include "field_names.h" +#include "field_types.h" +#include "noexceptions.h" +#include "resiter.h" +#include "row.h" + +#include +#include +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Connection; +#endif + +/// \brief A basic result set class, for use with "use" queries. +/// +/// A "use" query is one where you make the query and then process just +/// one row at a time in the result instead of dealing with them all as +/// a single large chunk. (The name comes from the MySQL C API function +/// that initiates this action, \c mysql_use_result().) By calling +/// fetch_row() until it throws a mysqlpp::BadQuery exception (or an +/// empty row if exceptions are disabled), you can process the result +/// set one row at a time. + +class MYSQLPP_EXPORT ResUse : public OptionalExceptions +{ +public: + /// \brief Default constructor + ResUse() : + OptionalExceptions(), + conn_(0), + result_(0), + initialized_(false), + names_(0), + types_(0), + fields_(this) + { + } + + /// \brief Create the object, fully initialized + ResUse(MYSQL_RES* result, Connection* c = 0, bool te = true); + + /// \brief Create a copy of another ResUse object + ResUse(const ResUse& other) : + OptionalExceptions(), + initialized_(false) + { + copy(other); + other.result_ = 0; + } + + /// \brief Destroy object + virtual ~ResUse(); + + /// \brief Copy another ResUse object's data into this object + ResUse& operator =(const ResUse& other); + + /// \brief Return raw MySQL C API result set + MYSQL_RES* raw_result() + { + return result_; + } + + /// \brief Wraps mysql_fetch_row() in MySQL C API. + /// + /// This is not a thin wrapper. It does a lot of error checking before + /// returning the mysqlpp::Row object containing the row data. + Row fetch_row() + { + if (!result_) { + if (throw_exceptions()) { + throw BadQuery("Results not fetched"); + } + else { + return Row(); + } + } + MYSQL_ROW row = mysql_fetch_row(result_); + unsigned long* length = mysql_fetch_lengths(result_); + if (!row || !length) { + if (throw_exceptions()) { + throw EndOfResults(); + } + else { + return Row(); + } + } + return Row(row, this, length, throw_exceptions()); + } + + /// \brief Wraps mysql_fetch_lengths() in MySQL C API. + unsigned long *fetch_lengths() const + { + return mysql_fetch_lengths(result_); + } + + /// \brief Wraps mysql_fetch_field() in MySQL C API. + Field& fetch_field() const + { + return *mysql_fetch_field(result_); + } + + /// \brief Wraps mysql_field_seek() in MySQL C API. + void field_seek(int field) + { + mysql_field_seek(result_, field); + } + + /// \brief Wraps mysql_num_fields() in MySQL C API. + int num_fields() const + { + return mysql_num_fields(result_); + } + + /// \brief Documentation needed! + void parent_leaving() + { + conn_ = 0; + } + + /// \brief Free all resources held by the object. + /// + /// This class's destructor is little more than a call to purge(), + /// so you can think of this as a way to re-use a ResUse object, + /// to avoid having to completely re-create it. + void purge() + { + if (result_) { + mysql_free_result(result_); + result_ = 0; + } + + delete names_; + names_ = 0; + + delete types_; + types_ = 0; + + table_.erase(); + } + + /// \brief Return true if we have a valid result set + /// + /// This operator is primarily used to determine if a query was + /// successful: + /// + /// \code + /// Query q("...."); + /// if (q.use()) { + /// ... + /// \endcode + /// + /// Query::use() returns a ResUse object, and it won't contain a + /// valid result set if the query failed. + operator bool() const + { + return result_; + } + + /// \brief Return the number of columns in the result set. + unsigned int columns() const + { + return num_fields(); + } + + /// \brief Get the name of table that the result set comes from. + std::string& table() + { + return table_; + } + + /// \brief Return the name of the table + /// + /// This is only valid + const std::string& table() const + { + return table_; + } + + /// \brief Get the index of the named field. + /// + /// This is the inverse of field_name(). + int field_num(const std::string&) const; + + /// \brief Get the name of the field at the given index. + /// + /// This is the inverse of field_num(). + std::string& field_name(int); + + /// \brief Get the name of the field at the given index. + const std::string& field_name(int) const; + + /// \brief Get the names of the fields within this result set. + FieldNames& field_names(); + + /// \brief Get the names of the fields within this result set. + const FieldNames& field_names() const; + + /// \brief Reset the names in the field list to their original + /// values. + void reset_field_names(); + + /// \brief Get the MySQL type for a field given its index. + mysql_type_info& field_type(int i); + + /// \brief Get the MySQL type for a field given its index. + const mysql_type_info& field_type(int) const; + + /// \brief Get a list of the types of the fields within this + /// result set. + FieldTypes& field_types(); + + /// \brief Get a list of the types of the fields within this + /// result set. + const FieldTypes& field_types() const; + + /// \brief Reset the field types to their original values. + void reset_field_types(); + + /// \brief Alias for field_num() + int names(const std::string & s) const { return field_num(s); } + + /// \brief Alias for field_name() + std::string& names(int i) { return field_name(i); } + + /// \brief Alias for field_name() + const std::string& names(int i) const { return field_name(i); } + + /// \brief Alias for field_names() + FieldNames& names() { return field_names(); } + + /// \brief Alias for field_names() + const FieldNames& names() const { return field_names(); } + + /// \brief Alias for reset_field_names() + void reset_names() { reset_field_names(); } + + /// \brief Alias for field_type() + mysql_type_info& types(int i) { return field_type(i); } + + /// \brief Alias for field_type() + const mysql_type_info& types(int i) const { return field_type(i); } + + /// \brief Alias for field_types() + FieldTypes& types() { return field_types(); } + + /// \brief Alias for field_types() + const FieldTypes& types() const { return field_types(); } + + /// \brief Alias for reset_field_types() + void reset_types() { reset_field_types(); } + + /// \brief Get the underlying Fields structure. + const Fields& fields() const { return fields_; } + + /// \brief Get the underlying Field structure given its index. + const Field& fields(unsigned int i) const { return fields_.at(i); } + + /// \brief Returns true if the other ResUse object shares the same + /// underlying C API result set as this one. + /// + /// This works because the underlying result set is stored as a + /// pointer, and thus can be copied and then compared. + bool operator ==(const ResUse& other) const + { + return result_ == other.result_; + } + + /// \brief Returns true if the other ResUse object has a different + /// underlying C API result set from this one. + bool operator !=(const ResUse& other) const + { + return result_ != other.result_; + } + +protected: + Connection* conn_; ///< server result set comes from + mutable MYSQL_RES* result_; ///< underlying C API result set + bool initialized_; ///< if true, object is fully initted + mutable FieldNames* names_; ///< list of field names in result + mutable FieldTypes* types_; ///< list of field types in result + Fields fields_; ///< list of fields in result + std::string table_; ///< table result set comes from + + /// \brief Copy another ResUse object's contents into this one. + /// + /// Self-copy is not allowed. + void copy(const ResUse& other); +}; + + +/// \brief This class manages SQL result sets. +/// +/// Objects of this class are created to manage the result of "store" +/// queries, where the result set is handed to the program as single +/// block of row data. (The name comes from the MySQL C API function +/// \c mysql_store_result() which creates these blocks of row data.) +/// +/// This class is a random access container (in the STL sense) which +/// is neither less-than comparable nor assignable. This container +/// provides a reverse random-access iterator in addition to the normal +/// forward one. + +class MYSQLPP_EXPORT Result : public ResUse, + public const_subscript_container +{ +public: + /// \brief Default constructor + Result() + { + } + + /// \brief Fully initialize object + Result(MYSQL_RES* result, bool te = true) : + ResUse(result, 0, te) + { + } + + /// \brief Initialize object as a copy of another Result object + Result(const Result& other) : + ResUse(other), + const_subscript_container() // no copying here + { + conn_ = 0; + } + + /// \brief Destroy result set + virtual ~Result() { } + + /// \brief Wraps mysql_fetch_row() in MySQL C API. + /// + /// This is simply the const version of the same function in our + /// \link mysqlpp::ResUse parent class \endlink . Why this cannot + /// actually \e be in our parent class is beyond me. + const Row fetch_row() const + { + if (!result_) { + if (throw_exceptions()) { + throw BadQuery("Results not fetched"); + } + else { + return Row(); + } + } + MYSQL_ROW row = mysql_fetch_row(result_); + unsigned long* length = mysql_fetch_lengths(result_); + if (!row || !length) { + if (throw_exceptions()) { + throw EndOfResults(); + } + else { + return Row(); + } + } + return Row(row, this, length, throw_exceptions()); + } + + /// \brief Wraps mysql_num_rows() in MySQL C API. + my_ulonglong num_rows() const + { + if (initialized_) + return mysql_num_rows(result_); + else + return 0; + } + + /// \brief Wraps mysql_data_seek() in MySQL C API. + void data_seek(uint offset) const + { + mysql_data_seek(result_, offset); + } + + /// \brief Alias for num_rows(), only with different return type. + size_type size() const + { + return size_type(num_rows()); + } + + /// \brief Alias for num_rows(), only with different return type. + size_type rows() const + { + return size_type(num_rows()); + } + + /// \brief Get the row with an offset of i. + const Row at(size_type i) const + { + data_seek(i); + return fetch_row(); + } +}; + + +/// \brief Swaps two ResUse objects +inline void swap(ResUse& x, ResUse& y) +{ + ResUse tmp = x; + x = y; + y = tmp; +} + +/// \brief Swaps two Result objects +inline void swap(Result& x, Result& y) +{ + Result tmp = x; + x = y; + y = tmp; +} + +/// \brief Holds the information on the success of queries that +/// don't return any results. +class MYSQLPP_EXPORT ResNSel +{ +public: + bool success; ///< if true, query was successful + my_ulonglong insert_id; ///< last value used for AUTO_INCREMENT field + my_ulonglong rows; ///< number of rows affected + std::string info; ///< additional info about query result + + ResNSel() : + success(false) + { + } + + /// \brief Initialize object + ResNSel(Connection* q); + + /// \brief Returns true if the query was successful + operator bool() { return success; } +}; + + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/row.cpp b/code/meosdb/mysql++/row.cpp new file mode 100644 index 0000000..3ab78ac --- /dev/null +++ b/code/meosdb/mysql++/row.cpp @@ -0,0 +1,186 @@ +/*********************************************************************** + row.cpp - Implements the Row class. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "row.h" +#include "result.h" +#include "exceptions.h" + +namespace mysqlpp { + +Row::Row(const MYSQL_ROW& d, const ResUse* r, + unsigned long* jj, bool te) : +OptionalExceptions(te), +res_(r), +initialized_(false) +{ + if (!d || !r) { + if (throw_exceptions()) { + throw BadQuery("ROW or RES is NULL"); + } + else { + return; + } + } + + data_.clear(); + is_nulls_.clear(); + initialized_ = true; + + for (size_type i = 0; i < size(); ++i) { + data_.insert(data_.end(), + (d[i] ? std::string(d[i], jj[i]) : std::string("NULL"))); + is_nulls_.insert(is_nulls_.end(), d[i] ? false : true); + } +} + + +Row::~Row() +{ + data_.clear(); + is_nulls_.clear(); + initialized_ = false; +} + + +Row::size_type Row::size() const +{ + return res_->num_fields(); +} + +const ColData Row::at(size_type i) const +{ + if (initialized_) { + const std::string& s = data_.at(i); + return ColData(s.data(), s.length(), res_->types(i), + is_nulls_[i]); + } + else { + if (throw_exceptions()) + throw std::out_of_range("Row not initialized"); + else + return ColData(); + } +} + +const ColData Row::operator [](const char* field) const +{ + size_type si = res_->field_num(std::string(field)); + if (si < size()) { + return at(si); + } + else { + throw BadFieldName(field); + } +} + + +value_list_ba +Row::field_list(const char* d) const +{ + return value_list_ba + (parent().names(), d, do_nothing); +} + +template +value_list_ba +Row::field_list(const char *d, Manip m) const +{ + return value_list_ba(parent().names(), d, m); +} + +template +value_list_b +Row::field_list(const char *d, Manip m, const std::vector& vb) const +{ + return value_list_b(parent().names(), vb, d, m); +} + +value_list_b +Row::field_list(const char* d, const std::vector& vb) const +{ + return value_list_b(parent().names(), + vb, d, quote); +} + +value_list_b +Row::field_list(const std::vector& vb) const +{ + return value_list_b(parent().names(), + vb, ",", quote); +} + +template value_list_b +Row::field_list(const char* d, Manip m, bool t0, bool t1, bool t2, + bool t3, bool t4, bool t5, bool t6, bool t7, bool t8, bool t9, + bool ta, bool tb, bool tc) const +{ + std::vector vb; + create_vector(parent().names().size(), vb, t0, t1, t2, t3, t4, + t5, t6, t7, t8, t9, ta, tb, tc); + return value_list_b(parent().names(), vb, d, m); +} + +value_list_b +Row::field_list(const char *d, bool t0, bool t1, bool t2, bool t3, + bool t4, bool t5, bool t6, bool t7, bool t8, bool t9, bool ta, + bool tb, bool tc) const +{ + std::vector vb; + create_vector(parent().names().size(), vb, t0, t1, t2, t3, t4, + t5, t6, t7, t8, t9, ta, tb, tc); + return value_list_b(parent().names(), + vb, d, quote); +} + +value_list_b +Row::field_list(bool t0, bool t1, bool t2, bool t3, bool t4, bool t5, + bool t6, bool t7, bool t8, bool t9, bool ta, bool tb, + bool tc) const +{ + std::vector vb; + create_vector(parent().names().size(), vb, t0, t1, t2, t3, t4, + t5, t6, t7, t8, t9, ta, tb, tc); + return value_list_b(parent().names(), + vb, ",", quote); +} + +equal_list_ba +Row::equal_list(const char* d, const char* e) const +{ + return equal_list_ba( + parent().names(), *this, d, e, quote); +} + +template +equal_list_ba +Row::equal_list(const char* d, const char* e, Manip m) const +{ + return equal_list_ba( + parent().names(), *this, d, e, m); +} + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/row.h b/code/meosdb/mysql++/row.h new file mode 100644 index 0000000..1e28655 --- /dev/null +++ b/code/meosdb/mysql++/row.h @@ -0,0 +1,479 @@ +/// \file row.h +/// \brief Declares the classes for holding row data from a result set. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_ROW_H +#define MYSQLPP_ROW_H + +#include "coldata.h" +#include "exceptions.h" +#include "noexceptions.h" +#include "resiter.h" +#include "vallist.h" + +#include +#include + +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class FieldNames; +class MYSQLPP_EXPORT ResUse; +#endif + +/// \brief Manages rows from a result set. +class MYSQLPP_EXPORT Row : + public const_subscript_container, + public OptionalExceptions +{ +public: + /// \brief Default constructor + Row() : + res_(0), + initialized_(false) + { + } + + /// \brief Create a row object + /// + /// \param d MySQL C API row data + /// \param r result set that the row comes from + /// \param jj length of each item in d + /// \param te if true, throw exceptions on errors + Row(const MYSQL_ROW& d, const ResUse* r, + unsigned long* jj, bool te = true); + + /// \brief Destroy object + ~Row(); + + /// \brief Get a reference to our parent class. + const ResUse& parent() const + { + return *res_; + } + + /// \brief Get the number of fields in the row. + size_type size() const; + + /// \brief Get the value of a field given its name. + /// + /// If the field does not exist in this row, we throw a BadFieldName + /// exception. + /// + /// For this operator to work, the Result or ResUse object that + /// created this object must still exist. In other words, you + /// cannot re-use or destroy the result object until you are done + /// retrieving data from this row object. + /// + /// Note that we return the + /// \link mysqlpp::ColData_Tmpl ColData \endlink object by value. + /// The purpose of ColData is to make it easy to convert the string + /// data returned by the MySQL server to some more appropriate type, + /// so you're almost certain to use this operator in a construct + /// like this: + /// + /// \code + /// string s = row["myfield"]; + /// \endcode + /// + /// That accesses myfield within the row, returns a temporary + /// ColData object, which is then automatically converted to a + /// \c std::string and copied into \c s. That works fine, but + /// beware of this similar but incorrect construct: + /// + /// \code + /// const char* pc = row["myfield"]; + /// \endcode + /// + /// This one line of code does what you expect, but \c pc is then a + /// dangling pointer: it points to memory owned by the temporary + /// ColData object, which will have been destroyed by the time you + /// get around to actually \e using the pointer. + /// + /// This function is rather inefficient. If that is a concern for + /// you, use at(), operator[](size_type) or the SSQLS mechanism' + /// instead. + const ColData operator [](const char* field) const; + + /// \brief Get the value of a field given its index. + /// + /// This function is just syntactic sugar, wrapping the at() method. + /// The at() method is the only way to get at the first field in a + /// result set by index, as \c row[0] is ambiguous: it could call + /// either \c operator[] overload. + /// + /// \sa at() for the full documentation for this operator, and + /// operator[](const char*) for further caveats about using this + /// operator. + const ColData operator [](size_type i) const + { + return at(i); + } + + /// \brief Get the value of a field given its index. + /// + /// If the index value is bad, the underlying std::vector is + /// supposed to throw an exception, according to the Standard. + /// + /// For this function to work, the Result or ResUse object that + /// created this object must still exist. In other words, you + /// cannot re-use or destroy the result object until you are done + /// retrieving data from this row object. + /// + /// See operator[](const char*) for more caveats. + const ColData at(size_type i) const; + + /// \brief Return the value of a field as a C string given its + /// index, in raw form. + /// + /// This is the same thing as operator[], except that the data isn't + /// converted to a ColData object first. Also, this method does not + /// check for out-of-bounds array indices. + const char* raw_data(int i) const + { + return data_[i].data(); + } + + /// \brief Return the size of a field's raw data given its index. + std::string::size_type raw_size(int i) const + { + return data_[i].length(); + } + + /// \brief Return the value of a field as a C++ string given its + /// index, in raw form. + /// + /// This is the same thing as operator[], except that the data isn't + /// converted to a ColData object first. + const std::string& raw_string(int i) const + { + return data_.at(i); + } + + /// \brief Returns true if there is data in the row. + operator bool() const + { + return data_.size(); + } + + /// \brief Get a list of the values in this row + /// + /// When inserted into a C++ stream, the delimiter 'd' will be used + /// between the items, and the quoting and escaping rules will be + /// set by the manipulator 'm' you choose. + /// + /// \param d delimiter to use between values + /// \param m manipulator to use when inserting values into a stream + template + value_list_ba value_list(const char* d = ",", + Manip m = quote) const + { + return value_list_ba(*this, d, m); + } + + /// \brief Get a list of the values in this row + /// + /// \param d delimiter to use between values + /// \param vb for each true item in this list, add that value to the + /// returned list; ignore the others + /// \param m manipulator to use when inserting values into a stream + template + value_list_b value_list(const char *d, + const std::vector& vb, Manip m = quote) const + { + return value_list_b(*this, vb, d, m); + } + + /// \brief Get a list of the values in this row + /// + /// \param vb for each true item in this list, add that value to the + /// returned list; ignore the others + /// + /// Items will be quoted and escaped when inserted into a C++ stream, + /// and a comma will be used as a delimiter between the items. + value_list_b value_list( + const std::vector &vb) const + { + return value_list_b(*this, vb, ",", quote); + } + + /// \brief Get a list of the values in this row + /// + /// For each true parameter, the value in that position within the + /// row is added to the returned list. When the list is inserted + /// into a C++ stream, the delimiter 'd' will be placed between the + /// items, and the manipulator 'm' used before each item. + template + value_list_b value_list(const char *d, Manip m, + bool t0, bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) const + { + std::vector vb; + create_vector(size(), vb, t0, t1, t2, t3, t4, t5, t6, + t7, t8, t9, ta, tb, tc); + return value_list_b(*this, vb, d, m); + } + + /// \brief Get a list of the values in this row + /// + /// For each true parameter, the value in that position within the + /// row is added to the returned list. When the list is inserted + /// into a C++ stream, the delimiter 'd' will be placed between the + /// items, and items will be quoted and escaped. + value_list_b + value_list(const char *d, bool t0, bool t1 = false, bool t2 = false, + bool t3 = false, bool t4 = false, bool t5 = false, + bool t6 = false, bool t7 = false, bool t8 = false, + bool t9 = false, bool ta = false, bool tb = false, + bool tc = false) const + { + std::vector vb; + create_vector(size(), vb, t0, t1, t2, t3, t4, t5, t6, + t7, t8, t9, ta, tb, tc); + return value_list_b(*this, vb, d, quote); + } + + /// \brief Get a list of the values in this row + /// + /// For each true parameter, the value in that position within the + /// row is added to the returned list. When the list is inserted + /// into a C++ stream, the a comma will be placed between the items, + /// as a delimiter, and items will be quoted and escaped. + value_list_b value_list(bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) const + { + std::vector vb; + create_vector(size(), vb, t0, t1, t2, t3, t4, t5, t6, + t7, t8, t9, ta, tb, tc); + return value_list_b(*this, vb, ",", quote); + } + + /// \brief Get a list of the values in this row + /// + /// The 's' parameters name the fields that will be added to the + /// returned list. When inserted into a C++ stream, the delimiter + /// 'd' will be placed between the items, and the manipulator 'm' + /// will be inserted before each item. + template + value_list_b value_list(const char *d, Manip m, + std::string s0, std::string s1 = "", std::string s2 = "", + std::string s3 = "", std::string s4 = "", + std::string s5 = "", std::string s6 = "", + std::string s7 = "", std::string s8 = "", + std::string s9 = "", std::string sa = "", + std::string sb = "", std::string sc = "") const + { + std::vector vb; + create_vector(*this, vb, s0, s1, s2, s3, s4, s5, s6, s7, s8, + s9, sa, sb, sc); + return value_list_b(*this, vb, d, m); + } + + /// \brief Get a list of the values in this row + /// + /// The 's' parameters name the fields that will be added to the + /// returned list. When inserted into a C++ stream, the delimiter + /// 'd' will be placed between the items, and items will be quoted + /// and escaped. + value_list_b value_list( + const char *d, + std::string s0, std::string s1 = "", std::string s2 = "", + std::string s3 = "", std::string s4 = "", + std::string s5 = "", std::string s6 = "", + std::string s7 = "", std::string s8 = "", + std::string s9 = "", std::string sa = "", + std::string sb = "", std::string sc = "") const + { + std::vector vb; + create_vector(*this, vb, s0, s1, s2, s3, s4, s5, s6, s7, s8, + s9, sa, sb, sc); + return value_list_b(*this, vb, d, quote); + } + + /// \brief Get a list of the values in this row + /// + /// The 's' parameters name the fields that will be added to the + /// returned list. When inserted into a C++ stream, a comma will be + /// placed between the items as a delimiter, and items will be + /// quoted and escaped. + value_list_b value_list( + std::string s0, + std::string s1 = "", std::string s2 = "", + std::string s3 = "", std::string s4 = "", + std::string s5 = "", std::string s6 = "", + std::string s7 = "", std::string s8 = "", + std::string s9 = "", std::string sa = "", + std::string sb = "", std::string sc = "") const + { + std::vector vb; + create_vector(*this, vb, s0, s1, s2, s3, s4, s5, s6, s7, s8, + s9, sa, sb, sc); + return value_list_b(*this, vb, ",", quote); + } + + /// \brief Get a list of the field names in this row + /// + /// When inserted into a C++ stream, the delimiter 'd' will be used + /// between the items, and no manipulator will be used on the items. + value_list_ba + field_list(const char* d = ",") const; + + /// \brief Get a list of the field names in this row + /// + /// \param d delimiter to place between the items when the list is + /// inserted into a C++ stream + /// \param m manipulator to use before each item when the list is + /// inserted into a C++ stream + template + value_list_ba field_list(const char* d, + Manip m) const; + + /// \brief Get a list of the field names in this row + /// + /// \param d delimiter to place between the items when the list is + /// inserted into a C++ stream + /// \param m manipulator to use before each item when the list is + /// inserted into a C++ stream + /// \param vb for each true item in this list, add that field name + /// to the returned list; ignore the others + template + value_list_b field_list(const char* d, Manip m, + const std::vector& vb) const; + + /// \brief Get a list of the field names in this row + /// + /// \param d delimiter to place between the items when the list is + /// inserted into a C++ stream + /// \param vb for each true item in this list, add that field name + /// to the returned list; ignore the others + /// + /// Field names will be quoted and escaped when inserted into a C++ + /// stream. + value_list_b field_list( + const char* d, const std::vector& vb) const; + + /// \brief Get a list of the field names in this row + /// + /// \param vb for each true item in this list, add that field name + /// to the returned list; ignore the others + /// + /// Field names will be quoted and escaped when inserted into a C++ + /// stream, and a comma will be placed between them as a delimiter. + value_list_b field_list( + const std::vector& vb) const; + + /// \brief Get a list of the field names in this row + /// + /// For each true parameter, the field name in that position within + /// the row is added to the returned list. When the list is + /// inserted into a C++ stream, the delimiter 'd' will be placed + /// between the items as a delimiter, and the manipulator 'm' used + /// before each item. + template + value_list_b field_list(const char *d, Manip m, + bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) const; + + /// \brief Get a list of the field names in this row + /// + /// For each true parameter, the field name in that position within + /// the row is added to the returned list. When the list is + /// inserted into a C++ stream, the delimiter 'd' will be placed + /// between the items as a delimiter, and the items will be quoted + /// and escaped. + value_list_b field_list( + const char *d, bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) const; + + /// \brief Get a list of the field names in this row + /// + /// For each true parameter, the field name in that position within + /// the row is added to the returned list. When the list is + /// inserted into a C++ stream, a comma will be placed between the + /// items as a delimiter, and the items will be quoted and escaped. + value_list_b field_list( + bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) const; + + /// \brief Get an "equal list" of the fields and values in this row + /// + /// When inserted into a C++ stream, the delimiter 'd' will be used + /// between the items, " = " is the relationship operator, and items + /// will be quoted and escaped. + equal_list_ba + equal_list(const char* d = ",", const char* e = " = ") const; + + /// \brief Get an "equal list" of the fields and values in this row + /// + /// This method's parameters govern how the returned list will + /// behave when you insert it into a C++ stream: + /// + /// \param d delimiter to use between items + /// \param e the operator to use between elements + /// \param m the manipulator to use for each element + /// + /// For example, if d is ",", e is " = ", and m is the quote + /// manipulator, then the field and value lists (a, b) (c, d'e) + /// will yield an equal list that gives the following when inserted + /// into a C++ stream: + /// + /// \code + /// 'a' = 'c', 'b' = 'd''e' + /// \endcode + /// + /// Notice how the single quote was 'escaped' in the SQL way to + /// avoid a syntax error. + template + equal_list_ba equal_list(const char* d, + const char* e, Manip m) const; + +private: + std::vector data_; + std::vector is_nulls_; + const ResUse* res_; + bool initialized_; +}; + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/sql_string.cpp b/code/meosdb/mysql++/sql_string.cpp new file mode 100644 index 0000000..97a1269 --- /dev/null +++ b/code/meosdb/mysql++/sql_string.cpp @@ -0,0 +1,178 @@ +/*********************************************************************** + sql_string.cpp - Implements the SQLString template. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "sql_string.h" + +#include +#include + +using namespace std; + +namespace mysqlpp { + +SQLString::SQLString() : +is_string(false), +dont_escape(false), +processed(false) +{ +} + +SQLString::SQLString(const string& str) : +string(str), +is_string(true), +dont_escape(false), +processed(false) +{ +} + +SQLString::SQLString(const char* str) : +string(str), +is_string(true), +dont_escape(false), +processed(false) +{ +} + +SQLString::SQLString(const char* str, size_t len) : +string(str, len), +is_string(true), +dont_escape(false), +processed(false) +{ +} + +SQLString::SQLString(char i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << static_cast(i); + assign(outs.str()); +} + +SQLString::SQLString(unsigned char i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << static_cast(i); + assign(outs.str()); +} + +SQLString::SQLString(short int i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << i; + assign(outs.str()); +} + +SQLString::SQLString(unsigned short int i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << i; + assign(outs.str()); +} + +SQLString::SQLString(int i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << i; + assign(outs.str()); +} + +SQLString::SQLString(unsigned int i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << i; + assign(outs.str()); +} + +SQLString::SQLString(longlong i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << i; + assign(outs.str()); +} + +SQLString::SQLString(ulonglong i) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs << i; + assign(outs.str()); +} + +SQLString::SQLString(float f) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs.precision(7); // max digits in IEEE 754 single-prec float + outs << f; + assign(outs.str()); +} + +SQLString::SQLString(double f) : +is_string(false), +dont_escape(false), +processed(false) +{ + ostringstream outs; + outs.precision(16); // max digits in IEEE 754 double-prec float + outs << f; + assign(outs.str()); +} + +SQLString::SQLString(const null_type& i) : +string("NULL"), +is_string(false), +dont_escape(false), +processed(false) +{ +} + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/sql_string.h b/code/meosdb/mysql++/sql_string.h new file mode 100644 index 0000000..b59908e --- /dev/null +++ b/code/meosdb/mysql++/sql_string.h @@ -0,0 +1,143 @@ +/// \file sql_string.h +/// \brief Declares an \c std::string derivative that adds some things +/// needed within the library. +/// +/// This class adds some flags needed by other parts of MySQL++, and it +/// adds conversion functions from any primitive type. This helps in +/// inserting these primitive types into the database, because we need +/// everything in string form to build SQL queries. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_SQL_STRING_H +#define MYSQLPP_SQL_STRING_H + +#include "common.h" +#include "null.h" + +#include +#include + +namespace mysqlpp { + +/// \brief A specialized \c std::string that will convert from any +/// valid MySQL type. + +class MYSQLPP_EXPORT SQLString : public std::string { +public: + /// \brief If true, the object's string data is a copy of another + /// string. Otherwise, it's the string form of an integral type. + bool is_string; + + /// \brief If true, the string data doesn't need to be SQL-escaped + /// when building a query. + bool dont_escape; + + /// \brief If true, one of the MySQL++ manipulators has processed + /// the string data. + /// + /// "Processing" is escaping special SQL characters, and/or adding + /// quotes. See the documentation for manip.h for details. + /// + /// This flag is used by the template query mechanism, to prevent a + /// string from being re-escaped or re-quoted each time that query + /// is reused. The flag is reset by operator=, to force the new + /// parameter value to be re-processed. + bool processed; + + /// \brief Default constructor; empty string + SQLString(); + + /// \brief Create object as a copy of a C++ string + SQLString(const std::string& str); + + /// \brief Create object as a copy of a C string + SQLString(const char* str); + + /// \brief Create object as a copy of a known-length string of + /// characters. + SQLString(const char* str, size_t len); + + /// \brief Create object as the string form of a \c char value + SQLString(char i); + + /// \brief Create object as the string form of an \c unsigned + /// \c char value + SQLString(unsigned char i); + + /// \brief Create object as the string form of a \c short \c int + /// value + SQLString(short int i); + + /// \brief Create object as the string form of an \c unsigned + /// \c short \c int value + SQLString(unsigned short int i); + + /// \brief Create object as the string form of an \c int value + SQLString(int i); + + /// \brief Create object as the string form of an \c unsigned + /// \c int value + SQLString(unsigned int i); + + /// \brief Create object as the string form of a \c longlong + /// value + SQLString(longlong i); + + /// \brief Create object as the string form of an \c unsigned + /// \c longlong value + SQLString(ulonglong i); + + /// \brief Create object as the string form of a \c float + /// value + SQLString(float i); + + /// \brief Create object as the string form of a \c double + /// value + SQLString(double i); + + /// \brief Create object representing NULL + SQLString(const null_type& i); + + /// \brief Copy a C string into this object + SQLString& operator =(const char* str) + { + std::string::operator =(str); + processed = false; + return *this; + } + + /// \brief Copy a C++ \c string into this object + SQLString& operator =(const std::string& str) + { + std::string::operator =(str); + processed = false; + return *this; + } +}; + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/sql_types.h b/code/meosdb/mysql++/sql_types.h new file mode 100644 index 0000000..5d3d12b --- /dev/null +++ b/code/meosdb/mysql++/sql_types.h @@ -0,0 +1,85 @@ +/// \file sql_types.h +/// \brief Declares the closest C++ equivalent of each MySQL column type + +/*********************************************************************** + Copyright (c) 2006 by Educational Technology Resources, Inc. Others + may also hold copyrights on code in this file. See the CREDITS file in + the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_SQL_TYPES_H) +#define MYSQLPP_SQL_TYPES_H + +#include "common.h" + +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +// Nearest C++ equivalents of MySQL data types. These are only the "NOT +// NULL" variants. Wrap these types in MySQL++'s Null<> template to get +// NULL-able types. +typedef signed char sql_tinyint; +typedef unsigned char sql_tinyint_unsigned; +typedef short sql_smallint; +typedef unsigned short sql_smallint_unsigned; +typedef int sql_int; +typedef unsigned int sql_int_unsigned; +typedef int sql_mediumint; +typedef unsigned int sql_mediumint_unsigned; +typedef longlong sql_bigint; +typedef ulonglong sql_bigint_unsigned; + +typedef float sql_float; +typedef double sql_double; +typedef double sql_decimal; + +typedef std::string sql_enum; + +typedef ColData sql_blob; +typedef ColData sql_tinyblob; +typedef ColData sql_mediumblob; +typedef ColData sql_longblob; + +typedef std::string sql_char; +typedef std::string sql_varchar; + +#ifdef MYSQLPP_DATETIME_H + // MySQL++ date and time types are defined, so make aliases for + // them matching the style of the above types. + typedef Date sql_date; + typedef Time sql_time; + typedef Time sql_timestamp; + typedef DateTime sql_datetime; +#endif +#ifdef MYSQLPP_MYSET_H + // Ditto for MySQL++'s SQL set type + typedef Set<> sql_set; +#endif + +#endif // !defined(DOXYGEN_IGNORE) + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_SQL_TYPES_H) + diff --git a/code/meosdb/mysql++/stream2string.h b/code/meosdb/mysql++/stream2string.h new file mode 100644 index 0000000..65ebdef --- /dev/null +++ b/code/meosdb/mysql++/stream2string.h @@ -0,0 +1,56 @@ +/// \file stream2string.h +/// \brief Declares an adapter that converts something that can be +/// inserted into a C++ stream into a string type. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_STREAM2STRING_H +#define MYSQLPP_STREAM2STRING_H + +#include + +namespace mysqlpp { + +/// \brief Converts a stream-able object to any type that can be +/// initialized from an \c std::string. +/// +/// This adapter takes any object that has an \c out_stream() member +/// function and converts it to a string type. An example of such a +/// type within the library is mysqlpp::Date. + +template +Strng stream2string(const T& object) +{ + std::ostringstream str; + object.out_stream(str); + str << std::ends; + Strng s = str.str(); + return s; +} + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/string_util.cpp b/code/meosdb/mysql++/string_util.cpp new file mode 100644 index 0000000..1785c25 --- /dev/null +++ b/code/meosdb/mysql++/string_util.cpp @@ -0,0 +1,145 @@ +/*********************************************************************** + string_util.cpp - Implements utility functions for manipulating + C++ strings. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "string_util.h" + +namespace mysqlpp { + +void strip(std::string& s) +{ + size_t i, j = s.size() - 1; + if (!s.size()) { + return; + } + for (i = 0; s[i] == ' '; i++) ; + if (i) { + s.erase(0, i); + } + j = s.size(); + if (!j) { + return; + } + j--; + for (i = j; i && s[i] == ' '; i--) ; + if (i != j) { + s.erase(i + 1, static_cast (-1)); + } +} + +void escape_string(std::string & s) +{ + if (!s.size()) { + return; + } + + for (unsigned int i = 0; i < s.size(); i++) { + switch (s[i]) { + case '\0': // Must be escaped for "mysql" + s[i] = '\\'; + s.insert(i, "0", 1); + i++; + break; + case '\n': // Must be escaped for logs + s[i] = '\\'; + s.insert(i, "n", 1); + i++; + break; + case '\r': + s[i] = '\\'; + s.insert(i, "r", 1); + i++; + break; + case '\\': + s[i] = '\\'; + s.insert(i, "\\", 1); + i++; + break; + case '\"': + s[i] = '\\'; + s.insert(i, "\"", 1); + i++; + break; + case '\'': // Better safe than sorry + s[i] = '\\'; + s.insert(i, "\'", 1); + i++; + break; + case '\032': // This gives problems on Win32 + s[i] = '\\'; + s.insert(i, "Z", 1); + i++; + break; + default: + break; + } + } +} + + +void +str_to_upr(std::string& s) +{ + for (std::string::size_type i = 0; i < s.length(); ++i) { + s[i] = toupper(s[i]); + } +} + + +void +str_to_lwr(std::string& s) +{ + for (std::string::size_type i = 0; i < s.length(); ++i) { + s[i] = tolower(s[i]); + } +} + + +void +strip_all_blanks(std::string& s) +{ + for (std::string::size_type i = 0; i < s.length(); ++i) { + if (s[i] == ' ') { + s.erase(i, 1); + --i; + } + } +} + + +void +strip_all_non_num(std::string& s) +{ + for (std::string::size_type i = 0; i < s.length(); ++i) { + if (!isdigit(s[i])) { + s.erase(i, 1); + --i; + } + } +} + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/string_util.h b/code/meosdb/mysql++/string_util.h new file mode 100644 index 0000000..377b10e --- /dev/null +++ b/code/meosdb/mysql++/string_util.h @@ -0,0 +1,61 @@ +/// \file string_util.h +/// \brief Declares string-handling utility functions used within +/// the library. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_STRING_UTIL_H +#define MYSQLPP_STRING_UTIL_H + +#include "common.h" + +#include + +#include + +namespace mysqlpp { + +/// \brief Strips blanks at left and right ends +MYSQLPP_EXPORT extern void strip(std::string& s); + +/// \brief C++ equivalent of mysql_escape_string() +MYSQLPP_EXPORT extern void escape_string(std::string& s); + +/// \brief Changes case of string to upper +MYSQLPP_EXPORT extern void str_to_upr(std::string& s); + +/// \brief Changes case of string to lower +MYSQLPP_EXPORT extern void str_to_lwr(std::string& s); + +/// \brief Removes all blanks +MYSQLPP_EXPORT extern void strip_all_blanks(std::string& s); + +/// \brief Removes all non-numerics +MYSQLPP_EXPORT extern void strip_all_non_num(std::string& s); + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/tiny_int.h b/code/meosdb/mysql++/tiny_int.h new file mode 100644 index 0000000..cec30e5 --- /dev/null +++ b/code/meosdb/mysql++/tiny_int.h @@ -0,0 +1,239 @@ +/// \file tiny_int.h +/// \brief Declares class for holding a SQL tiny_int + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_TINY_INT_H +#define MYSQLPP_TINY_INT_H + +namespace mysqlpp { + +/// \brief Class for holding an SQL \c tiny_int object. +/// +/// This is required because the closest C++ type, \c char, doesn't +/// have all the right semantics. For one, inserting a \c char into a +/// stream won't give you a number. +/// +/// Several of the functions below accept a \c short \c int argument, +/// but internally we store the data as a \c char. Beware of integer +/// overflows! + +class MYSQLPP_EXPORT tiny_int +{ +public: + /// \brief Default constructor + /// + /// Value is uninitialized + tiny_int() { } + + /// \brief Create object from any integral type that can be + /// converted to a \c short \c int. + tiny_int(short int v) : + value_(char(v)) + { + } + + /// \brief Return value as a \c short \c int. + operator short int() const + { + return static_cast(value_); + } + + /// \brief Assign a \c short \c int to the object. + tiny_int& operator =(short int v) + { + value_ = char(v); + return *this; + } + + /// \brief Add another value to this object + tiny_int& operator +=(short int v) + { + value_ += char(v); + return *this; + } + + /// \brief Subtract another value to this object + tiny_int& operator -=(short int v) + { + value_ -= char(v); + return *this; + } + + /// \brief Multiply this value by another object + tiny_int& operator *=(short int v) + { + value_ *= char(v); + return *this; + } + + /// \brief Divide this value by another object + tiny_int& operator /=(short int v) + { + value_ /= char(v); + return *this; + } + + /// \brief Divide this value by another object and store the + /// remainder + tiny_int& operator %=(short int v) + { + value_ %= char(v); + return *this; + } + + /// \brief Bitwise AND this value by another value + tiny_int& operator &=(short int v) + { + value_ &= char(v); + return *this; + } + + /// \brief Bitwise OR this value by another value + tiny_int& operator |=(short int v) + { + value_ |= char(v); + return *this; + } + + /// \brief Bitwise XOR this value by another value + tiny_int& operator ^=(short int v) + { + value_ ^= char(v); + return *this; + } + + /// \brief Shift this value left by \c v positions + tiny_int& operator <<=(short int v) + { + value_ <<= char(v); + return *this; + } + + /// \brief Shift this value right by \c v positions + tiny_int& operator >>=(short int v) + { + value_ >>= char(v); + return *this; + } + + /// \brief Add one to this value and return that value + tiny_int& operator ++() + { + value_++; + return *this; + } + + /// \brief Subtract one from this value and return that value + tiny_int& operator --() + { + value_--; + return *this; + } + + /// \brief Add one to this value and return the previous value + tiny_int operator ++(int) + { + tiny_int tmp = value_; + value_++; + return tmp; + } + + /// \brief Subtract one from this value and return the previous + /// value + tiny_int operator --(int) + { + tiny_int tmp = value_; + value_--; + return tmp; + } + + /// \brief Return this value minus \c i + tiny_int operator -(const tiny_int& i) const + { + return value_ - i; + } + + /// \brief Return this value plus \c i + tiny_int operator +(const tiny_int& i) const + { + return value_ + i; + } + + /// \brief Return this value multiplied by \c i + tiny_int operator *(const tiny_int& i) const + { + return value_ * i; + } + + /// \brief Return this value divided by \c i + tiny_int operator /(const tiny_int& i) const + { + return value_ / i; + } + + /// \brief Return the modulus of this value divided by \c i + tiny_int operator %(const tiny_int& i) const + { + return value_ % i; + } + + /// \brief Return this value bitwise OR'd by \c i + tiny_int operator |(const tiny_int& i) const + { + return value_ | i; + } + + /// \brief Return this value bitwise AND'd by \c i + tiny_int operator &(const tiny_int& i) const + { + return value_ & i; + } + + /// \brief Return this value bitwise XOR'd by \c i + tiny_int operator ^(const tiny_int& i) const + { + return value_ ^ i; + } + + /// \brief Return this value bitwise shifted left by \c i + tiny_int operator <<(const tiny_int& i) const + { + return value_ << i; + } + + /// \brief Return this value bitwise shifted right by \c i + tiny_int operator >>(const tiny_int& i) const + { + return value_ >> i; + } + +private: + char value_; +}; + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql++/transaction.cpp b/code/meosdb/mysql++/transaction.cpp new file mode 100644 index 0000000..faaf060 --- /dev/null +++ b/code/meosdb/mysql++/transaction.cpp @@ -0,0 +1,97 @@ +/*********************************************************************** + transaction.cpp - Implements the Transaction class. + + Copyright (c) 2006 by Educational Technology Resources, Inc. Others + may also hold copyrights on code in this file. See the CREDITS file + in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#define MYSQLPP_NOT_HEADER +#include "common.h" + +#include "transaction.h" + +#include "connection.h" +#include "query.h" + +using namespace std; +using namespace mysqlpp; + + +//// ctor ////////////////////////////////////////////////////////////// + +Transaction::Transaction(Connection& conn, bool consistent) : +conn_(conn), +finished_(true) // don't bother rolling it back if ctor fails +{ + // Begin the transaction set + Query q(conn_.query()); + q << "START TRANSACTION"; + if (consistent) { + q << " WITH CONSISTENT SNAPSHOT"; + } + q.execute(); + + // Setup succeeded, so mark our transaction as not-finished. + finished_ = false; +} + + +//// dtor ////////////////////////////////////////////////////////////// + +Transaction::~Transaction() +{ + if (!finished_) { + try { + rollback(); + } + catch (...) { + // eat all exceptions + } + } +} + + +//// commit //////////////////////////////////////////////////////////// + +void +Transaction::commit() +{ + Query q(conn_.query()); + q << "COMMIT"; + q.execute(); + + finished_ = true; +} + + +//// rollback ////////////////////////////////////////////////////////// + +void +Transaction::rollback() +{ + Query q(conn_.query()); + q << "ROLLBACK"; + q.execute(); + + finished_ = true; +} + + diff --git a/code/meosdb/mysql++/transaction.h b/code/meosdb/mysql++/transaction.h new file mode 100644 index 0000000..a8567d3 --- /dev/null +++ b/code/meosdb/mysql++/transaction.h @@ -0,0 +1,91 @@ +/// \file transaction.h +/// \brief Declares the Transaction class. +/// +/// This object works with the Connection class to automate the use of +/// MySQL transactions. It allows you to express these transactions +/// directly in C++ code instead of sending the raw SQL commands. + +/*********************************************************************** + Copyright (c) 2006 by Educational Technology Resources, Inc. Others + may also hold copyrights on code in this file. See the CREDITS file + in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#if !defined(MYSQLPP_TRANSACTION_H) +#define MYSQLPP_TRANSACTION_H + +#include "common.h" + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Make Doxygen ignore this +class MYSQLPP_EXPORT Connection; +#endif + +/// \brief Helper object for creating exception-safe SQL transactions. + +class MYSQLPP_EXPORT Transaction +{ +public: + /// \brief Constructor + /// + /// \param conn The connection we use to manage the transaction set + /// \param consistent Whether to use "consistent snapshots" during + /// the transaction. See the documentation for "START TRANSACTION" + /// in the MySQL manual for more on this. + Transaction(Connection& conn, bool consistent = false); + + /// \brief Destructor + /// + /// If the transaction has not been committed or rolled back by the + /// time the destructor is called, it is rolled back. This is the + /// right thing because one way this can happen is if the object is + /// being destroyed as the stack is unwound to handle an exception. + /// In that instance, you certainly want to roll back the + /// transaction. + ~Transaction(); + + /// \brief Commits the transaction + /// + /// This commits all updates to the database using the connection + /// we were created with since this object was created. This is a + /// no-op if the table isn't stored using a transaction-aware + /// storage engine. See CREATE TABLE in the MySQL manual for + /// details. + void commit(); + + /// \brief Rolls back the transaction + /// + /// This abandons all SQL statements made on the connection since + /// this object was created. This only works on tables stored using + /// a transaction-aware storage engine. See CREATE TABLE in the + /// MySQL manual for details. + void rollback(); + +private: + Connection& conn_; ///! Connection to send queries through + bool finished_; ///! True when we commit or roll back xaction +}; + +} // end namespace mysqlpp + +#endif // !defined(MYSQLPP_TRANSACTION_H) + diff --git a/code/meosdb/mysql++/type_info.cpp b/code/meosdb/mysql++/type_info.cpp new file mode 100644 index 0000000..191536c --- /dev/null +++ b/code/meosdb/mysql++/type_info.cpp @@ -0,0 +1,192 @@ +/*********************************************************************** + type_info.cpp - Implements the mysql_type_info class. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "common.h" +#include "type_info.h" + +#include "datetime.h" +#include "myset.h" +#include "sql_types.h" + +#include + +#include + +using namespace std; + +namespace mysqlpp { + +// The first half of this array roughly parallels enum_field_types +// in mysql/mysql_com.h. It is a lookup table used by the type() method +// below when translating from SQL type information to the closest +// C++ equivalent. +// +// The second half of the list parallels the first, to handle null-able +// versions of the types in the first half. This is required because +// SQL's 'null' concept does not map neatly into the C++ type system, so +// null-able versions of these types have to have a different C++ type, +// implemented using the Null template. See null.h for further details. +// +// Types marked true (the "default" field) are added to a lookup map in +// the mysql_type_info_lookup class in order to provide reverse lookup +// of C++ types to SQL types. Put another way, if you take the subset +// of all items marked true, the typeid() of each item must be unique. +const mysql_type_info::sql_type_info mysql_type_info::types[62] = { + sql_type_info("DECIMAL NOT NULL", typeid(sql_decimal), 0), + sql_type_info("TINYINT NOT NULL", typeid(sql_tinyint), 1, true), + sql_type_info("SMALLINT NOT NULL", typeid(sql_smallint), 2, true), + sql_type_info("INT NOT NULL", typeid(sql_int), 3, true), + sql_type_info("FLOAT NOT NULL", typeid(sql_float), 4, true), + sql_type_info("DOUBLE NOT NULL", typeid(sql_double), 5, true), + sql_type_info("NULL NOT NULL", typeid(void), 6), + sql_type_info("TIMESTAMP NOT NULL", typeid(sql_timestamp), 7), + sql_type_info("BIGINT NOT NULL", typeid(sql_bigint), 8, true), + sql_type_info("MEDIUMINT NOT NULL", typeid(sql_mediumint), 9), + sql_type_info("DATE NOT NULL", typeid(sql_date), 10, true), + sql_type_info("TIME NOT NULL", typeid(sql_time), 11, true), + sql_type_info("DATETIME NOT NULL", typeid(sql_datetime), 12, true), + sql_type_info("ENUM NOT NULL", typeid(sql_enum), 13, true), + sql_type_info("SET NOT NULL", typeid(sql_set), 14, true), + sql_type_info("TINYBLOB NOT NULL", typeid(sql_tinyblob), 15), + sql_type_info("MEDIUMBLOB NOT NULL", typeid(sql_mediumblob), 16), + sql_type_info("LONGBLOB NOT NULL", typeid(sql_longblob), 17), + sql_type_info("BLOB NOT NULL", typeid(sql_blob), 18), + sql_type_info("VARCHAR NOT NULL", typeid(sql_varchar), 19, true), + sql_type_info("CHAR NOT NULL", typeid(sql_char), 20), + sql_type_info("CHAR NOT NULL", typeid(sql_char), 21), + sql_type_info("TINYINT UNSIGNED NOT NULL", typeid(sql_tinyint_unsigned), 22, true), + sql_type_info("SMALLINT UNSIGNED NOT NULL", typeid(sql_smallint_unsigned), 23, true), + sql_type_info("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned), 24), + sql_type_info("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned), 25), + sql_type_info("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned), 26), + sql_type_info("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned), 27), + sql_type_info("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned), 28, true), + sql_type_info("BIGINT UNSIGNED NOT NULL", typeid(sql_bigint_unsigned), 29, true), + sql_type_info("MEDIUMINT UNSIGNED NOT NULL", typeid(sql_mediumint_unsigned), 30), + + sql_type_info("DECIMAL NULL", typeid(Null), 0), + sql_type_info("TINYINT NULL", typeid(Null), 1, true), + sql_type_info("SMALLINT NULL", typeid(Null), 2, true), + sql_type_info("INT NULL", typeid(Null), 3, true), + sql_type_info("FLOAT NULL", typeid(Null), 4, true), + sql_type_info("DOUBLE NULL", typeid(Null), 5, true), + sql_type_info("NULL NULL", typeid(Null), 6), + sql_type_info("TIMESTAMP NULL", typeid(Null), 7), + sql_type_info("BIGINT NULL", typeid(Null), 8, true), + sql_type_info("MEDIUMINT NULL", typeid(Null), 9), + sql_type_info("DATE NULL", typeid(Null), 10, true), + sql_type_info("TIME NULL", typeid(Null), 11, true), + sql_type_info("DATETIME NULL", typeid(Null), 12, true), + sql_type_info("ENUM NULL", typeid(Null), 13, true), + sql_type_info("SET NULL", typeid(Null), 14, true), + sql_type_info("TINYBLOB NULL", typeid(Null), 15), + sql_type_info("MEDIUMBLOB NULL", typeid(Null), 16), + sql_type_info("LONGBLOB NULL", typeid(Null), 17), + sql_type_info("BLOB NULL", typeid(Null), 18), + sql_type_info("VARCHAR NULL", typeid(Null), 19, true), + sql_type_info("CHAR NULL", typeid(Null), 20), + sql_type_info("CHAR NULL", typeid(Null), 21), + sql_type_info("TINYINT UNSIGNED NULL", typeid(Null), 22, true), + sql_type_info("SMALLINT UNSIGNED NULL", typeid(Null), 23, true), + sql_type_info("INT UNSIGNED NULL", typeid(Null), 24), + sql_type_info("INT UNSIGNED NULL", typeid(Null), 25), + sql_type_info("INT UNSIGNED NULL", typeid(Null), 26), + sql_type_info("INT UNSIGNED NULL", typeid(Null), 27), + sql_type_info("INT UNSIGNED NULL", typeid(Null), 28, true), + sql_type_info("BIGINT UNSIGNED NULL", typeid(Null), 29, true), + sql_type_info("MEDIUMINT UNSIGNED NULL", typeid(Null), 30), +}; + +const mysql_type_info::sql_type_info_lookup + mysql_type_info::lookups(mysql_type_info::types, 62); + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +mysql_ti_sql_type_info_lookup::mysql_ti_sql_type_info_lookup( + const sql_type_info types[], const int size) +{ + for (int i = 0; i != size; i++) { + if (types[i].default_) { + map_[types[i].c_type_] = i; + } + } +} + +#endif // !defined(DOXYGEN_IGNORE) + +unsigned char mysql_type_info::type(enum_field_types t, + bool _unsigned, bool _null) +{ + if (_null) { + if (_unsigned) { + return unsigned_null_offset + t; + } + else { + if (t < 200) + return null_offset + t; + else + return null_offset + (t - 234); + } + } + else { + if (_unsigned) { + return unsigned_offset + t; + } + else { + if (t < 200) + return offset + t; + else + return offset + (t - 234); + } + } +} + +bool mysql_type_info::quote_q() const +{ + const type_info& ti = base_type().c_type(); + return ti == typeid(string) || + ti == typeid(sql_date) || + ti == typeid(sql_time) || + ti == typeid(sql_datetime) || + ti == typeid(sql_set); +} + +bool mysql_type_info::escape_q() const +{ + const type_info& ti = c_type(); + return ti == typeid(string) || + ti == typeid(sql_enum) || + ti == typeid(sql_blob) || + ti == typeid(sql_tinyblob) || + ti == typeid(sql_mediumblob) || + ti == typeid(sql_longblob) || + ti == typeid(sql_char) || + ti == typeid(sql_varchar); +} + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/type_info.h b/code/meosdb/mysql++/type_info.h new file mode 100644 index 0000000..c9d56fd --- /dev/null +++ b/code/meosdb/mysql++/type_info.h @@ -0,0 +1,368 @@ +/// \file type_info.h +/// \brief Declares classes that provide an interface between the SQL +/// and C++ type systems. +/// +/// These classes are mostly used internal to the library. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2006 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_TYPE_INFO_H +#define MYSQLPP_TYPE_INFO_H + +#include "common.h" + +#include +#include + +namespace mysqlpp { + +#if !defined(DOXYGEN_IGNORE) +// Doxygen will not generate documentation for this section. + +class MYSQLPP_EXPORT mysql_type_info; +class MYSQLPP_EXPORT mysql_ti_sql_type_info_lookup; + +class MYSQLPP_EXPORT mysql_ti_sql_type_info +{ +private: + friend class mysql_type_info; + friend class mysql_ti_sql_type_info_lookup; + + mysql_ti_sql_type_info& operator=( + const mysql_ti_sql_type_info& b); + + // Not initting _base_type and _default because only mysql_type_info + // can create them. There *must* be only one copy of each. + mysql_ti_sql_type_info() : + sql_name_(0), + c_type_(0), + base_type_(0), + default_(false) + { + } + + mysql_ti_sql_type_info(const char* s, + const std::type_info& t, const unsigned char bt = 0, + const bool d = false) : + sql_name_(s), + c_type_(&t), + base_type_(bt), + default_(d) + { + } + + const char* sql_name_; + const std::type_info* c_type_; + const unsigned char base_type_; + const bool default_; +}; + + +struct type_info_cmp +{ + bool operator() (const std::type_info* lhs, + const std::type_info* rhs) const + { + return lhs->before(*rhs) != 0; + } +}; + +class MYSQLPP_EXPORT mysql_ti_sql_type_info_lookup +{ +private: + friend class mysql_type_info; + + typedef mysql_ti_sql_type_info sql_type_info; + + mysql_ti_sql_type_info_lookup( + const sql_type_info types[], const int size); + + const unsigned char& operator []( + const std::type_info& ti) const + { + return map_.find(&ti)->second; + } + + std::map map_; +}; + +#endif // !defined(DOXYGEN_IGNORE) + + +/// \brief Holds basic type information for ColData. +/// +/// Class to hold basic type information for mysqlpp::ColData. +class MYSQLPP_EXPORT mysql_type_info +{ +public: + /// \brief Create object + /// + /// \param n index into the internal type table + /// + /// Because of the \c n parameter's definition, this constructor + /// shouldn't be used outside the library. + /// + /// The default is intended to try and crash a program using a + /// default mysql_type_info object. This is a very wrong thing + /// to do. + mysql_type_info(unsigned char n = static_cast(-1)) : + _length(0), + _max_length(0), + num_(n) + { + } + + /// \brief Create object from MySQL C API type info + /// + /// \param t the MySQL C API type ID for this type + /// \param _unsigned if true, this is the unsigned version of the type + /// \param _null if true, this type can hold a SQL null + mysql_type_info(enum_field_types t, bool _unsigned, bool _null) : + _length(0), + _max_length(0), + num_(type(t, _unsigned, _null)) + { + } + + /// \brief Create object from a MySQL C API field + /// + /// \param f field from which we extract the type info + mysql_type_info(const MYSQL_FIELD& f) : + _length(f.length), + _max_length(f.max_length), + num_(type(f.type, (f.flags & UNSIGNED_FLAG) != 0, + (f.flags & NOT_NULL_FLAG) == 0)) + { + } + + /// \brief Create object as a copy of another + mysql_type_info(const mysql_type_info& t) : + _length(0), + _max_length(0), + num_(t.num_) + { + } + + /// \brief Create object from a C++ type_info object + /// + /// This tries to map a C++ type to the closest MySQL data type. + /// It is necessarily somewhat approximate. + mysql_type_info(const std::type_info& t) : + num_(lookups[t]) + { + } + + /// \brief Assign a new internal type value + /// + /// \param n an index into the internal MySQL++ type table + /// + /// This function shouldn't be used outside the library. + mysql_type_info& operator =(unsigned char n) + { + num_ = n; + return *this; + } + + /// \brief Assign another mysql_type_info object to this object + mysql_type_info& operator =(const mysql_type_info& t) + { + num_ = t.num_; + return *this; + } + + /// \brief Assign a C++ type_info object to this object + /// + /// This tries to map a C++ type to the closest MySQL data type. + /// It is necessarily somewhat approximate. + mysql_type_info& operator =(const std::type_info& t) + { + num_ = lookups[t]; + return *this; + } + + /// \brief Returns an implementation-defined name of the C++ type. + /// + /// Returns the name that would be returned by typeid().name() for + /// the C++ type associated with the SQL type. + const char* name() const { return deref().c_type_->name(); } + + /// \brief Returns the name of the SQL type. + /// + /// Returns the SQL name for the type. + const char* sql_name() const { return deref().sql_name_; } + + /// \brief Returns the type_info for the C++ type associated with + /// the SQL type. + /// + /// Returns the C++ type_info record corresponding to the SQL type. + const std::type_info& c_type() const { return *deref().c_type_; } + + /// \brief Return length of data in this field + /// + /// This only works if you initialized this object from a + /// MYSQL_FIELD object. + const unsigned int length() const { return _length; } + + /// \brief Return maximum length of data in this field + /// + /// This only works if you initialized this object from a + /// MYSQL_FIELD object. + const unsigned int max_length() const { return _max_length; } + + /// \brief Returns the type_info for the C++ type inside of the + /// mysqlpp::Null type. + /// + /// Returns the type_info for the C++ type inside the mysqlpp::Null + /// type. If the type is not Null then this is the same as c_type(). + const mysql_type_info base_type() const + { + return mysql_type_info(deref().base_type_); + } + + /// \brief Returns the ID of the SQL type. + /// + /// Returns the ID number MySQL uses for this type. Note: Do not + /// depend on the value of this ID as it may change between MySQL + /// versions. + int id() const + { + return num_; + } + + /// \brief Returns true if the SQL type is of a type that needs to + /// be quoted. + /// + /// \return true if the type needs to be quoted for syntactically + /// correct SQL. + bool quote_q() const; + + /// \brief Returns true if the SQL type is of a type that needs to + /// be escaped. + /// + /// \return true if the type needs to be escaped for syntactically + /// correct SQL. + bool escape_q() const; + + /// \brief Provides a way to compare two types for sorting. + /// + /// Returns true if the SQL ID of this type is lower than that of + /// another. Used by mysqlpp::type_info_cmp when comparing types. + bool before(mysql_type_info& b) + { + return num_ < b.num_; + } + + /// \brief The internal constant we use for our string type. + /// + /// We expose this because other parts of MySQL++ need to know + /// what the string constant is at the moment. + static const unsigned char string_type = 20; + + unsigned int _length; ///< field length, from MYSQL_FIELD + unsigned int _max_length; ///< max data length, from MYSQL_FIELD + +private: + typedef mysql_ti_sql_type_info sql_type_info; + typedef mysql_ti_sql_type_info_lookup sql_type_info_lookup; + + static const sql_type_info types[62]; + + static const unsigned char offset = 0; + static const unsigned char unsigned_offset = 21; + static const unsigned char null_offset = 31; + static const unsigned char unsigned_null_offset = 52; + + static const sql_type_info_lookup lookups; + + /// \brief Return an index into mysql_type_info::types array given + /// MySQL type information. + /// + /// This function is used in mapping from MySQL type information + /// (a type enum, and flags indicating whether it is unsigned and + /// whether it can be 'null') to the closest C++ types available + /// within MySQL++. Notice that nulls have to be handled specially: + /// the SQL null concept doesn't map directly onto the C++ type + /// system. See null.h for details. + /// + /// \param t MySQL C API type constant, from mysql_com.h + /// \param _unsigned if true, indicates the unsigned variant of a + /// MySQL type + /// \param _null if true, indicates the variant of the MySQL type + /// that can also hold an SQL 'null' instead of regular data. + static unsigned char type(enum_field_types t, + bool _unsigned, bool _null = false); + + const sql_type_info& deref() const + { + return types[num_]; + } + + unsigned char num_; +}; + +/// \brief Returns true if two mysql_type_info objects are equal. +inline bool operator ==(const mysql_type_info& a, const mysql_type_info& b) +{ + return a.id() == b.id(); +} + +/// \brief Returns true if two mysql_type_info objects are not equal. +inline bool operator !=(const mysql_type_info& a, const mysql_type_info& b) +{ + return a.id() != b.id(); +} + +/// \brief Returns true if a given mysql_type_info object is equal +/// to a given C++ type_info object. +inline bool operator ==(const std::type_info& a, const mysql_type_info& b) +{ + return a == b.c_type(); +} + +/// \brief Returns true if a given mysql_type_info object is not equal +/// to a given C++ type_info object. +inline bool operator !=(const std::type_info& a, const mysql_type_info& b) +{ + return a != b.c_type(); +} + +/// \brief Returns true if a given mysql_type_info object is equal +/// to a given C++ type_info object. +inline bool operator ==(const mysql_type_info& a, const std::type_info& b) +{ + return a.c_type() == b; +} + +/// \brief Returns true if a given mysql_type_info object is not equal +/// to a given C++ type_info object. +inline bool operator !=(const mysql_type_info& a, const std::type_info& b) +{ + return a.c_type() != b; +} + +} // end namespace mysqlpp + +#endif + diff --git a/code/meosdb/mysql++/vallist.cpp b/code/meosdb/mysql++/vallist.cpp new file mode 100644 index 0000000..8377af7 --- /dev/null +++ b/code/meosdb/mysql++/vallist.cpp @@ -0,0 +1,144 @@ +/*********************************************************************** + vallist.cpp - Implements utility functions for building value lists. + This is internal functionality used within the library. + + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#include "vallist.h" + +#include "result.h" +#include "row.h" + +using std::string; + +namespace mysqlpp { + +void +create_vector(size_t size, std::vector& v, bool t0, bool t1, bool t2, + bool t3, bool t4, bool t5, bool t6, bool t7, bool t8, bool t9, + bool ta, bool tb, bool tc) +{ + v.reserve(size); + + v.push_back(t0); + if (size == 1) return; + + v.push_back(t1); + if (size == 2) return; + + v.push_back(t2); + if (size == 3) return; + + v.push_back(t3); + if (size == 4) return; + + v.push_back(t4); + if (size == 5) return; + + v.push_back(t5); + if (size == 6) return; + + v.push_back(t6); + if (size == 7) return; + + v.push_back(t7); + if (size == 8) return; + + v.push_back(t8); + if (size == 9) return; + + v.push_back(t9); + if (size == 10) return; + + v.push_back(ta); + if (size == 11) return; + + v.push_back(tb); + if (size == 12) return; + + v.push_back(tc); +} + + +template +void create_vector(const Container& c, std::vector& v, + std::string s0, std::string s1, std::string s2, std::string s3, + std::string s4, std::string s5, std::string s6, std::string s7, + std::string s8, std::string s9, std::string sa, std::string sb, + std::string sc) +{ + v.insert(v.begin(), c.size(), false); + + v[c.parent().field_num(s0)] = true; + if (s1.empty()) return; + + v[c.parent().field_num(s1)] = true; + if (s2.empty()) return; + + v[c.parent().field_num(s2)] = true; + if (s3.empty()) return; + + v[c.parent().field_num(s3)] = true; + if (s4.empty()) return; + + v[c.parent().field_num(s4)] = true; + if (s5.empty()) return; + + v[c.parent().field_num(s5)] = true; + if (s6.empty()) return; + + v[c.parent().field_num(s6)] = true; + if (s7.empty()) return; + + v[c.parent().field_num(s7)] = true; + if (s8.empty()) return; + + v[c.parent().field_num(s8)] = true; + if (s9.empty()) return; + + v[c.parent().field_num(s9)] = true; + if (sa.empty()) return; + + v[c.parent().field_num(sa)] = true; + if (sb.empty()) return; + + v[c.parent().field_num(sb)] = true; + if (sc.empty()) return; + + v[c.parent().field_num(sc)] = true; +} + + +#if !defined(DOXYGEN_IGNORE) +// Instantiate above template. Not sure why this is necessary. Hide it +// from Doxygen, because we clearly cannot appease it by documenting it. +template void +create_vector(const Row& c, std::vector& v, string s0, + string s1, string s2, string s3, string s4, string s5, + string s6, string s7, string s8, string s9, string sa, + string sb, string sc); +#endif + +} // end namespace mysqlpp + diff --git a/code/meosdb/mysql++/vallist.h b/code/meosdb/mysql++/vallist.h new file mode 100644 index 0000000..cd79b65 --- /dev/null +++ b/code/meosdb/mysql++/vallist.h @@ -0,0 +1,688 @@ +/// \file vallist.h +/// \brief Declares templates for holding lists of values. + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +#ifndef MYSQLPP_VALLIST_H +#define MYSQLPP_VALLIST_H + +#include "manip.h" + +#include +#include + +namespace mysqlpp { + + +/// \brief Holds two lists of items, typically used to construct a +/// SQL "equals clause". +/// +/// The WHERE clause in a SQL SELECT statment is an example of an +/// equals clause. +/// +/// Imagine an object of this type contains the lists (a, b) (c, d), +/// and that the object's delimiter and equals symbols are set to ", " +/// and " = " respectively. When you insert that object into a C++ +/// stream, you would get "a = c, b = d". +/// +/// This class is never instantiated by hand. The equal_list() +/// functions build instances of this structure template to do their +/// work. MySQL++'s SSQLS mechanism calls those functions when +/// building SQL queries; you can call them yourself to do similar work. +/// The "Harnessing SSQLS Internals" section of the user manual has +/// some examples of this. +/// +/// \sa equal_list_b + +template +struct equal_list_ba +{ + /// \brief the list of objects on the left-hand side of the + /// equals sign + const Seq1* list1; + + /// \brief the list of objects on the right-hand side of the + /// equals sign + const Seq2* list2; + + /// \brief delimiter to use between each pair of elements + const char* delem; + + /// \brief "equal" sign to use between each item in each equal + /// pair; doesn't have to actually be " = " + const char* equl; + + /// \brief manipulator to use when inserting the equal_list into + /// a C++ stream + Manip manip; + + /// \brief Create object + /// + /// \param s1 list of objects on left-hand side of equal sign + /// \param s2 list of objects on right-hand side of equal sign + /// \param d what delimiter to use between each group in the list + /// when inserting the list into a C++ stream + /// \param e the "equals" sign between each pair of items in the + /// equal list; doesn't actually have to be " = "! + /// \param m manipulator to use when inserting the list into a + /// C++ stream + equal_list_ba(const Seq1& s1, const Seq2& s2, const char* d, + const char* e, Manip m) : + list1(&s1), + list2(&s2), + delem(d), + equl(e), + manip(m) + { + } +}; + + +/// \brief Same as equal_list_ba, plus the option to have some elements +/// of the equals clause suppressed. +/// +/// Imagine an object of this type contains the lists (a, b, c) +/// (d, e, f), that the object's 'fields' list is (true, false, true), +/// and that the object's delimiter and equals symbols are set to +/// " AND " and " = " respectively. When you insert that object into a +/// C++ stream, you would get "a = d AND c = f". +/// +/// See equal_list_ba's documentation for more details. + +template +struct equal_list_b +{ + /// \brief the list of objects on the left-hand side of the + /// equals sign + const Seq1* list1; + + /// \brief the list of objects on the right-hand side of the + /// equals sign + const Seq2* list2; + + /// \brief for each true item in the list, the pair in that position + /// will be inserted into a C++ stream + const std::vector fields; + + /// \brief delimiter to use between each pair of elements + const char* delem; + + /// \brief "equal" sign to use between each item in each equal + /// pair; doesn't have to actually be " = " + const char* equl; + + /// \brief manipulator to use when inserting the equal_list into + /// a C++ stream + Manip manip; + + /// \brief Create object + /// + /// \param s1 list of objects on left-hand side of equal sign + /// \param s2 list of objects on right-hand side of equal sign + /// \param f for each true item in the list, the pair of items + /// in that position will be inserted into a C++ stream + /// \param d what delimiter to use between each group in the list + /// when inserting the list into a C++ stream + /// \param e the "equals" sign between each pair of items in the + /// equal list; doesn't actually have to be " = "! + /// \param m manipulator to use when inserting the list into a + /// C++ stream + equal_list_b(const Seq1& s1, const Seq2& s2, + const std::vector& f, const char* d, + const char* e, Manip m) : + list1(&s1), + list2(&s2), + fields(f), + delem(d), + equl(e), + manip(m) + { + } +}; + + +/// \brief Holds a list of items, typically used to construct a SQL +/// "value list". +/// +/// The SQL INSERT statement has a VALUES clause; this class can +/// be used to construct the list of items for that clause. +/// +/// Imagine an object of this type contains the list (a, b, c), and +/// that the object's delimiter symbol is set to ", ". When you +/// insert that object into a C++ stream, you would get "a, b, c". +/// +/// This class is never instantiated by hand. The value_list() +/// functions build instances of this structure template to do their +/// work. MySQL++'s SSQLS mechanism calls those functions when +/// building SQL queries; you can call them yourself to do similar work. +/// The "Harnessing SSQLS Internals" section of the user manual has +/// some examples of this. +/// +/// \sa value_list_b + +template +struct value_list_ba +{ + /// \brief set of objects in the value list + const Seq* list; + + /// \brief delimiter to use between each value in the list when + /// inserting it into a C++ stream + const char* delem; + + /// \brief manipulator to use when inserting the list into a + /// C++ stream + Manip manip; + + /// \brief Create object + /// + /// \param s set of objects in the value list + /// \param d what delimiter to use between each value in the list + /// when inserting the list into a C++ stream + /// \param m manipulator to use when inserting the list into a + /// C++ stream + value_list_ba(const Seq& s, const char* d, Manip m) : + list(&s), + delem(d), + manip(m) + { + } +}; + + +/// \brief Same as value_list_ba, plus the option to have some elements +/// of the list suppressed. +/// +/// Imagine an object of this type contains the list (a, b, c), that +/// the object's 'fields' list is (true, false, true), and that the +/// object's delimiter is set to ":". When you insert that object +/// into a C++ stream, you would get "a:c". +/// +/// See value_list_ba's documentation for more details. + +#pragma warning(disable:4512) + +template +struct value_list_b +{ + /// \brief set of objects in the value list + const Seq* list; + + /// \brief delimiter to use between each value in the list when + /// inserting it into a C++ stream + const std::vector fields; + + /// \brief delimiter to use between each value in the list when + /// inserting it into a C++ stream + const char* delem; + + /// \brief manipulator to use when inserting the list into a C++ + /// stream + Manip manip; + + /// \brief Create object + /// + /// \param s set of objects in the value list + /// \param f for each true item in the list, the list item + /// in that position will be inserted into a C++ stream + /// \param d what delimiter to use between each value in the list + /// when inserting the list into a C++ stream + /// \param m manipulator to use when inserting the list into a + /// C++ stream + value_list_b(const Seq& s, const std::vector& f, + const char* d, Manip m) : + list(&s), + fields(f), + delem(d), + manip(m) + { + } +}; + + +/// \brief Inserts an equal_list_ba into an std::ostream. +/// +/// Given two lists (a, b) and (c, d), a delimiter D, and an equals +/// symbol E, this operator will insert "aEcDbEd" into the stream. +/// +/// See equal_list_ba's documentation for concrete examples. +/// +/// \sa equal_list() + +template +std::ostream& operator <<(std::ostream& o, + const equal_list_ba& el) +{ + typename Seq1::const_iterator i = el.list1->begin(); + typename Seq2::const_iterator j = el.list2->begin(); + + while (1) { + o << *i << el.equl << el.manip << *j; + if ((++i == el.list1->end()) || (++j == el.list2->end())) { + break; + } + o << el.delem; + } + + return o; +} + + +/// \brief Same as operator<< for equal_list_ba, plus the option to +/// suppress insertion of some list items in the stream. +/// +/// See equal_list_b's documentation for examples of how this works. + +template +std::ostream& operator <<(std::ostream& o, + const equal_list_b & el) +{ + typename Seq1::const_iterator i = el.list1->begin(); + typename Seq2::const_iterator j = el.list2->begin(); + + int k = 0; + while (1) { + if (el.fields[k++]) { + o << *i << el.equl << el.manip << *j; + } + if ((++i == el.list1->end()) || (++j == el.list2->end())) { + break; + } + if (el.fields[k]) { + o << el.delem; + } + } + + return o; +} + + +/// \brief Inserts a value_list_ba into an std::ostream. +/// +/// Given a list (a, b) and a delimiter D, this operator will insert +/// "aDb" into the stream. +/// +/// See value_list_ba's documentation for concrete examples. +/// +/// \sa value_list() + +template +std::ostream& operator <<(std::ostream& o, + const value_list_ba& cl) +{ + typename Seq::const_iterator i = cl.list->begin(); + + while (1) { + o << cl.manip << *i; + if (++i == cl.list->end()) { + break; + } + o << cl.delem; + } + + return o; +} + + +/// \brief Same as operator<< for value_list_ba, plus the option to +/// suppress insertion of some list items in the stream. +/// +/// See value_list_b's documentation for examples of how this works. + +template +std::ostream& operator <<(std::ostream& o, + const value_list_b& cl) +{ + typename Seq::const_iterator i = cl.list->begin(); + + int k = 0; + while (1) { + if (cl.fields[k++]) { + o << cl.manip << *i; + } + if (++i == cl.list->end()) { + break; + } + if (cl.fields[k]) { + o << cl.delem; + } + } + + return o; +} + + +/// \brief Create a vector of bool with the given arguments as values. +/// +/// This function takes up to 13 bools, with the size parameter +/// controlling the actual number of parameters we pay attention to. +/// +/// This function is used within the library to build the vector used +/// in calling the vector form of Row::equal_list(), Row::value_list(), +/// and Row::field_list(). See the "Harnessing SSQLS Internals" section +/// of the user manual to see that feature at work. + +void create_vector(size_t size, std::vector& v, bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false); + + +/// \brief Create a vector of bool using a list of named fields. +/// +/// This function is used with the ResUse and Result containers, +/// which have a field_num() member function that maps a field name +/// to its position number. So for each named field, we set the +/// bool in the vector at the corresponding position to true. +/// +/// This function is used within the library to build the vector used +/// in calling the vector form of Row::equal_list(), Row::value_list(), +/// and Row::field_list(). See the "Harnessing SSQLS Internals" section +/// of the user manual to see that feature at work. + +template +void create_vector(const Container& c, std::vector& v, + std::string s0, std::string s1, std::string s2, + std::string s3, std::string s4, std::string s5, + std::string s6, std::string s7, std::string s8, + std::string s9, std::string sa, std::string sb, + std::string sc); + + + +/// \brief Constructs a value_list_ba +/// +/// This function returns a value list that uses the 'do_nothing' +/// manipulator. That is, the items are not quoted or escaped in any +/// way. See value_list(Seq, const char*, Manip) if you need to +/// specify a manipulator. +/// +/// \param s an STL sequence of items in the value list +/// \param d delimiter operator<< should place between items + +template +value_list_ba +value_list(const Seq& s, const char* d = ",") +{ + return value_list_ba(s, d, do_nothing); +} + + +/// \brief Constructs a value_list_ba +/// +/// \param s an STL sequence of items in the value list +/// \param d delimiter operator<< should place between items +/// \param m manipulator to use when inserting items into a stream + +template +value_list_ba +value_list(const Seq& s, const char* d, Manip m) +{ + return value_list_ba(s, d, m); +} + + +/// \brief Constructs a value_list_b (sparse value list) +/// +/// \param s an STL sequence of items in the value list +/// \param d delimiter operator<< should place between items +/// \param m manipulator to use when inserting items into a stream +/// \param vb for each item in this vector that is true, the +/// corresponding item in the value list is inserted into a stream; +/// the others are suppressed + +template +inline value_list_b +value_list(const Seq& s, const char* d, Manip m, + const std::vector& vb) +{ + return value_list_b(s, vb, d, m); +} + + +/// \brief Constructs a value_list_b (sparse value list) +/// +/// Same as value_list(Seq&, const char*, Manip, const vector&), +/// except that it takes the bools as arguments instead of wrapped up +/// in a vector object. + +template +value_list_b +value_list(const Seq& s, const char* d, Manip m, bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) +{ + std::vector vb; + create_vector(s.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, + ta, tb, tc); + return value_list_b(s, vb, d, m); +} + +/// \brief Constructs a sparse value list +/// +/// Same as value_list(Seq&, const char*, Manip, bool, bool...) but +/// without the Manip parameter. We use the do_nothing manipulator, +/// meaning that the value list items are neither escaped nor quoted +/// when being inserted into a stream. + +template +value_list_b +value_list(const Seq& s, const char* d, bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) +{ + std::vector vb; + create_vector(s.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, + ta, tb, tc); + return value_list_b(s, vb, d, do_nothing); +} + + +/// \brief Constructs a sparse value list +/// +/// Same as value_list(Seq&, const char*, Manip, bool, bool...) but +/// without the Manip or delimiter parameters. We use the do_nothing +/// manipulator, meaning that the value list items are neither escaped +/// nor quoted when being inserted into a stream. The delimiter is a +/// comma. This form is suitable for lists of simple data, such as +/// integers. + +template +value_list_b +value_list(const Seq& s, bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) +{ + std::vector vb; + create_vector(s.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, + ta, tb, tc); + return value_list_b(s, vb, ",", do_nothing); +} + + +/// \brief Constructs an equal_list_ba +/// +/// This function returns an equal list that uses the 'do_nothing' +/// manipulator. That is, the items are not quoted or escaped in any +/// way when inserted into a stream. See equal_list(Seq, Seq, +/// const char*, const char*, Manip) if you need a different +/// manipulator. +/// +/// The idea is for both lists to be of equal length because +/// corresponding elements from each list are handled as pairs, but if +/// one list is shorter than the other, the generated list will have +/// that many elements. +/// +/// \param s1 items on the left side of the equals sign when the +/// equal list is inserted into a stream +/// \param s2 items on the right side of the equals sign +/// \param d delimiter operator<< should place between pairs +/// \param e what operator<< should place between items in each pair; +/// by default, an equals sign, as that is the primary use for this +/// mechanism. + +template +equal_list_ba +equal_list(const Seq1& s1, const Seq2& s2, const char *d = ",", + const char *e = " = ") +{ + return equal_list_ba(s1, s2, d, + e, do_nothing); +} + + +/// \brief Constructs an equal_list_ba +/// +/// Same as equal_list(Seq&, Seq&, const char*, const char*) except that +/// it also lets you specify the manipulator. Use this version if the +/// data must be escaped or quoted when being inserted into a stream. + +template +equal_list_ba +equal_list(const Seq1& s1, const Seq2& s2, const char* d, + const char* e, Manip m) +{ + return equal_list_ba(s1, s2, d, e, m); +} + + +/// \brief Constructs a equal_list_b (sparse equal list) +/// +/// Same as equal_list(Seq&, Seq&, const char*, const char*, Manip) except +/// that you can pass a vector of bools. For each true item in that +/// list, operator<< adds the corresponding item is put in the equal +/// list. This lets you pass in sequences when you don't want all of +/// the elements to be inserted into a stream. + +template +equal_list_b +equal_list(const Seq1& s1, const Seq2& s2, const char* d, + const char *e, Manip m, const std::vector& vb) +{ + return equal_list_b(s1, s2, vb, d, e, m); +} + + +/// \brief Constructs a equal_list_b (sparse equal list) +/// +/// Same as equal_list(Seq&, Seq&, const char*, const char*, Manip, +/// vector&) except that it takes boolean parameters +/// instead of a list of bools. + +template +equal_list_b +equal_list(const Seq1& s1, const Seq2& s2, const char* d, + const char* e, Manip m, bool t0, bool t1 = false, + bool t2 = false, bool t3 = false, bool t4 = false, + bool t5 = false, bool t6 = false, bool t7 = false, + bool t8 = false, bool t9 = false, bool ta = false, + bool tb = false, bool tc = false) +{ + std::vector vb; + create_vector(s1.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, + t9, ta, tb, tc); + return equal_list_b(s1, s2, vb, d, e, m); +} + + +/// \brief Constructs a equal_list_b (sparse equal list) +/// +/// Same as equal_list(Seq&, Seq&, const char*, const char*, Manip, +/// bool, bool...) except that it doesn't take the Manip argument. +/// It uses the do_nothing manipulator instead, meaning that none of +/// the elements are escaped when being inserted into a stream. + +template +equal_list_b +equal_list(const Seq1& s1, const Seq2& s2, const char* d, + const char* e, bool t0, bool t1 = false, bool t2 = false, + bool t3 = false, bool t4 = false, bool t5 = false, + bool t6 = false, bool t7 = false, bool t8 = false, + bool t9 = false, bool ta = false, bool tb = false, + bool tc = false) +{ + std::vector vb; + create_vector(s1.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, + t9, ta, tb, tc); + return equal_list_b(s1, s2, vb, + d, e, do_nothing); +} + + +/// \brief Constructs a equal_list_b (sparse equal list) +/// +/// Same as equal_list(Seq&, Seq&, const char*, const char*, bool, +/// bool...) except that it doesn't take the second const char* +/// argument. It uses " = " for the equals symbol. + +template +equal_list_b +equal_list(const Seq1& s1, const Seq2& s2, const char* d, bool t0, + bool t1 = false, bool t2 = false, bool t3 = false, + bool t4 = false, bool t5 = false, bool t6 = false, + bool t7 = false, bool t8 = false, bool t9 = false, + bool ta = false, bool tb = false, bool tc = false) +{ + std::vector vb; + create_vector(s1.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, + t9, ta, tb, tc); + return equal_list_b(s1, s2, vb, + d, " = ", do_nothing); +} + + +/// \brief Constructs a equal_list_b (sparse equal list) +/// +/// Same as equal_list(Seq&, Seq&, const char*, bool, bool...) except +/// that it doesn't take the const char* argument. It uses a comma for +/// the delimiter. This form is useful for building simple equals +/// lists, where no manipulators are necessary, and the default +/// delimiter and equals symbol are suitable. + +template +equal_list_b +equal_list(const Seq1& s1, const Seq2& s2, bool t0, bool t1 = false, + bool t2 = false, bool t3 = false, bool t4 = false, + bool t5 = false, bool t6 = false, bool t7 = false, + bool t8 = false, bool t9 = false, bool ta = false, + bool tb = false, bool tc = false) +{ + std::vector vb; + create_vector(s1.size(), vb, t0, t1, t2, t3, t4, t5, t6, t7, t8, + t9, ta, tb, tc); + return equal_list_b(s1, s2, vb, + ",", " = ", do_nothing); +} + +} // end namespace mysqlpp + +#endif diff --git a/code/meosdb/mysql50/config-win.h b/code/meosdb/mysql50/config-win.h new file mode 100644 index 0000000..5a8c0cc --- /dev/null +++ b/code/meosdb/mysql50/config-win.h @@ -0,0 +1,459 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Defines for Win32 to make it compatible for MySQL */ + +#ifdef __WIN2000__ +/* We have to do this define before including windows.h to get the AWE API +functions */ +#define _WIN32_WINNT 0x0500 +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +/* Avoid endless warnings about sprintf() etc. being unsafe. */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include /* Because of rint() */ +#include +#include +#include + +#define HAVE_SMEM 1 + +#if defined(_WIN64) || defined(WIN64) +#define SYSTEM_TYPE "Win64" +#elif defined(_WIN32) || defined(WIN32) +#define SYSTEM_TYPE "Win32" +#else +#define SYSTEM_TYPE "Windows" +#endif + +#if defined(_M_IA64) +#define MACHINE_TYPE "ia64" +#elif defined(_M_IX86) +#define MACHINE_TYPE "ia32" +#elif defined(_M_ALPHA) +#define MACHINE_TYPE "axp" +#else +#define MACHINE_TYPE "unknown" /* Define to machine type name */ +#endif + +#if !(defined(_WIN64) || defined(WIN64)) +#ifndef _WIN32 +#define _WIN32 /* Compatible with old source */ +#endif +#ifndef __WIN32__ +#define __WIN32__ +#endif +#endif /* _WIN64 */ +#ifndef __WIN__ +#define __WIN__ /* To make it easier in VC++ */ +#endif + +#ifndef MAX_INDEXES +#define MAX_INDEXES 64 +#endif + +/* File and lock constants */ +#define O_SHARE 0x1000 /* Open file in sharing mode */ +#ifdef __BORLANDC__ +#define F_RDLCK LK_NBLCK /* read lock */ +#define F_WRLCK LK_NBRLCK /* write lock */ +#define F_UNLCK LK_UNLCK /* remove lock(s) */ +#else +#define F_RDLCK _LK_NBLCK /* read lock */ +#define F_WRLCK _LK_NBRLCK /* write lock */ +#define F_UNLCK _LK_UNLCK /* remove lock(s) */ +#endif + +#define F_EXCLUSIVE 1 /* We have only exclusive locking */ +#define F_TO_EOF (INT_MAX32/2) /* size for lock of all file */ +#define F_OK 0 /* parameter to access() */ +#define W_OK 2 + +#define S_IROTH S_IREAD /* for my_lib */ + +#ifdef __BORLANDC__ +#define FILE_BINARY O_BINARY /* my_fopen in binary mode */ +#define O_TEMPORARY 0 +#define O_SHORT_LIVED 0 +#define SH_DENYNO _SH_DENYNO +#else +#define O_BINARY _O_BINARY /* compability with MSDOS */ +#define FILE_BINARY _O_BINARY /* my_fopen in binary mode */ +#define O_TEMPORARY _O_TEMPORARY +#define O_SHORT_LIVED _O_SHORT_LIVED +#define SH_DENYNO _SH_DENYNO +#endif +#define NO_OPEN_3 /* For my_create() */ + +#define SIGQUIT SIGTERM /* No SIGQUIT */ + +#undef _REENTRANT /* Crashes something for win32 */ +#undef SAFE_MUTEX /* Can't be used on windows */ + +#if defined(_MSC_VER) && _MSC_VER >= 1310 +#define LL(A) A##ll +#define ULL(A) A##ull +#else +#define LL(A) ((__int64) A) +#define ULL(A) ((unsigned __int64) A) +#endif + +#define LONGLONG_MIN LL(0x8000000000000000) +#define LONGLONG_MAX LL(0x7FFFFFFFFFFFFFFF) +#define ULONGLONG_MAX ULL(0xFFFFFFFFFFFFFFFF) + +/* Type information */ + +#if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT +typedef unsigned short ushort; +typedef unsigned int uint; +#endif /* defined(__EMX__) || !defined(HAVE_UINT) */ + +typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */ +typedef __int64 longlong; +#ifndef HAVE_SIGSET_T +typedef int sigset_t; +#endif +#define longlong_defined +/* + off_t should not be __int64 because of conflicts in header files; + Use my_off_t or os_off_t instead +*/ +#ifndef HAVE_OFF_T +typedef long off_t; +#endif +typedef __int64 os_off_t; +#ifdef _WIN64 +typedef UINT_PTR rf_SetTimer; +#else +#ifndef HAVE_SIZE_T +typedef unsigned int size_t; +#endif +typedef uint rf_SetTimer; +#endif + +#define Socket_defined +#define my_socket SOCKET +#define bool BOOL +#define SIGPIPE SIGINT +#define RETQSORTTYPE void +#define QSORT_TYPE_IS_VOID +#define RETSIGTYPE void +#define SOCKET_SIZE_TYPE int +#define my_socket_defined +#define bool_defined +#define byte_defined +#define HUGE_PTR +#define STDCALL __stdcall /* Used by libmysql.dll */ +#define isnan(X) _isnan(X) +#define finite(X) _finite(X) + +#ifndef UNDEF_THREAD_HACK +#define THREAD +#endif +#define VOID_SIGHANDLER +#define SIZEOF_CHAR 1 +#define SIZEOF_LONG 4 +#define SIZEOF_LONG_LONG 8 +#define SIZEOF_OFF_T 8 +#ifdef _WIN64 +#define SIZEOF_CHARP 8 +#else +#define SIZEOF_CHARP 4 +#endif +#define HAVE_BROKEN_NETINET_INCLUDES +#ifdef __NT__ +#define HAVE_NAMED_PIPE /* We can only create pipes on NT */ +#endif + +/* ERROR is defined in wingdi.h */ +#undef ERROR + +/* We need to close files to break connections on shutdown */ +#ifndef SIGNAL_WITH_VIO_CLOSE +#define SIGNAL_WITH_VIO_CLOSE +#endif + +/* Use all character sets in MySQL */ +#define USE_MB 1 +#define USE_MB_IDENT 1 +#define USE_STRCOLL 1 + +/* All windows servers should support .sym files */ +#undef USE_SYMDIR +#define USE_SYMDIR + +/* If LOAD DATA LOCAL INFILE should be enabled by default */ +#define ENABLED_LOCAL_INFILE 1 + +/* If query profiling should be enabled by default */ +#define ENABLED_PROFILING 1 + +/* Convert some simple functions to Posix */ + +#define my_sigset(A,B) signal((A),(B)) +#define finite(A) _finite(A) +#define sleep(A) Sleep((A)*1000) +#define popen(A,B) _popen((A),(B)) +#define pclose(A) _pclose(A) + +#ifndef __BORLANDC__ +#define access(A,B) _access(A,B) +#endif + +#if !defined(__cplusplus) +#define inline __inline +#endif /* __cplusplus */ + +inline double rint(double nr) +{ + double f = floor(nr); + double c = ceil(nr); + return (((c-nr) >= (nr-f)) ? f :c); +} + +#ifdef _WIN64 +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) + +#else +inline double ulonglong2double(ulonglong value) +{ + longlong nr=(longlong) value; + if (nr >= 0) + return (double) nr; + return (18446744073709551616.0 + (double) nr); +} +#define my_off_t2double(A) ulonglong2double(A) +#endif /* _WIN64 */ + +#if SIZEOF_OFF_T > 4 +#define lseek(A,B,C) _lseeki64((A),(longlong) (B),(C)) +#define tell(A) _telli64(A) +#endif + + +#define STACK_DIRECTION -1 + +/* Optimized store functions for Intel x86 */ + +#ifndef _WIN64 +#define sint2korr(A) (*((int16 *) (A))) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (*((long *) (A))) +#define uint2korr(A) (*((uint16 *) (A))) +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) +#define uint4korr(A) (*((unsigned long *) (A))) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint8korr(A) (*((ulonglong *) (A))) +#define sint8korr(A) (*((longlong *) (A))) +#define int2store(T,A) *((uint16*) (T))= (uint16) (A) +#define int3store(T,A) { *(T)= (uchar) ((A));\ + *(T+1)=(uchar) (((uint) (A) >> 8));\ + *(T+2)=(uchar) (((A) >> 16)); } +#define int4store(T,A) *((long *) (T))= (long) (A) +#define int5store(T,A) { *(T)= (uchar)((A));\ + *((T)+1)=(uchar) (((A) >> 8));\ + *((T)+2)=(uchar) (((A) >> 16));\ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); } +#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) + +#define doubleget(V,M) do { *((long *) &V) = *((long*) M); \ + *(((long *) &V)+1) = *(((long*) M)+1); } while(0) +#define doublestore(T,V) do { *((long *) T) = *((long*) &V); \ + *(((long *) T)+1) = *(((long*) &V)+1); } while(0) +#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); } +#define floatstore(T,V) memcpy((byte*)(T), (byte*)(&V), sizeof(float)) +#define floatget(V,M) memcpy((byte*)(&V), (byte*)(M), sizeof(float)) +#define float8get(V,M) doubleget((V),(M)) +#define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float)) +#define float8store(V,M) doublestore((V),(M)) +#endif /* _WIN64 */ + +#define HAVE_PERROR +#define HAVE_VFPRINT +#define HAVE_RENAME /* Have rename() as function */ +#define HAVE_BINARY_STREAMS /* Have "b" flag in streams */ +#define HAVE_LONG_JMP /* Have long jump function */ +#define HAVE_LOCKING /* have locking() call */ +#define HAVE_ERRNO_AS_DEFINE /* errno is a define */ +#define HAVE_STDLIB /* everything is include in this file */ +#define HAVE_MEMCPY +#define HAVE_MEMMOVE +#define HAVE_GETCWD +#define HAVE_TELL +#define HAVE_TZNAME +#define HAVE_PUTENV +#define HAVE_SELECT +#define HAVE_SETLOCALE +#define HAVE_SOCKET /* Giangi */ +#define HAVE_FLOAT_H +#define HAVE_LIMITS_H +#define HAVE_STDDEF_H +#define HAVE_RINT /* defined in this file */ +#define NO_FCNTL_NONBLOCK /* No FCNTL */ +#define HAVE_ALLOCA +#define HAVE_STRPBRK +#define HAVE_STRSTR +#define HAVE_COMPRESS +#define HAVE_CREATESEMAPHORE +#define HAVE_ISNAN +#define HAVE_FINITE +#define HAVE_QUERY_CACHE +#define SPRINTF_RETURNS_INT +#define HAVE_SETFILEPOINTER +#define HAVE_VIO_READ_BUFF +#define HAVE_STRNLEN + +#ifndef __NT__ +#undef FILE_SHARE_DELETE +#define FILE_SHARE_DELETE 0 /* Not implemented on Win 98/ME */ +#endif + +#ifdef NOT_USED +#define HAVE_SNPRINTF /* Gave link error */ +#define _snprintf snprintf +#endif + +#ifdef _MSC_VER +#define HAVE_LDIV /* The optimizer breaks in zortech for ldiv */ +#define HAVE_ANSI_INCLUDE +#define HAVE_SYS_UTIME_H +#define HAVE_STRTOUL +#endif +#define my_reinterpret_cast(A) reinterpret_cast +#define my_const_cast(A) const_cast + + +/* MYSQL OPTIONS */ + +#ifdef _CUSTOMCONFIG_ +#include +#else +#define DEFAULT_MYSQL_HOME "c:\\mysql" +#define DATADIR "c:\\mysql\\data" +#define PACKAGE "mysql" +#define DEFAULT_BASEDIR "C:\\" +#define SHAREDIR "share" +#define DEFAULT_CHARSET_HOME "C:/mysql/" +#endif +#ifndef DEFAULT_HOME_ENV +#define DEFAULT_HOME_ENV MYSQL_HOME +#endif +#ifndef DEFAULT_GROUP_SUFFIX_ENV +#define DEFAULT_GROUP_SUFFIX_ENV MYSQL_GROUP_SUFFIX +#endif + +/* File name handling */ + +#define FN_LIBCHAR '\\' +#define FN_ROOTDIR "\\" +#define FN_DEVCHAR ':' +#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ +#define FN_NO_CASE_SENCE /* Files are not case-sensitive */ +#define OS_FILE_LIMIT 2048 + +#define DO_NOT_REMOVE_THREAD_WRAPPERS +#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) +#define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) +/* The following is only used for statistics, so it should be good enough */ +#ifdef __NT__ /* This should also work on Win98 but .. */ +#define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) +#define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C)) +#define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) +#else +#define thread_safe_add(V,C,L) \ + pthread_mutex_lock((L)); (V)+=(C); pthread_mutex_unlock((L)); +#define thread_safe_sub(V,C,L) \ + pthread_mutex_lock((L)); (V)-=(C); pthread_mutex_unlock((L)); +#define statistic_add(V,C,L) (V)+=(C) +#endif +#define statistic_increment(V,L) thread_safe_increment((V),(L)) +#define statistic_decrement(V,L) thread_safe_decrement((V),(L)) + +#define shared_memory_buffer_length 16000 +#define default_shared_memory_base_name "MYSQL" + +#define MYSQL_DEFAULT_CHARSET_NAME "latin1" +#define MYSQL_DEFAULT_COLLATION_NAME "latin1_swedish_ci" + +#define HAVE_SPATIAL 1 +#define HAVE_RTREE_KEYS 1 + +#define HAVE_OPENSSL 1 +#define HAVE_YASSL 1 + +/* Define charsets you want */ +/* #undef HAVE_CHARSET_armscii8 */ +/* #undef HAVE_CHARSET_ascii */ +#define HAVE_CHARSET_big5 1 +#define HAVE_CHARSET_cp1250 1 +/* #undef HAVE_CHARSET_cp1251 */ +/* #undef HAVE_CHARSET_cp1256 */ +/* #undef HAVE_CHARSET_cp1257 */ +/* #undef HAVE_CHARSET_cp850 */ +/* #undef HAVE_CHARSET_cp852 */ +/* #undef HAVE_CHARSET_cp866 */ +#define HAVE_CHARSET_cp932 1 +/* #undef HAVE_CHARSET_dec8 */ +#define HAVE_CHARSET_eucjpms 1 +#define HAVE_CHARSET_euckr 1 +#define HAVE_CHARSET_gb2312 1 +#define HAVE_CHARSET_gbk 1 +/* #undef HAVE_CHARSET_greek */ +/* #undef HAVE_CHARSET_hebrew */ +/* #undef HAVE_CHARSET_hp8 */ +/* #undef HAVE_CHARSET_keybcs2 */ +/* #undef HAVE_CHARSET_koi8r */ +/* #undef HAVE_CHARSET_koi8u */ +#define HAVE_CHARSET_latin1 1 +#define HAVE_CHARSET_latin2 1 +/* #undef HAVE_CHARSET_latin5 */ +/* #undef HAVE_CHARSET_latin7 */ +/* #undef HAVE_CHARSET_macce */ +/* #undef HAVE_CHARSET_macroman */ +#define HAVE_CHARSET_sjis 1 +/* #undef HAVE_CHARSET_swe7 */ +#define HAVE_CHARSET_tis620 1 +#define HAVE_CHARSET_ucs2 1 +#define HAVE_CHARSET_ujis 1 +#define HAVE_CHARSET_utf8 1 +#define HAVE_UCA_COLLATIONS 1 + diff --git a/code/meosdb/mysql50/decimal.h b/code/meosdb/mysql50/decimal.h new file mode 100644 index 0000000..2353bab --- /dev/null +++ b/code/meosdb/mysql50/decimal.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _decimal_h +#define _decimal_h + +typedef enum +{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} + decimal_round_mode; +typedef int32 decimal_digit_t; + +typedef struct st_decimal_t { + int intg, frac, len; + my_bool sign; + decimal_digit_t *buf; +} decimal_t; + +int internal_str2dec(const char *from, decimal_t *to, char **end, + my_bool fixed); +int decimal2string(decimal_t *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler); +int decimal2ulonglong(decimal_t *from, ulonglong *to); +int ulonglong2decimal(ulonglong from, decimal_t *to); +int decimal2longlong(decimal_t *from, longlong *to); +int longlong2decimal(longlong from, decimal_t *to); +int decimal2double(decimal_t *from, double *to); +int double2decimal(double from, decimal_t *to); +int decimal_actual_fraction(decimal_t *from); +int decimal2bin(decimal_t *from, char *to, int precision, int scale); +int bin2decimal(char *from, decimal_t *to, int precision, int scale); + +int decimal_size(int precision, int scale); +int decimal_bin_size(int precision, int scale); +int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, + int param); + +int decimal_intg(decimal_t *from); +int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_cmp(decimal_t *from1, decimal_t *from2); +int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, + int scale_incr); +int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_round(decimal_t *from, decimal_t *to, int new_scale, + decimal_round_mode mode); +int decimal_is_zero(decimal_t *from); +void max_decimal(int precision, int frac, decimal_t *to); + +#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) +#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1) + +/* set a decimal_t to zero */ + +#define decimal_make_zero(dec) do { \ + (dec)->buf[0]=0; \ + (dec)->intg=1; \ + (dec)->frac=0; \ + (dec)->sign=0; \ + } while(0) + +/* + returns the length of the buffer to hold string representation + of the decimal (including decimal dot, possible sign and \0) +*/ + +#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \ + (dec)->frac + ((dec)->frac > 0) + 2) + +/* negate a decimal */ +#define decimal_neg(dec) do { (dec)->sign^=1; } while(0) + +/* + conventions: + + decimal_smth() == 0 -- everything's ok + decimal_smth() <= 1 -- result is usable, but precision loss is possible + decimal_smth() <= 2 -- result can be unusable, most significant digits + could've been lost + decimal_smth() > 2 -- no result was generated +*/ + +#define E_DEC_OK 0 +#define E_DEC_TRUNCATED 1 +#define E_DEC_OVERFLOW 2 +#define E_DEC_DIV_ZERO 4 +#define E_DEC_BAD_NUM 8 +#define E_DEC_OOM 16 + +#define E_DEC_ERROR 31 +#define E_DEC_FATAL_ERROR 30 + +#endif + diff --git a/code/meosdb/mysql50/errmsg.h b/code/meosdb/mysql50/errmsg.h new file mode 100644 index 0000000..a104824 --- /dev/null +++ b/code/meosdb/mysql50/errmsg.h @@ -0,0 +1,102 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Error messages for MySQL clients */ +/* (Error messages for the daemon are in share/language/errmsg.sys) */ + +#ifdef __cplusplus +extern "C" { +#endif +void init_client_errs(void); +void finish_client_errs(void); +extern const char *client_errors[]; /* Error messages */ +#ifdef __cplusplus +} +#endif + +#define CR_MIN_ERROR 2000 /* For easier client code */ +#define CR_MAX_ERROR 2999 +#if defined(OS2) && defined(MYSQL_SERVER) +#define CER(X) client_errors[(X)-CR_MIN_ERROR] +#elif !defined(ER) +#define ER(X) client_errors[(X)-CR_MIN_ERROR] +#endif +#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */ + +/* Do not add error numbers before CR_ERROR_FIRST. */ +/* If necessary to add lower numbers, change CR_ERROR_FIRST accordingly. */ +#define CR_ERROR_FIRST 2000 /*Copy first error nr.*/ +#define CR_UNKNOWN_ERROR 2000 +#define CR_SOCKET_CREATE_ERROR 2001 +#define CR_CONNECTION_ERROR 2002 +#define CR_CONN_HOST_ERROR 2003 +#define CR_IPSOCK_ERROR 2004 +#define CR_UNKNOWN_HOST 2005 +#define CR_SERVER_GONE_ERROR 2006 +#define CR_VERSION_ERROR 2007 +#define CR_OUT_OF_MEMORY 2008 +#define CR_WRONG_HOST_INFO 2009 +#define CR_LOCALHOST_CONNECTION 2010 +#define CR_TCP_CONNECTION 2011 +#define CR_SERVER_HANDSHAKE_ERR 2012 +#define CR_SERVER_LOST 2013 +#define CR_COMMANDS_OUT_OF_SYNC 2014 +#define CR_NAMEDPIPE_CONNECTION 2015 +#define CR_NAMEDPIPEWAIT_ERROR 2016 +#define CR_NAMEDPIPEOPEN_ERROR 2017 +#define CR_NAMEDPIPESETSTATE_ERROR 2018 +#define CR_CANT_READ_CHARSET 2019 +#define CR_NET_PACKET_TOO_LARGE 2020 +#define CR_EMBEDDED_CONNECTION 2021 +#define CR_PROBE_SLAVE_STATUS 2022 +#define CR_PROBE_SLAVE_HOSTS 2023 +#define CR_PROBE_SLAVE_CONNECT 2024 +#define CR_PROBE_MASTER_CONNECT 2025 +#define CR_SSL_CONNECTION_ERROR 2026 +#define CR_MALFORMED_PACKET 2027 +#define CR_WRONG_LICENSE 2028 + +/* new 4.1 error codes */ +#define CR_NULL_POINTER 2029 +#define CR_NO_PREPARE_STMT 2030 +#define CR_PARAMS_NOT_BOUND 2031 +#define CR_DATA_TRUNCATED 2032 +#define CR_NO_PARAMETERS_EXISTS 2033 +#define CR_INVALID_PARAMETER_NO 2034 +#define CR_INVALID_BUFFER_USE 2035 +#define CR_UNSUPPORTED_PARAM_TYPE 2036 + +#define CR_SHARED_MEMORY_CONNECTION 2037 +#define CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR 2038 +#define CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR 2039 +#define CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR 2040 +#define CR_SHARED_MEMORY_CONNECT_MAP_ERROR 2041 +#define CR_SHARED_MEMORY_FILE_MAP_ERROR 2042 +#define CR_SHARED_MEMORY_MAP_ERROR 2043 +#define CR_SHARED_MEMORY_EVENT_ERROR 2044 +#define CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR 2045 +#define CR_SHARED_MEMORY_CONNECT_SET_ERROR 2046 +#define CR_CONN_UNKNOW_PROTOCOL 2047 +#define CR_INVALID_CONN_HANDLE 2048 +#define CR_SECURE_AUTH 2049 +#define CR_FETCH_CANCELED 2050 +#define CR_NO_DATA 2051 +#define CR_NO_STMT_METADATA 2052 +#define CR_NO_RESULT_SET 2053 +#define CR_NOT_IMPLEMENTED 2054 +#define CR_SERVER_LOST_EXTENDED 2055 +#define CR_ERROR_LAST /*Copy last error nr:*/ 2055 +/* Add error numbers before CR_ERROR_LAST and change it accordingly. */ + diff --git a/code/meosdb/mysql50/keycache.h b/code/meosdb/mysql50/keycache.h new file mode 100644 index 0000000..fe527cb --- /dev/null +++ b/code/meosdb/mysql50/keycache.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Key cache variable structures */ + +#ifndef _keycache_h +#define _keycache_h +C_MODE_START + +/* declare structures that is used by st_key_cache */ + +struct st_block_link; +typedef struct st_block_link BLOCK_LINK; +struct st_keycache_page; +typedef struct st_keycache_page KEYCACHE_PAGE; +struct st_hash_link; +typedef struct st_hash_link HASH_LINK; + +/* info about requests in a waiting queue */ +typedef struct st_keycache_wqueue +{ + struct st_my_thread_var *last_thread; /* circular list of waiting threads */ +} KEYCACHE_WQUEUE; + +#define CHANGED_BLOCKS_HASH 128 /* must be power of 2 */ + +/* + The key cache structure + It also contains read-only statistics parameters. +*/ + +typedef struct st_key_cache +{ + my_bool key_cache_inited; + my_bool resize_in_flush; /* true during flush of resize operation */ + my_bool can_be_used; /* usage of cache for read/write is allowed */ + uint key_cache_shift; + ulong key_cache_mem_size; /* specified size of the cache memory */ + uint key_cache_block_size; /* size of the page buffer of a cache block */ + ulong min_warm_blocks; /* min number of warm blocks; */ + ulong age_threshold; /* age threshold for hot blocks */ + ulonglong keycache_time; /* total number of block link operations */ + uint hash_entries; /* max number of entries in the hash table */ + int hash_links; /* max number of hash links */ + int hash_links_used; /* number of hash links currently used */ + int disk_blocks; /* max number of blocks in the cache */ + ulong blocks_used; /* maximum number of concurrently used blocks */ + ulong blocks_unused; /* number of currently unused blocks */ + ulong blocks_changed; /* number of currently dirty blocks */ + ulong warm_blocks; /* number of blocks in warm sub-chain */ + ulong cnt_for_resize_op; /* counter to block resize operation */ + long blocks_available; /* number of blocks available in the LRU chain */ + HASH_LINK **hash_root; /* arr. of entries into hash table buckets */ + HASH_LINK *hash_link_root; /* memory for hash table links */ + HASH_LINK *free_hash_list; /* list of free hash links */ + BLOCK_LINK *free_block_list; /* list of free blocks */ + BLOCK_LINK *block_root; /* memory for block links */ + byte HUGE_PTR *block_mem; /* memory for block buffers */ + BLOCK_LINK *used_last; /* ptr to the last block of the LRU chain */ + BLOCK_LINK *used_ins; /* ptr to the insertion block in LRU chain */ + pthread_mutex_t cache_lock; /* to lock access to the cache structure */ + KEYCACHE_WQUEUE resize_queue; /* threads waiting during resize operation */ + KEYCACHE_WQUEUE waiting_for_hash_link; /* waiting for a free hash link */ + KEYCACHE_WQUEUE waiting_for_block; /* requests waiting for a free block */ + BLOCK_LINK *changed_blocks[CHANGED_BLOCKS_HASH]; /* hash for dirty file bl.*/ + BLOCK_LINK *file_blocks[CHANGED_BLOCKS_HASH]; /* hash for other file bl.*/ + + /* + The following variables are and variables used to hold parameters for + initializing the key cache. + */ + + ulonglong param_buff_size; /* size the memory allocated for the cache */ + ulong param_block_size; /* size of the blocks in the key cache */ + ulong param_division_limit; /* min. percentage of warm blocks */ + ulong param_age_threshold; /* determines when hot block is downgraded */ + + /* Statistics variables. These are reset in reset_key_cache_counters(). */ + ulong global_blocks_changed; /* number of currently dirty blocks */ + ulonglong global_cache_w_requests;/* number of write requests (write hits) */ + ulonglong global_cache_write; /* number of writes from cache to files */ + ulonglong global_cache_r_requests;/* number of read requests (read hits) */ + ulonglong global_cache_read; /* number of reads from files to cache */ + + int blocks; /* max number of blocks in the cache */ + my_bool in_init; /* Set to 1 in MySQL during init/resize */ +} KEY_CACHE; + +/* The default key cache */ +extern KEY_CACHE dflt_key_cache_var, *dflt_key_cache; + +extern int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + ulong use_mem, uint division_limit, + uint age_threshold); +extern int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + ulong use_mem, uint division_limit, + uint age_threshold); +extern void change_key_cache_param(KEY_CACHE *keycache, uint division_limit, + uint age_threshold); +extern byte *key_cache_read(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + byte *buff, uint length, + uint block_length,int return_buffer); +extern int key_cache_insert(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + byte *buff, uint length); +extern int key_cache_write(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + byte *buff, uint length, + uint block_length,int force_write); +extern int flush_key_blocks(KEY_CACHE *keycache, + int file, enum flush_type type); +extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup); + +/* Functions to handle multiple key caches */ +extern my_bool multi_keycache_init(void); +extern void multi_keycache_free(void); +extern KEY_CACHE *multi_key_cache_search(byte *key, uint length); +extern my_bool multi_key_cache_set(const byte *key, uint length, + KEY_CACHE *key_cache); +extern void multi_key_cache_change(KEY_CACHE *old_data, + KEY_CACHE *new_data); +extern int reset_key_cache_counters(const char *name, + KEY_CACHE *key_cache); +C_MODE_END +#endif /* _keycache_h */ diff --git a/code/meosdb/mysql50/libmysql.def b/code/meosdb/mysql50/libmysql.def new file mode 100644 index 0000000..09d1f6a --- /dev/null +++ b/code/meosdb/mysql50/libmysql.def @@ -0,0 +1,154 @@ +LIBRARY LIBMYSQL +VERSION 6.0 +EXPORTS + _dig_vec_lower + _dig_vec_upper + bmove_upp + delete_dynamic + free_defaults + getopt_compare_strings + getopt_ull_limit_value + handle_options + init_dynamic_array + insert_dynamic + int2str + is_prefix + list_add + list_delete + load_defaults + my_end + my_getopt_print_errors + my_init + my_malloc + my_memdup + my_no_flags_free + my_path + mysql_get_parameters + my_print_help + my_print_variables + my_realloc + my_strdup + mysql_thread_end + mysql_thread_init + myodbc_remove_escape + mysql_affected_rows + mysql_autocommit + mysql_stmt_bind_param + mysql_stmt_bind_result + mysql_change_user + mysql_character_set_name + mysql_close + mysql_commit + mysql_data_seek + mysql_debug + mysql_dump_debug_info + mysql_eof + mysql_errno + mysql_error + mysql_escape_string + mysql_hex_string + mysql_stmt_execute + mysql_stmt_fetch + mysql_stmt_fetch_column + mysql_fetch_field + mysql_fetch_field_direct + mysql_fetch_fields + mysql_fetch_lengths + mysql_fetch_row + mysql_field_count + mysql_field_seek + mysql_field_tell + mysql_free_result + mysql_get_client_info + mysql_get_host_info + mysql_get_proto_info + mysql_get_server_info + mysql_get_client_version + mysql_get_ssl_cipher + mysql_info + mysql_init + mysql_insert_id + mysql_kill + mysql_set_server_option + mysql_list_dbs + mysql_list_fields + mysql_list_processes + mysql_list_tables + mysql_more_results + mysql_next_result + mysql_num_fields + mysql_num_rows + mysql_odbc_escape_string + mysql_options + mysql_stmt_param_count + mysql_stmt_param_metadata + mysql_ping + mysql_stmt_result_metadata + mysql_query + mysql_read_query_result + mysql_real_connect + mysql_real_escape_string + mysql_real_query + mysql_refresh + mysql_rollback + mysql_row_seek + mysql_row_tell + mysql_select_db + mysql_stmt_send_long_data + mysql_send_query + mysql_shutdown + mysql_ssl_set + mysql_stat + mysql_stmt_affected_rows + mysql_stmt_close + mysql_stmt_reset + mysql_stmt_data_seek + mysql_stmt_errno + mysql_stmt_error + mysql_stmt_free_result + mysql_stmt_num_rows + mysql_stmt_row_seek + mysql_stmt_row_tell + mysql_stmt_store_result + mysql_store_result + mysql_thread_id + mysql_thread_safe + mysql_use_result + mysql_warning_count + mysql_stmt_sqlstate + mysql_sqlstate + mysql_get_server_version + set_dynamic + strcend + strcont + strdup_root + strfill + strinstr + strmake + strmov + strxmov + mysql_stmt_prepare + mysql_stmt_init + mysql_stmt_insert_id + mysql_stmt_attr_get + mysql_stmt_attr_set + mysql_stmt_field_count + client_errors + mysql_set_local_infile_default + mysql_set_local_infile_handler + mysql_disable_reads_from_master + mysql_disable_rpl_parse + mysql_enable_reads_from_master + mysql_enable_rpl_parse + mysql_master_query + mysql_rpl_parse_enabled + mysql_rpl_probe + mysql_rpl_query_type + mysql_slave_query + mysql_embedded + mysql_server_init + mysql_server_end + mysql_set_character_set + mysql_get_character_set_info + get_defaults_options + modify_defaults_file diff --git a/code/meosdb/mysql50/m_ctype.h b/code/meosdb/mysql50/m_ctype.h new file mode 100644 index 0000000..f3b9376 --- /dev/null +++ b/code/meosdb/mysql50/m_ctype.h @@ -0,0 +1,509 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + A better inplementation of the UNIX ctype(3) library. + Notes: my_global.h should be included before ctype.h +*/ + +#ifndef _m_ctype_h +#define _m_ctype_h + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MY_CS_NAME_SIZE 32 +#define MY_CS_CTYPE_TABLE_SIZE 257 +#define MY_CS_TO_LOWER_TABLE_SIZE 256 +#define MY_CS_TO_UPPER_TABLE_SIZE 256 +#define MY_CS_SORT_ORDER_TABLE_SIZE 256 +#define MY_CS_TO_UNI_TABLE_SIZE 256 + +#define CHARSET_DIR "charsets/" + +#define my_wc_t ulong + +typedef struct unicase_info_st +{ + uint16 toupper; + uint16 tolower; + uint16 sort; +} MY_UNICASE_INFO; + + +extern MY_UNICASE_INFO *my_unicase_default[256]; +extern MY_UNICASE_INFO *my_unicase_turkish[256]; + + +/* wm_wc and wc_mb return codes */ +#define MY_CS_ILSEQ 0 /* Wrong by sequence: wb_wc */ +#define MY_CS_ILUNI 0 /* Cannot encode Unicode to charset: wc_mb */ +#define MY_CS_TOOSMALL -101 /* Need at least one byte: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL2 -102 /* Need at least two bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL3 -103 /* Need at least three bytes: wc_mb and mb_wc */ +/* These following three are currently not really used */ +#define MY_CS_TOOSMALL4 -104 /* Need at least 4 bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL5 -105 /* Need at least 5 bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL6 -106 /* Need at least 6 bytes: wc_mb and mb_wc */ +/* A helper macros for "need at least n bytes" */ +#define MY_CS_TOOSMALLN(n) (-100-(n)) + +#define MY_SEQ_INTTAIL 1 +#define MY_SEQ_SPACES 2 + + /* My charsets_list flags */ +#define MY_CS_COMPILED 1 /* compiled-in sets */ +#define MY_CS_CONFIG 2 /* sets that have a *.conf file */ +#define MY_CS_INDEX 4 /* sets listed in the Index file */ +#define MY_CS_LOADED 8 /* sets that are currently loaded */ +#define MY_CS_BINSORT 16 /* if binary sort order */ +#define MY_CS_PRIMARY 32 /* if primary collation */ +#define MY_CS_STRNXFRM 64 /* if strnxfrm is used for sort */ +#define MY_CS_UNICODE 128 /* is a charset is full unicode */ +#define MY_CS_READY 256 /* if a charset is initialized */ +#define MY_CS_AVAILABLE 512 /* If either compiled-in or loaded*/ +#define MY_CS_CSSORT 1024 /* if case sensitive sort order */ +#define MY_CHARSET_UNDEFINED 0 + + +typedef struct my_uni_idx_st +{ + uint16 from; + uint16 to; + uchar *tab; +} MY_UNI_IDX; + +typedef struct +{ + uint beg; + uint end; + uint mb_len; +} my_match_t; + +enum my_lex_states +{ + MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT, + MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, + MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER, + MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, + MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, + MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, + MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON, + MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP, + MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR, + MY_LEX_IDENT_OR_KEYWORD, + MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_NCHAR, + MY_LEX_STRING_OR_DELIMITER +}; + +struct charset_info_st; + + +/* See strings/CHARSET_INFO.txt for information about this structure */ +typedef struct my_collation_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(uint)); + /* Collation routines */ + int (*strnncoll)(struct charset_info_st *, + const uchar *, uint, const uchar *, uint, my_bool); + int (*strnncollsp)(struct charset_info_st *, + const uchar *, uint, const uchar *, uint, + my_bool diff_if_only_endspace_difference); + int (*strnxfrm)(struct charset_info_st *, + uchar *, uint, const uchar *, uint); + uint (*strnxfrmlen)(struct charset_info_st *, uint); + my_bool (*like_range)(struct charset_info_st *, + const char *s, uint s_length, + pchar w_prefix, pchar w_one, pchar w_many, + uint res_length, + char *min_str, char *max_str, + uint *min_len, uint *max_len); + int (*wildcmp)(struct charset_info_st *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape,int w_one, int w_many); + + int (*strcasecmp)(struct charset_info_st *, const char *, const char *); + + uint (*instr)(struct charset_info_st *, + const char *b, uint b_length, + const char *s, uint s_length, + my_match_t *match, uint nmatch); + + /* Hash calculation */ + void (*hash_sort)(struct charset_info_st *cs, const uchar *key, uint len, + ulong *nr1, ulong *nr2); + my_bool (*propagate)(struct charset_info_st *cs, const uchar *str, uint len); +} MY_COLLATION_HANDLER; + +extern MY_COLLATION_HANDLER my_collation_mb_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler; +extern MY_COLLATION_HANDLER my_collation_ucs2_uca_handler; + + +/* See strings/CHARSET_INFO.txt about information on this structure */ +typedef struct my_charset_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(uint)); + /* Multibyte routines */ + int (*ismbchar)(struct charset_info_st *, const char *, const char *); + int (*mbcharlen)(struct charset_info_st *, uint); + uint (*numchars)(struct charset_info_st *, const char *b, const char *e); + uint (*charpos)(struct charset_info_st *, const char *b, const char *e, uint pos); + uint (*well_formed_len)(struct charset_info_st *, + const char *b,const char *e, + uint nchars, int *error); + uint (*lengthsp)(struct charset_info_st *, const char *ptr, uint length); + uint (*numcells)(struct charset_info_st *, const char *b, const char *e); + + /* Unicode convertion */ + int (*mb_wc)(struct charset_info_st *cs,my_wc_t *wc, + const unsigned char *s,const unsigned char *e); + int (*wc_mb)(struct charset_info_st *cs,my_wc_t wc, + unsigned char *s,unsigned char *e); + + /* Functions for case and sort convertion */ + uint (*caseup_str)(struct charset_info_st *, char *); + uint (*casedn_str)(struct charset_info_st *, char *); + uint (*caseup)(struct charset_info_st *, char *src, uint srclen, + char *dst, uint dstlen); + uint (*casedn)(struct charset_info_st *, char *src, uint srclen, + char *dst, uint dstlen); + + /* Charset dependant snprintf() */ + int (*snprintf)(struct charset_info_st *, char *to, uint n, const char *fmt, + ...) ATTRIBUTE_FORMAT_FPTR(printf, 4, 5); + int (*long10_to_str)(struct charset_info_st *, char *to, uint n, int radix, + long int val); + int (*longlong10_to_str)(struct charset_info_st *, char *to, uint n, + int radix, longlong val); + + void (*fill)(struct charset_info_st *, char *to, uint len, int fill); + + /* String-to-number convertion routines */ + long (*strntol)(struct charset_info_st *, const char *s, uint l, + int base, char **e, int *err); + ulong (*strntoul)(struct charset_info_st *, const char *s, uint l, + int base, char **e, int *err); + longlong (*strntoll)(struct charset_info_st *, const char *s, uint l, + int base, char **e, int *err); + ulonglong (*strntoull)(struct charset_info_st *, const char *s, uint l, + int base, char **e, int *err); + double (*strntod)(struct charset_info_st *, char *s, uint l, char **e, + int *err); + longlong (*strtoll10)(struct charset_info_st *cs, + const char *nptr, char **endptr, int *error); + ulonglong (*strntoull10rnd)(struct charset_info_st *cs, + const char *str, uint length, int unsigned_fl, + char **endptr, int *error); + ulong (*scan)(struct charset_info_st *, const char *b, const char *e, + int sq); +} MY_CHARSET_HANDLER; + +extern MY_CHARSET_HANDLER my_charset_8bit_handler; +extern MY_CHARSET_HANDLER my_charset_ucs2_handler; + + +/* See strings/CHARSET_INFO.txt about information on this structure */ +typedef struct charset_info_st +{ + uint number; + uint primary_number; + uint binary_number; + uint state; + const char *csname; + const char *name; + const char *comment; + const char *tailoring; + uchar *ctype; + uchar *to_lower; + uchar *to_upper; + uchar *sort_order; + uint16 *contractions; + uint16 **sort_order_big; + uint16 *tab_to_uni; + MY_UNI_IDX *tab_from_uni; + MY_UNICASE_INFO **caseinfo; + uchar *state_map; + uchar *ident_map; + uint strxfrm_multiply; + uchar caseup_multiply; + uchar casedn_multiply; + uint mbminlen; + uint mbmaxlen; + uint16 min_sort_char; + uint16 max_sort_char; /* For LIKE optimization */ + uchar pad_char; + my_bool escape_with_backslash_is_dangerous; + + MY_CHARSET_HANDLER *cset; + MY_COLLATION_HANDLER *coll; + +} CHARSET_INFO; + + +extern CHARSET_INFO my_charset_bin; +extern CHARSET_INFO my_charset_big5_chinese_ci; +extern CHARSET_INFO my_charset_big5_bin; +extern CHARSET_INFO my_charset_cp932_japanese_ci; +extern CHARSET_INFO my_charset_cp932_bin; +extern CHARSET_INFO my_charset_eucjpms_japanese_ci; +extern CHARSET_INFO my_charset_eucjpms_bin; +extern CHARSET_INFO my_charset_euckr_korean_ci; +extern CHARSET_INFO my_charset_euckr_bin; +extern CHARSET_INFO my_charset_gb2312_chinese_ci; +extern CHARSET_INFO my_charset_gb2312_bin; +extern CHARSET_INFO my_charset_gbk_chinese_ci; +extern CHARSET_INFO my_charset_gbk_bin; +extern CHARSET_INFO my_charset_latin1; +extern CHARSET_INFO my_charset_latin1_german2_ci; +extern CHARSET_INFO my_charset_latin1_bin; +extern CHARSET_INFO my_charset_latin2_czech_ci; +extern CHARSET_INFO my_charset_sjis_japanese_ci; +extern CHARSET_INFO my_charset_sjis_bin; +extern CHARSET_INFO my_charset_tis620_thai_ci; +extern CHARSET_INFO my_charset_tis620_bin; +extern CHARSET_INFO my_charset_ucs2_general_ci; +extern CHARSET_INFO my_charset_ucs2_bin; +extern CHARSET_INFO my_charset_ucs2_general_uca; +extern CHARSET_INFO my_charset_ujis_japanese_ci; +extern CHARSET_INFO my_charset_ujis_bin; +extern CHARSET_INFO my_charset_utf8_general_ci; +extern CHARSET_INFO my_charset_utf8_bin; +extern CHARSET_INFO my_charset_cp1250_czech_ci; + +/* declarations for simple charsets */ +extern int my_strnxfrm_simple(CHARSET_INFO *, uchar *, uint, const uchar *, + uint); +uint my_strnxfrmlen_simple(CHARSET_INFO *, uint); +extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, uint, + const uchar *, uint, my_bool); + +extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, uint, + const uchar *, uint, + my_bool diff_if_only_endspace_difference); + +extern void my_hash_sort_simple(CHARSET_INFO *cs, + const uchar *key, uint len, + ulong *nr1, ulong *nr2); + +extern uint my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, uint length); + +extern uint my_instr_simple(struct charset_info_st *, + const char *b, uint b_length, + const char *s, uint s_length, + my_match_t *match, uint nmatch); + + +/* Functions for 8bit */ +extern uint my_caseup_str_8bit(CHARSET_INFO *, char *); +extern uint my_casedn_str_8bit(CHARSET_INFO *, char *); +extern uint my_caseup_8bit(CHARSET_INFO *, char *src, uint srclen, + char *dst, uint dstlen); +extern uint my_casedn_8bit(CHARSET_INFO *, char *src, uint srclen, + char *dst, uint dstlen); + +extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *); + +int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e); +int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); + +ulong my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq); + +int my_snprintf_8bit(struct charset_info_st *, char *to, uint n, + const char *fmt, ...) + ATTRIBUTE_FORMAT(printf, 4, 5); + +long my_strntol_8bit(CHARSET_INFO *, const char *s, uint l, int base, + char **e, int *err); +ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, uint l, int base, + char **e, int *err); +longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, uint l, int base, + char **e, int *err); +ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, uint l, int base, + char **e, int *err); +double my_strntod_8bit(CHARSET_INFO *, char *s, uint l,char **e, + int *err); +int my_long10_to_str_8bit(CHARSET_INFO *, char *to, uint l, int radix, + long int val); +int my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, uint l, int radix, + longlong val); + +longlong my_strtoll10_8bit(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); +longlong my_strtoll10_ucs2(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); + +ulonglong my_strntoull10rnd_8bit(CHARSET_INFO *cs, + const char *str, uint length, int unsigned_fl, + char **endptr, int *error); +ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs, + const char *str, uint length, int unsigned_fl, + char **endptr, int *error); + +void my_fill_8bit(CHARSET_INFO *cs, char* to, uint l, int fill); + +my_bool my_like_range_simple(CHARSET_INFO *cs, + const char *ptr, uint ptr_length, + pbool escape, pbool w_one, pbool w_many, + uint res_length, + char *min_str, char *max_str, + uint *min_length, uint *max_length); + +my_bool my_like_range_mb(CHARSET_INFO *cs, + const char *ptr, uint ptr_length, + pbool escape, pbool w_one, pbool w_many, + uint res_length, + char *min_str, char *max_str, + uint *min_length, uint *max_length); + +my_bool my_like_range_ucs2(CHARSET_INFO *cs, + const char *ptr, uint ptr_length, + pbool escape, pbool w_one, pbool w_many, + uint res_length, + char *min_str, char *max_str, + uint *min_length, uint *max_length); + + +int my_wildcmp_8bit(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +int my_wildcmp_bin(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +uint my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); +uint my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e); +uint my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, uint pos); +uint my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e, + uint pos, int *error); +int my_mbcharlen_8bit(CHARSET_INFO *, uint c); + + +/* Functions for multibyte charsets */ +extern uint my_caseup_str_mb(CHARSET_INFO *, char *); +extern uint my_casedn_str_mb(CHARSET_INFO *, char *); +extern uint my_caseup_mb(CHARSET_INFO *, char *src, uint srclen, + char *dst, uint dstlen); +extern uint my_casedn_mb(CHARSET_INFO *, char *src, uint srclen, + char *dst, uint dstlen); +extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *); + +int my_wildcmp_mb(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); +uint my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); +uint my_numcells_mb(CHARSET_INFO *, const char *b, const char *e); +uint my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, uint pos); +uint my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e, + uint pos, int *error); +uint my_instr_mb(struct charset_info_st *, + const char *b, uint b_length, + const char *s, uint s_length, + my_match_t *match, uint nmatch); + +int my_wildcmp_unicode(CHARSET_INFO *cs, + const char *str, const char *str_end, + const char *wildstr, const char *wildend, + int escape, int w_one, int w_many, + MY_UNICASE_INFO **weights); + +extern my_bool my_parse_charset_xml(const char *bug, uint len, + int (*add)(CHARSET_INFO *cs)); + +my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, uint len); +my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, uint len); + + +#define _MY_U 01 /* Upper case */ +#define _MY_L 02 /* Lower case */ +#define _MY_NMR 04 /* Numeral (digit) */ +#define _MY_SPC 010 /* Spacing character */ +#define _MY_PNT 020 /* Punctuation */ +#define _MY_CTR 040 /* Control character */ +#define _MY_B 0100 /* Blank */ +#define _MY_X 0200 /* heXadecimal digit */ + + +#define my_isascii(c) (!((c) & ~0177)) +#define my_toascii(c) ((c) & 0177) +#define my_tocntrl(c) ((c) & 31) +#define my_toprint(c) ((c) | 64) +#define my_toupper(s,c) (char) ((s)->to_upper[(uchar) (c)]) +#define my_tolower(s,c) (char) ((s)->to_lower[(uchar) (c)]) +#define my_isalpha(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_U | _MY_L)) +#define my_isupper(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_U) +#define my_islower(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_L) +#define my_isdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_NMR) +#define my_isxdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_X) +#define my_isalnum(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_U | _MY_L | _MY_NMR)) +#define my_isspace(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_SPC) +#define my_ispunct(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_PNT) +#define my_isprint(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR | _MY_B)) +#define my_isgraph(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR)) +#define my_iscntrl(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_CTR) + +/* Some macros that should be cleaned up a little */ +#define my_isvar(s,c) (my_isalnum(s,c) || (c) == '_') +#define my_isvar_start(s,c) (my_isalpha(s,c) || (c) == '_') + +#define my_binary_compare(s) ((s)->state & MY_CS_BINSORT) +#define use_strnxfrm(s) ((s)->state & MY_CS_STRNXFRM) +#define my_strnxfrm(s, a, b, c, d) ((s)->coll->strnxfrm((s), (a), (b), (c), (d))) +#define my_strnncoll(s, a, b, c, d) ((s)->coll->strnncoll((s), (a), (b), (c), (d), 0)) +#define my_like_range(s, a, b, c, d, e, f, g, h, i, j) \ + ((s)->coll->like_range((s), (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))) +#define my_wildcmp(cs,s,se,w,we,e,o,m) ((cs)->coll->wildcmp((cs),(s),(se),(w),(we),(e),(o),(m))) +#define my_strcasecmp(s, a, b) ((s)->coll->strcasecmp((s), (a), (b))) +#define my_charpos(cs, b, e, num) (cs)->cset->charpos((cs), (const char*) (b), (const char *)(e), (num)) + + +#define use_mb(s) ((s)->cset->ismbchar != NULL) +#define my_ismbchar(s, a, b) ((s)->cset->ismbchar((s), (a), (b))) +#ifdef USE_MB +#define my_mbcharlen(s, a) ((s)->cset->mbcharlen((s),(a))) +#else +#define my_mbcharlen(s, a) 1 +#endif + +#define my_caseup_str(s, a) ((s)->cset->caseup_str((s), (a))) +#define my_casedn_str(s, a) ((s)->cset->casedn_str((s), (a))) +#define my_strntol(s, a, b, c, d, e) ((s)->cset->strntol((s),(a),(b),(c),(d),(e))) +#define my_strntoul(s, a, b, c, d, e) ((s)->cset->strntoul((s),(a),(b),(c),(d),(e))) +#define my_strntoll(s, a, b, c, d, e) ((s)->cset->strntoll((s),(a),(b),(c),(d),(e))) +#define my_strntoull(s, a, b, c,d, e) ((s)->cset->strntoull((s),(a),(b),(c),(d),(e))) +#define my_strntod(s, a, b, c, d) ((s)->cset->strntod((s),(a),(b),(c),(d))) + + +/* XXX: still need to take care of this one */ +#ifdef MY_CHARSET_TIS620 +#error The TIS620 charset is broken at the moment. Tell tim to fix it. +#define USE_TIS620 +#include "t_ctype.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _m_ctype_h */ diff --git a/code/meosdb/mysql50/m_string.h b/code/meosdb/mysql50/m_string.h new file mode 100644 index 0000000..e25e368 --- /dev/null +++ b/code/meosdb/mysql50/m_string.h @@ -0,0 +1,265 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* There may be prolems include all of theese. Try to test in + configure with ones are needed? */ + +/* This is needed for the definitions of strchr... on solaris */ + +#ifndef _m_string_h +#define _m_string_h +#ifndef __USE_GNU +#define __USE_GNU /* We want to use stpcpy */ +#endif +#if defined(HAVE_STRINGS_H) +#include +#endif +#if defined(HAVE_STRING_H) +#include +#endif + +/* need by my_vsnprintf */ +#include + +/* Correct some things for UNIXWARE7 */ +#ifdef HAVE_UNIXWARE7_THREADS +#undef HAVE_STRINGS_H +#undef HAVE_MEMORY_H +#define HAVE_MEMCPY +#ifndef HAVE_MEMMOVE +#define HAVE_MEMMOVE +#endif +#undef HAVE_BCMP +#undef bcopy +#undef bcmp +#undef bzero +#endif /* HAVE_UNIXWARE7_THREADS */ +#ifdef _AIX +#undef HAVE_BCMP +#endif + +/* This is needed for the definitions of bzero... on solaris */ +#if defined(HAVE_STRINGS_H) && !defined(HAVE_mit_thread) +#include +#endif + +/* This is needed for the definitions of memcpy... on solaris */ +#if defined(HAVE_MEMORY_H) && !defined(__cplusplus) +#include +#endif + +#if !defined(HAVE_MEMCPY) && !defined(HAVE_MEMMOVE) +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define memset(A,C,B) bfill((A),(B),(C)) +# define memmove(d, s, n) bmove ((d), (s), (n)) +#elif defined(HAVE_MEMMOVE) +# define bmove(d, s, n) memmove((d), (s), (n)) +#else +# define memmove(d, s, n) bmove((d), (s), (n)) /* our bmove */ +#endif + +/* Unixware 7 */ +#if !defined(HAVE_BFILL) +# define bfill(A,B,C) memset((A),(C),(B)) +# define bmove_align(A,B,C) memcpy((A),(B),(C)) +#endif + +#if !defined(HAVE_BCMP) +# define bcopy(s, d, n) memcpy((d), (s), (n)) +# define bcmp(A,B,C) memcmp((A),(B),(C)) +# define bzero(A,B) memset((A),0,(B)) +# define bmove_align(A,B,C) memcpy((A),(B),(C)) +#endif + +#if defined(__cplusplus) && !defined(OS2) +extern "C" { +#endif + +/* + my_str_malloc() and my_str_free() are assigned to implementations in + strings/alloc.c, but can be overridden in the calling program. + */ +extern void *(*my_str_malloc)(size_t); +extern void (*my_str_free)(void *); + +#if defined(HAVE_STPCPY) && !defined(HAVE_mit_thread) +#define strmov(A,B) stpcpy((A),(B)) +#ifndef stpcpy +extern char *stpcpy(char *, const char *); /* For AIX with gcc 2.95.3 */ +#endif +#endif + +/* Declared in int2str() */ +extern char NEAR _dig_vec_upper[]; +extern char NEAR _dig_vec_lower[]; + +/* Defined in strtod.c */ +extern const double log_10[309]; + +#ifdef BAD_STRING_COMPILER +#define strmov(A,B) (memccpy(A,B,0,INT_MAX)-1) +#else +#define strmov_overlapp(A,B) strmov(A,B) +#define strmake_overlapp(A,B,C) strmake(A,B,C) +#endif + +#ifdef BAD_MEMCPY /* Problem with gcc on Alpha */ +#define memcpy_fixed(A,B,C) bmove((A),(B),(C)) +#else +#define memcpy_fixed(A,B,C) memcpy((A),(B),(C)) +#endif + +#ifdef MSDOS +#undef bmove_align +#define bmove512(A,B,C) bmove_align(A,B,C) +extern void bmove_align(gptr dst,const gptr src,uint len); +#endif + +#if (!defined(USE_BMOVE512) || defined(HAVE_purify)) && !defined(bmove512) +#define bmove512(A,B,C) memcpy(A,B,C) +#endif + + /* Prototypes for string functions */ + +#if !defined(bfill) && !defined(HAVE_BFILL) +extern void bfill(gptr dst,uint len,pchar fill); +#endif + +#if !defined(bzero) && !defined(HAVE_BZERO) +extern void bzero(gptr dst,uint len); +#endif + +#if !defined(bcmp) && !defined(HAVE_BCMP) +extern int bcmp(const char *s1,const char *s2,uint len); +#endif +#ifdef HAVE_purify +extern int my_bcmp(const char *s1,const char *s2,uint len); +#undef bcmp +#define bcmp(A,B,C) my_bcmp((A),(B),(C)) +#endif + +#ifndef bmove512 +extern void bmove512(gptr dst,const gptr src,uint len); +#endif + +#if !defined(HAVE_BMOVE) && !defined(bmove) +extern void bmove(char *dst, const char *src,uint len); +#endif + +extern void bmove_upp(char *dst,const char *src,uint len); +extern void bchange(char *dst,uint old_len,const char *src, + uint new_len,uint tot_len); +extern void strappend(char *s,uint len,pchar fill); +extern char *strend(const char *s); +extern char *strcend(const char *, pchar); +extern char *strfield(char *src,int fields,int chars,int blanks, + int tabch); +extern char *strfill(my_string s,uint len,pchar fill); +extern uint strinstr(const char *str,const char *search); +extern uint r_strinstr(reg1 my_string str,int from, reg4 my_string search); +extern char *strkey(char *dst,char *head,char *tail,char *flags); +extern char *strmake(char *dst,const char *src,uint length); +#ifndef strmake_overlapp +extern char *strmake_overlapp(char *dst,const char *src, uint length); +#endif + +#ifndef strmov +extern char *strmov(char *dst,const char *src); +#endif +extern char *strnmov(char *dst,const char *src,uint n); +extern char *strsuff(const char *src,const char *suffix); +extern char *strcont(const char *src,const char *set); +extern char *strxcat _VARARGS((char *dst,const char *src, ...)); +extern char *strxmov _VARARGS((char *dst,const char *src, ...)); +extern char *strxcpy _VARARGS((char *dst,const char *src, ...)); +extern char *strxncat _VARARGS((char *dst,uint len, const char *src, ...)); +extern char *strxnmov _VARARGS((char *dst,uint len, const char *src, ...)); +extern char *strxncpy _VARARGS((char *dst,uint len, const char *src, ...)); + +/* Prototypes of normal stringfunctions (with may ours) */ + +#ifdef WANT_STRING_PROTOTYPES +extern char *strcat(char *, const char *); +extern char *strchr(const char *, pchar); +extern char *strrchr(const char *, pchar); +extern char *strcpy(char *, const char *); +extern int strcmp(const char *, const char *); +#ifndef __GNUC__ +extern size_t strlen(const char *); +#endif +#endif +#ifndef HAVE_STRNLEN +extern uint strnlen(const char *s, uint n); +#endif + +#if !defined(__cplusplus) +#ifndef HAVE_STRPBRK +extern char *strpbrk(const char *, const char *); +#endif +#ifndef HAVE_STRSTR +extern char *strstr(const char *, const char *); +#endif +#endif +extern int is_prefix(const char *, const char *); + +/* Conversion routines */ +double my_strtod(const char *str, char **end, int *error); +double my_atof(const char *nptr); + +extern char *llstr(longlong value,char *buff); +#ifndef HAVE_STRTOUL +extern long strtol(const char *str, char **ptr, int base); +extern ulong strtoul(const char *str, char **ptr, int base); +#endif + +extern char *int2str(long val, char *dst, int radix, int upcase); +extern char *int10_to_str(long val,char *dst,int radix); +extern char *str2int(const char *src,int radix,long lower,long upper, + long *val); +longlong my_strtoll10(const char *nptr, char **endptr, int *error); +#if SIZEOF_LONG == SIZEOF_LONG_LONG +#define longlong2str(A,B,C) int2str((A),(B),(C),1) +#define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C)) +#undef strtoll +#define strtoll(A,B,C) strtol((A),(B),(C)) +#define strtoull(A,B,C) strtoul((A),(B),(C)) +#ifndef HAVE_STRTOULL +#define HAVE_STRTOULL +#endif +#ifndef HAVE_STRTOLL +#define HAVE_STRTOLL +#endif +#else +#ifdef HAVE_LONG_LONG +extern char *longlong2str(longlong val,char *dst,int radix); +extern char *longlong10_to_str(longlong val,char *dst,int radix); +#if (!defined(HAVE_STRTOULL) || defined(HAVE_mit_thread)) || defined(NO_STRTOLL_PROTO) +extern longlong strtoll(const char *str, char **ptr, int base); +extern ulonglong strtoull(const char *str, char **ptr, int base); +#endif +#endif +#endif + +/* my_vsnprintf.c */ + +extern int my_vsnprintf( char *str, size_t n, + const char *format, va_list ap ); +extern int my_snprintf(char *to, size_t n, const char *fmt, ...) + ATTRIBUTE_FORMAT(printf, 3, 4); + +#if defined(__cplusplus) && !defined(OS2) +} +#endif +#endif diff --git a/code/meosdb/mysql50/my_alloc.h b/code/meosdb/mysql50/my_alloc.h new file mode 100644 index 0000000..5baecc9 --- /dev/null +++ b/code/meosdb/mysql50/my_alloc.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + Data structures for mysys/my_alloc.c (root memory allocator) +*/ + +#ifndef _my_alloc_h +#define _my_alloc_h + +#define ALLOC_MAX_BLOCK_TO_DROP 4096 +#define ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP 10 + +typedef struct st_used_mem +{ /* struct for once_alloc (block) */ + struct st_used_mem *next; /* Next block in use */ + unsigned int left; /* memory left in block */ + unsigned int size; /* size of block */ +} USED_MEM; + + +typedef struct st_mem_root +{ + USED_MEM *free; /* blocks with free memory in it */ + USED_MEM *used; /* blocks almost without free memory */ + USED_MEM *pre_alloc; /* preallocated block */ + /* if block have less memory it will be put in 'used' list */ + unsigned int min_malloc; + unsigned int block_size; /* initial block size */ + unsigned int block_num; /* allocated blocks counter */ + /* + first free block in queue test counter (if it exceed + MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) + */ + unsigned int first_block_usage; + + void (*error_handler)(void); +} MEM_ROOT; +#endif diff --git a/code/meosdb/mysql50/my_attribute.h b/code/meosdb/mysql50/my_attribute.h new file mode 100644 index 0000000..fea689a --- /dev/null +++ b/code/meosdb/mysql50/my_attribute.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + Helper macros used for setting different __attributes__ + on functions in a portable fashion +*/ + +#ifndef _my_attribute_h +#define _my_attribute_h + +/* + Disable __attribute__() on gcc < 2.7, g++ < 3.4, and non-gcc compilers. + Some forms of __attribute__ are actually supported in earlier versions of + g++, but we just disable them all because we only use them to generate + compilation warnings. +*/ +#ifndef __attribute__ +# if !defined(__GNUC__) +# define __attribute__(A) +# elif GCC_VERSION < 2008 +# define __attribute__(A) +# elif defined(__cplusplus) && GCC_VERSION < 3004 +# define __attribute__(A) +# endif +#endif + +/* + __attribute__((format(...))) is only supported in gcc >= 2.8 and g++ >= 3.4 + But that's already covered by the __attribute__ tests above, so this is + just a convenience macro. +*/ +#ifndef ATTRIBUTE_FORMAT +# define ATTRIBUTE_FORMAT(style, m, n) __attribute__((format(style, m, n))) +#endif + +/* + + __attribute__((format(...))) on a function pointer is not supported + until gcc 3.1 +*/ +#ifndef ATTRIBUTE_FORMAT_FPTR +# if (GCC_VERSION >= 3001) +# define ATTRIBUTE_FORMAT_FPTR(style, m, n) ATTRIBUTE_FORMAT(style, m, n) +# else +# define ATTRIBUTE_FORMAT_FPTR(style, m, n) +# endif /* GNUC >= 3.1 */ +#endif + + +#endif diff --git a/code/meosdb/mysql50/my_dbug.h b/code/meosdb/mysql50/my_dbug.h new file mode 100644 index 0000000..b9bca43 --- /dev/null +++ b/code/meosdb/mysql50/my_dbug.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _dbug_h +#define _dbug_h + +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(DBUG_OFF) && !defined(_lint) +extern int _db_on_,_no_db_; +extern FILE *_db_fp_; +extern char *_db_process_; +extern int _db_keyword_(const char *keyword); +extern int _db_strict_keyword_(const char *keyword); +extern void _db_setjmp_(void); +extern void _db_longjmp_(void); +extern void _db_push_(const char *control); +extern void _db_pop_(void); +extern void _db_enter_(const char *_func_,const char *_file_,uint _line_, + const char **_sfunc_,const char **_sfile_, + uint *_slevel_, char ***); +extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_, + uint *_slevel_); +extern void _db_pargs_(uint _line_,const char *keyword); +extern void _db_doprnt_ _VARARGS((const char *format,...)) + ATTRIBUTE_FORMAT(printf, 1, 2); +extern void _db_dump_(uint _line_,const char *keyword,const char *memory, + uint length); +extern void _db_output_(uint flag); +extern void _db_end_(void); +extern void _db_lock_file(void); +extern void _db_unlock_file(void); + +#define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \ + char **_db_framep_; \ + _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \ + &_db_framep_) +#define DBUG_LEAVE \ + (_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_)) +#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) +#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) +#define DBUG_EXECUTE(keyword,a1) \ + do {if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}} while(0) +#define DBUG_PRINT(keyword,arglist) \ + do {if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}} while(0) +#define DBUG_PUSH(a1) _db_push_ (a1) +#define DBUG_POP() _db_pop_ () +#define DBUG_PROCESS(a1) (_db_process_ = a1) +#define DBUG_FILE (_db_fp_) +#define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) +#define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) +#define DBUG_DUMP(keyword,a1,a2)\ + do {if (_db_on_) {_db_dump_(__LINE__,keyword,a1,a2);}} while(0) +#define DBUG_IN_USE (_db_fp_ && _db_fp_ != stderr) +#define DEBUGGER_OFF _no_db_=1;_db_on_=0; +#define DEBUGGER_ON _no_db_=0 +#define DBUG_END() _db_end_ () +#define DBUG_LOCK_FILE { _db_lock_file(); } +#define DBUG_UNLOCK_FILE { _db_unlock_file(); } +#define DBUG_OUTPUT(A) { _db_output_(A); } +#define DBUG_ASSERT(A) assert(A) +#define DBUG_EXECUTE_IF(keyword,a1) \ + do {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}} while(0) +#define IF_DBUG(A) A +#else /* No debugger */ + +#define DBUG_ENTER(a1) +#define DBUG_RETURN(a1) return(a1) +#define DBUG_VOID_RETURN return +#define DBUG_EXECUTE(keyword,a1) {} +#define DBUG_EXECUTE_IF(keyword,a1) {} +#define DBUG_PRINT(keyword,arglist) {} +#define DBUG_PUSH(a1) {} +#define DBUG_POP() {} +#define DBUG_PROCESS(a1) {} +#define DBUG_FILE (stderr) +#define DBUG_SETJMP setjmp +#define DBUG_LONGJMP longjmp +#define DBUG_DUMP(keyword,a1,a2) {} +#define DBUG_IN_USE 0 +#define DEBUGGER_OFF +#define DEBUGGER_ON +#define DBUG_END() +#define DBUG_LOCK_FILE +#define DBUG_UNLOCK_FILE +#define DBUG_OUTPUT(A) +#define DBUG_ASSERT(A) {} +#define DBUG_LEAVE +#define IF_DBUG(A) +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/meosdb/mysql50/my_dir.h b/code/meosdb/mysql50/my_dir.h new file mode 100644 index 0000000..f50002d --- /dev/null +++ b/code/meosdb/mysql50/my_dir.h @@ -0,0 +1,105 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_dir_h +#define _my_dir_h +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MY_DIR_H +#define MY_DIR_H + +#include + + /* Defines for my_dir and my_stat */ + +#define MY_S_IFMT S_IFMT /* type of file */ +#define MY_S_IFDIR S_IFDIR /* directory */ +#define MY_S_IFCHR S_IFCHR /* character special */ +#define MY_S_IFBLK S_IFBLK /* block special */ +#define MY_S_IFREG S_IFREG /* regular */ +#define MY_S_IFIFO S_IFIFO /* fifo */ +#define MY_S_ISUID S_ISUID /* set user id on execution */ +#define MY_S_ISGID S_ISGID /* set group id on execution */ +#define MY_S_ISVTX S_ISVTX /* save swapped text even after use */ +#define MY_S_IREAD S_IREAD /* read permission, owner */ +#define MY_S_IWRITE S_IWRITE /* write permission, owner */ +#define MY_S_IEXEC S_IEXEC /* execute/search permission, owner */ + +#define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR) +#define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR) +#define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK) +#define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG) +#define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO) + +#define MY_DONT_SORT 512 /* my_lib; Don't sort files */ +#define MY_WANT_STAT 1024 /* my_lib; stat files */ + + /* typedefs for my_dir & my_stat */ + +#ifdef USE_MY_STAT_STRUCT + +typedef struct my_stat +{ + dev_t st_dev; /* major & minor device numbers */ + ino_t st_ino; /* inode number */ + ushort st_mode; /* file permissons (& suid sgid .. bits) */ + short st_nlink; /* number of links to file */ + ushort st_uid; /* user id */ + ushort st_gid; /* group id */ + dev_t st_rdev; /* more major & minor device numbers (???) */ + off_t st_size; /* size of file */ + time_t st_atime; /* time for last read */ + time_t st_mtime; /* time for last contens modify */ + time_t st_ctime; /* time for last inode or contents modify */ +} MY_STAT; + +#else + +#define MY_STAT struct stat /* Orginal struct have what we need */ + +#endif /* USE_MY_STAT_STRUCT */ + +/* Struct describing one file returned from my_dir */ +typedef struct fileinfo +{ + char *name; + MY_STAT *mystat; +} FILEINFO; + +typedef struct st_my_dir /* Struct returned from my_dir */ +{ + /* + These members are just copies of parts of DYNAMIC_ARRAY structure, + which is allocated right after the end of MY_DIR structure (MEM_ROOT + for storing names is also resides there). We've left them here because + we don't want to change code that uses my_dir. + */ + struct fileinfo *dir_entry; + uint number_off_files; +} MY_DIR; + +extern MY_DIR *my_dir(const char *path,myf MyFlags); +extern void my_dirend(MY_DIR *buffer); +extern MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags); +extern int my_fstat(int filenr, MY_STAT *stat_area, myf MyFlags); + +#endif /* MY_DIR_H */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/meosdb/mysql50/my_getopt.h b/code/meosdb/mysql50/my_getopt.h new file mode 100644 index 0000000..322860a --- /dev/null +++ b/code/meosdb/mysql50/my_getopt.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2002-2004 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_getopt_h +#define _my_getopt_h + +C_MODE_START + +#define GET_NO_ARG 1 +#define GET_BOOL 2 +#define GET_INT 3 +#define GET_UINT 4 +#define GET_LONG 5 +#define GET_ULONG 6 +#define GET_LL 7 +#define GET_ULL 8 +#define GET_STR 9 +#define GET_STR_ALLOC 10 +#define GET_DISABLED 11 + +#define GET_ASK_ADDR 128 +#define GET_TYPE_MASK 127 + +enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG }; + +struct my_option +{ + const char *name; /* Name of the option */ + int id; /* unique id or short option */ + const char *comment; /* option comment, for autom. --help */ + gptr *value; /* The variable value */ + gptr *u_max_value; /* The user def. max variable value */ + const char **str_values; /* Pointer to possible values */ + ulong var_type; + enum get_opt_arg_type arg_type; + longlong def_value; /* Default value */ + longlong min_value; /* Min allowed value */ + longlong max_value; /* Max allowed value */ + longlong sub_size; /* Subtract this from given value */ + long block_size; /* Value should be a mult. of this */ + int app_type; /* To be used by an application */ +}; + +typedef my_bool (* my_get_one_option) (int, const struct my_option *, char * ); +typedef void (* my_error_reporter) (enum loglevel level, const char *format, ... ); + +extern char *disabled_my_option; +extern my_bool my_getopt_print_errors; +extern my_error_reporter my_getopt_error_reporter; + +extern int handle_options (int *argc, char ***argv, + const struct my_option *longopts, my_get_one_option); +extern void my_print_help(const struct my_option *options); +extern void my_print_variables(const struct my_option *options); +extern void my_getopt_register_get_addr(gptr* (*func_addr)(const char *, uint, + const struct my_option *)); + +ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp); +my_bool getopt_compare_strings(const char *s, const char *t, uint length); + +C_MODE_END + +#endif /* _my_getopt_h */ + diff --git a/code/meosdb/mysql50/my_global.h b/code/meosdb/mysql50/my_global.h new file mode 100644 index 0000000..e45605f --- /dev/null +++ b/code/meosdb/mysql50/my_global.h @@ -0,0 +1,1352 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* This is the include file that should be included 'first' in every C file. */ + +#ifndef _global_h +#define _global_h + +#ifndef EMBEDDED_LIBRARY +#define HAVE_REPLICATION +#define HAVE_EXTERNAL_CLIENT +#endif + +#if defined( __EMX__) && !defined( MYSQL_SERVER) +/* moved here to use below VOID macro redefinition */ +#define INCL_BASE +#define INCL_NOPMAPI +#include +#endif /* __EMX__ */ + +#ifdef __CYGWIN__ +/* We use a Unix API, so pretend it's not Windows */ +#undef WIN +#undef WIN32 +#undef _WIN +#undef _WIN32 +#undef _WIN64 +#undef __WIN__ +#undef __WIN32__ +#define HAVE_ERRNO_AS_DEFINE +#endif /* __CYGWIN__ */ + +#if defined(__QNXNTO__) && !defined(FD_SETSIZE) +#define FD_SETSIZE 1024 /* Max number of file descriptor bits in + fd_set, used when calling 'select' + Must be defined before including + "sys/select.h" and "sys/time.h" + */ +#endif + + +/* to make command line shorter we'll define USE_PRAGMA_INTERFACE here */ +#ifdef USE_PRAGMA_IMPLEMENTATION +#define USE_PRAGMA_INTERFACE +#endif + +#if defined(i386) && !defined(__i386__) +#define __i386__ +#endif + +/* Macros to make switching between C and C++ mode easier */ +#ifdef __cplusplus +#define C_MODE_START extern "C" { +#define C_MODE_END } +#else +#define C_MODE_START +#define C_MODE_END +#endif + +#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) +#include +#elif defined(OS2) +#include +#elif defined(__NETWARE__) +#include +#include +#if defined(__cplusplus) && defined(inline) +#undef inline /* fix configure problem */ +#endif +#else +#include +#if defined(__cplusplus) && defined(inline) +#undef inline /* fix configure problem */ +#endif +#endif /* _WIN32... */ + +/* Make it easier to add conditionl code for windows */ +#ifdef __WIN__ +#define IF_WIN(A,B) (A) +#else +#define IF_WIN(A,B) (B) +#endif + + +/* Some defines to avoid ifdefs in the code */ +#ifndef NETWARE_YIELD +#define NETWARE_YIELD +#define NETWARE_SET_SCREEN_MODE(A) +#endif + +/* + The macros below are used to allow build of Universal/fat binaries of + MySQL and MySQL applications under darwin. +*/ +#ifdef TARGET_FAT_BINARY +# undef SIZEOF_CHARP +# undef SIZEOF_INT +# undef SIZEOF_LONG +# undef SIZEOF_LONG_LONG +# undef SIZEOF_OFF_T +# undef SIZEOF_SHORT + +#if defined(__i386__) +# undef WORDS_BIGENDIAN +# define SIZEOF_CHARP 4 +# define SIZEOF_INT 4 +# define SIZEOF_LONG 4 +# define SIZEOF_LONG_LONG 8 +# define SIZEOF_OFF_T 8 +# define SIZEOF_SHORT 2 + +#elif defined(__ppc__) +# define WORDS_BIGENDIAN +# define SIZEOF_CHARP 4 +# define SIZEOF_INT 4 +# define SIZEOF_LONG 4 +# define SIZEOF_LONG_LONG 8 +# define SIZEOF_OFF_T 8 +# define SIZEOF_SHORT 2 + +#else +# error Building FAT binary for an unknown architecture. +#endif +#endif /* TARGET_FAT_BINARY */ + + +/* + The macros below are borrowed from include/linux/compiler.h in the + Linux kernel. Use them to indicate the likelyhood of the truthfulness + of a condition. This serves two purposes - newer versions of gcc will be + able to optimize for branch predication, which could yield siginficant + performance gains in frequently executed sections of the code, and the + other reason to use them is for documentation +*/ + +#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) +#define __builtin_expect(x, expected_value) (x) +#endif + +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + + +/* Fix problem with S_ISLNK() on Linux */ +#if defined(TARGET_OS_LINUX) || defined(__GLIBC__) +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +/* + Temporary solution to solve bug#7156. Include "sys/types.h" before + the thread headers, else the function madvise() will not be defined +*/ +#if defined(HAVE_SYS_TYPES_H) && ( defined(sun) || defined(__sun) ) +#include +#endif + +/* The client defines this to avoid all thread code */ +#if defined(UNDEF_THREADS_HACK) +#undef THREAD +#undef HAVE_mit_thread +#undef HAVE_LINUXTHREADS +#undef HAVE_NPTL +#undef HAVE_UNIXWARE7_THREADS +#endif + +#ifdef HAVE_THREADS_WITHOUT_SOCKETS +/* MIT pthreads does not work with unix sockets */ +#undef HAVE_SYS_UN_H +#endif + +#define __EXTENSIONS__ 1 /* We want some extension */ +#ifndef __STDC_EXT__ +#define __STDC_EXT__ 1 /* To get large file support on hpux */ +#endif + +/* + Solaris 9 include file refers to X/Open document + + System Interfaces and Headers, Issue 5 + + saying we should define _XOPEN_SOURCE=500 to get POSIX.1c prototypes, + but apparently other systems (namely FreeBSD) don't agree. + + On a newer Solaris 10, the above file recognizes also _XOPEN_SOURCE=600. + Furthermore, it tests that if a program requires older standard + (_XOPEN_SOURCE<600 or _POSIX_C_SOURCE<200112L) it cannot be + run on a new compiler (that defines _STDC_C99) and issues an #error. + It's also an #error if a program requires new standard (_XOPEN_SOURCE=600 + or _POSIX_C_SOURCE=200112L) and a compiler does not define _STDC_C99. + + To add more to this mess, Sun Studio C compiler defines _STDC_C99 while + C++ compiler does not! + + So, in a desperate attempt to get correct prototypes for both + C and C++ code, we define either _XOPEN_SOURCE=600 or _XOPEN_SOURCE=500 + depending on the compiler's announced C standard support. + + Cleaner solutions are welcome. +*/ +#ifdef __sun +#if __STDC_VERSION__ - 0 >= 199901L +#define _XOPEN_SOURCE 600 +#else +#define _XOPEN_SOURCE 500 +#endif +#endif + +#if defined(THREAD) && !defined(__WIN__) && !defined(OS2) +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */ +#endif + +#if !defined(SCO) +#define _REENTRANT 1 /* Some thread libraries require this */ +#endif +#if !defined(_THREAD_SAFE) && !defined(_AIX) +#define _THREAD_SAFE /* Required for OSF1 */ +#endif +#ifndef HAVE_mit_thread +#ifdef HAVE_UNIXWARE7_THREADS +#include +#else +#if defined(HPUX10) || defined(HPUX11) +C_MODE_START /* HPUX needs this, signal.h bug */ +#include +C_MODE_END +#else +#include /* AIX must have this included first */ +#endif +#endif /* HAVE_UNIXWARE7_THREADS */ +#endif /* HAVE_mit_thread */ +#if !defined(SCO) && !defined(_REENTRANT) +#define _REENTRANT 1 /* Threads requires reentrant code */ +#endif +#endif /* THREAD */ + +/* Go around some bugs in different OS and compilers */ +#ifdef _AIX /* By soren@t.dk */ +#define _H_STRINGS +#define _SYS_STREAM_H +/* #define _AIX32_CURSES */ /* XXX: this breaks AIX 4.3.3 (others?). */ +#define ulonglong2double(A) my_ulonglong2double(A) +#define my_off_t2double(A) my_ulonglong2double(A) +C_MODE_START +double my_ulonglong2double(unsigned long long A); +C_MODE_END +#endif /* _AIX */ + +#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */ +#undef HAVE_SNPRINTF +#endif +#ifdef HAVE_BROKEN_PREAD +/* + pread()/pwrite() are not 64 bit safe on HP-UX 11.0 without + installing the kernel patch PHKL_20349 or greater +*/ +#undef HAVE_PREAD +#undef HAVE_PWRITE +#endif +#if defined(HAVE_BROKEN_INLINE) && !defined(__cplusplus) +#undef inline +#define inline +#endif + +#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */ +#undef HAVE_GETHOSTBYNAME_R +#endif +#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */ +#undef HAVE_INITGROUPS +#endif + +/* gcc/egcs issues */ + +#if defined(__GNUC) && defined(__EXCEPTIONS) +#error "Please add -fno-exceptions to CXXFLAGS and reconfigure/recompile" +#endif + + +/* Fix a bug in gcc 2.8.0 on IRIX 6.2 */ +#if SIZEOF_LONG == 4 && defined(__LONG_MAX__) && (__GNUC__ == 2 && __GNUC_MINOR__ == 8) +#undef __LONG_MAX__ /* Is a longlong value in gcc 2.8.0 ??? */ +#define __LONG_MAX__ 2147483647 +#endif + +/* egcs 1.1.2 has a problem with memcpy on Alpha */ +#if defined(__GNUC__) && defined(__alpha__) && ! (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) +#define BAD_MEMCPY +#endif + +#if defined(_lint) && !defined(lint) +#define lint +#endif +#if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG) +#define _LONG_LONG 1 /* For AIX string library */ +#endif + +#ifndef stdin +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDDEF_H +#include +#endif + +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_TIMEB_H +#include /* Avoid warnings on SCO */ +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA) +#undef HAVE_ALLOCA +#undef HAVE_ALLOCA_H +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif +#ifdef HAVE_ATOMIC_ADD +#define new my_arg_new +#define need_to_restore_new 1 +C_MODE_START +#include +C_MODE_END +#ifdef need_to_restore_new /* probably safer than #ifdef new */ +#undef new +#undef need_to_restore_new +#endif +#endif +#include /* Recommended by debian */ +/* We need the following to go around a problem with openssl on solaris */ +#if defined(HAVE_CRYPT_H) +#include +#endif + +/* + A lot of our programs uses asserts, so better to always include it + This also fixes a problem when people uses DBUG_ASSERT without including + assert.h +*/ +#include + +/* Go around some bugs in different OS and compilers */ +#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) +#include /* HPUX 10.20 defines ulong here. UGLY !!! */ +#define HAVE_ULONG +#endif +#ifdef DONT_USE_FINITE /* HPUX 11.x has is_finite() */ +#undef HAVE_FINITE +#endif +#if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) && defined(THREAD) +/* Fix bug in setrlimit */ +#undef setrlimit +#define setrlimit cma_setrlimit64 +#endif +/* Declare madvise where it is not declared for C++, like Solaris */ +#if HAVE_MADVISE && !HAVE_DECL_MADVISE && defined(__cplusplus) +extern "C" int madvise(void *addr, size_t len, int behav); +#endif + +#ifdef __QNXNTO__ +/* This has to be after include limits.h */ +#define HAVE_ERRNO_AS_DEFINE +#define HAVE_FCNTL_LOCK +#undef HAVE_FINITE +#undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */ +#undef LONGLONG_MAX /* standard system library 'limits.h' */ +#ifdef __cplusplus +#ifndef HAVE_RINT +#define HAVE_RINT +#endif /* rint() and isnan() functions are not */ +#define rint(a) std::rint(a) /* visible in C++ scope due to an error */ +#define isnan(a) std::isnan(a) /* in the usr/include/math.h on QNX */ +#endif +#endif + +/* We can not live without the following defines */ + +#define USE_MYFUNC 1 /* Must use syscall indirection */ +#define MASTER 1 /* Compile without unireg */ +#define ENGLISH 1 /* Messages in English */ +#define POSIX_MISTAKE 1 /* regexp: Fix stupid spec error */ +#define USE_REGEX 1 /* We want the use the regex library */ +/* Do not define for ultra sparcs */ +#ifndef OS2 +#define USE_BMOVE512 1 /* Use this unless system bmove is faster */ +#endif + +#define QUOTE_ARG(x) #x /* Quote argument (before cpp) */ +#define STRINGIFY_ARG(x) QUOTE_ARG(x) /* Quote argument, after cpp */ + +/* Paranoid settings. Define I_AM_PARANOID if you are paranoid */ +#ifdef I_AM_PARANOID +#define DONT_ALLOW_USER_CHANGE 1 +#define DONT_USE_MYSQL_PWD 1 +#endif + +/* Does the system remember a signal handler after a signal ? */ +#ifndef HAVE_BSD_SIGNALS +#define DONT_REMEMBER_SIGNAL +#endif + +/* Define void to stop lint from generating "null effekt" comments */ +#ifndef DONT_DEFINE_VOID +#ifdef _lint +int __void__; +#define VOID(X) (__void__ = (int) (X)) +#else +#undef VOID +#define VOID(X) (X) +#endif +#endif /* DONT_DEFINE_VOID */ + +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) +#define LINT_INIT(var) var=0 /* No uninitialize-warning */ +#else +#define LINT_INIT(var) +#endif + +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || defined(HAVE_purify) +#define PURIFY_OR_LINT_INIT(var) var=0 +#else +#define PURIFY_OR_LINT_INIT(var) +#endif + +/* Define some useful general macros */ +#if !defined(max) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT +typedef unsigned int uint; +typedef unsigned short ushort; +#endif + +#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1) +#define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0) +#define swap_variables(t, a, b) { register t dummy; dummy= a; a= b; b= dummy; } +#define test(a) ((a) ? 1 : 0) +#define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0) +#define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0) +#define test_all_bits(a,b) (((a) & (b)) == (b)) +#define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) +#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) +#ifndef HAVE_RINT +#define rint(A) floor((A)+(((A) < 0)? -0.5 : 0.5)) +#endif + +/* Define some general constants */ +#ifndef TRUE +#define TRUE (1) /* Logical true */ +#define FALSE (0) /* Logical false */ +#endif + +#if defined(__GNUC__) +#define function_volatile volatile +#define my_reinterpret_cast(A) reinterpret_cast +#define my_const_cast(A) const_cast +# ifndef GCC_VERSION +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +# endif +#elif !defined(my_reinterpret_cast) +#define my_reinterpret_cast(A) (A) +#define my_const_cast(A) (A) +#endif + +#include + +/* + Wen using the embedded library, users might run into link problems, + duplicate declaration of __cxa_pure_virtual, solved by declaring it a + weak symbol. +*/ +#if defined(USE_MYSYS_NEW) && ! defined(DONT_DECLARE_CXA_PURE_VIRTUAL) +C_MODE_START +int __cxa_pure_virtual () __attribute__ ((weak)); +C_MODE_END +#endif + +/* From old s-system.h */ + +/* + Support macros for non ansi & other old compilers. Since such + things are no longer supported we do nothing. We keep then since + some of our code may still be needed to upgrade old customers. +*/ +#define _VARARGS(X) X +#define _STATIC_VARARGS(X) X +#define _PC(X) X + +#if defined(DBUG_ON) && defined(DBUG_OFF) +#undef DBUG_OFF +#endif + +#if defined(_lint) && !defined(DBUG_OFF) +#define DBUG_OFF +#endif + +#include + +#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/ +#define ASCII_BITS_USED 8 /* Bit char used */ +#define NEAR_F /* No near function handling */ + +/* Some types that is different between systems */ + +typedef int File; /* File descriptor */ +#ifndef Socket_defined +typedef int my_socket; /* File descriptor for sockets */ +#define INVALID_SOCKET -1 +#endif +/* Type for fuctions that handles signals */ +#define sig_handler RETSIGTYPE +C_MODE_START +typedef void (*sig_return)();/* Returns type from signal */ +C_MODE_END +#if defined(__GNUC__) && !defined(_lint) +typedef char pchar; /* Mixed prototypes can take char */ +typedef char puchar; /* Mixed prototypes can take char */ +typedef char pbool; /* Mixed prototypes can take char */ +typedef short pshort; /* Mixed prototypes can take short int */ +typedef float pfloat; /* Mixed prototypes can take float */ +#else +typedef int pchar; /* Mixed prototypes can't take char */ +typedef uint puchar; /* Mixed prototypes can't take char */ +typedef int pbool; /* Mixed prototypes can't take char */ +typedef int pshort; /* Mixed prototypes can't take short int */ +typedef double pfloat; /* Mixed prototypes can't take float */ +#endif +C_MODE_START +typedef int (*qsort_cmp)(const void *,const void *); +typedef int (*qsort_cmp2)(void*, const void *,const void *); +C_MODE_END +#ifdef HAVE_mit_thread +#define qsort_t void +#undef QSORT_TYPE_IS_VOID +#define QSORT_TYPE_IS_VOID +#else +#define qsort_t RETQSORTTYPE /* Broken GCC cant handle typedef !!!! */ +#endif +#ifdef HAVE_mit_thread +#define size_socket socklen_t /* Type of last arg to accept */ +#else +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +typedef SOCKET_SIZE_TYPE size_socket; +#endif + +#ifndef SOCKOPT_OPTLEN_TYPE +#define SOCKOPT_OPTLEN_TYPE size_socket +#endif + +/* file create flags */ + +#ifndef O_SHARE /* Probably not windows */ +#define O_SHARE 0 /* Flag to my_open for shared files */ +#ifndef O_BINARY +#define O_BINARY 0 /* Flag to my_open for binary files */ +#endif +#ifndef FILE_BINARY +#define FILE_BINARY O_BINARY /* Flag to my_fopen for binary streams */ +#endif +#ifdef HAVE_FCNTL +#define HAVE_FCNTL_LOCK +#define F_TO_EOF 0L /* Param to lockf() to lock rest of file */ +#endif +#endif /* O_SHARE */ + +#ifndef O_TEMPORARY +#define O_TEMPORARY 0 +#endif +#ifndef O_SHORT_LIVED +#define O_SHORT_LIVED 0 +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 +#endif + +/* additional file share flags for win32 */ +#ifdef __WIN__ +#define _SH_DENYRWD 0x110 /* deny read/write mode & delete */ +#define _SH_DENYWRD 0x120 /* deny write mode & delete */ +#define _SH_DENYRDD 0x130 /* deny read mode & delete */ +#define _SH_DENYDEL 0x140 /* deny delete only */ +#endif /* __WIN__ */ + + +/* #define USE_RECORD_LOCK */ + + /* Unsigned types supported by the compiler */ +#define UNSINT8 /* unsigned int8 (char) */ +#define UNSINT16 /* unsigned int16 */ +#define UNSINT32 /* unsigned int32 */ + + /* General constants */ +#define SC_MAXWIDTH 256 /* Max width of screen (for error messages) */ +#define FN_LEN 256 /* Max file name len */ +#define FN_HEADLEN 253 /* Max length of filepart of file name */ +#define FN_EXTLEN 20 /* Max length of extension (part of FN_LEN) */ +#define FN_REFLEN 512 /* Max length of full path-name */ +#define FN_EXTCHAR '.' +#define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ +#define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ +#define FN_PARENTDIR ".." /* Parent directory; Must be a string */ + +#ifndef FN_LIBCHAR +#ifdef __EMX__ +#define FN_LIBCHAR '\\' +#define FN_ROOTDIR "\\" +#else +#define FN_LIBCHAR '/' +#define FN_ROOTDIR "/" +#endif +#endif +#define MY_NFILE 64 /* This is only used to save filenames */ +#ifndef OS_FILE_LIMIT +#define OS_FILE_LIMIT 65535 +#endif + +/* #define EXT_IN_LIBNAME */ +/* #define FN_NO_CASE_SENCE */ +/* #define FN_UPPER_CASE TRUE */ + +/* + Io buffer size; Must be a power of 2 and a multiple of 512. May be + smaller what the disk page size. This influences the speed of the + isam btree library. eg to big to slow. +*/ +#define IO_SIZE 4096 +/* + How much overhead does malloc have. The code often allocates + something like 1024-MALLOC_OVERHEAD bytes +*/ +#ifdef SAFEMALLOC +#define MALLOC_OVERHEAD (8+24+4) +#else +#define MALLOC_OVERHEAD 8 +#endif + /* get memory in huncs */ +#define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD) + /* Typical record cash */ +#define RECORD_CACHE_SIZE (uint) (64*1024-MALLOC_OVERHEAD) + /* Typical key cash */ +#define KEY_CACHE_SIZE (uint) (8*1024*1024-MALLOC_OVERHEAD) + /* Default size of a key cache block */ +#define KEY_CACHE_BLOCK_SIZE (uint) 1024 + + + /* Some things that this system doesn't have */ + +#define NO_HASH /* Not needed anymore */ +#ifdef __WIN__ +#define NO_DIR_LIBRARY /* Not standar dir-library */ +#define USE_MY_STAT_STRUCT /* For my_lib */ +#endif + +/* Some defines of functions for portability */ + +#undef remove /* Crashes MySQL on SCO 5.0.0 */ +#ifndef __WIN__ +#ifdef OS2 +#define closesocket(A) soclose(A) +#else +#define closesocket(A) close(A) +#endif +#ifndef ulonglong2double +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) +#endif +#endif + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#define ulong_to_double(X) ((double) (ulong) (X)) +#define SET_STACK_SIZE(X) /* Not needed on real machines */ + +#if !defined(HAVE_mit_thread) && !defined(HAVE_STRTOK_R) +#define strtok_r(A,B,C) strtok((A),(B)) +#endif + +/* Remove some things that mit_thread break or doesn't support */ +#if defined(HAVE_mit_thread) && defined(THREAD) +#undef HAVE_PREAD +#undef HAVE_REALPATH +#undef HAVE_MLOCK +#undef HAVE_TEMPNAM /* Use ours */ +#undef HAVE_PTHREAD_SETPRIO +#undef HAVE_FTRUNCATE +#undef HAVE_READLINK +#endif + +/* This is from the old m-machine.h file */ + +#if SIZEOF_LONG_LONG > 4 +#define HAVE_LONG_LONG 1 +#endif + +/* + Some pre-ANSI-C99 systems like AIX 5.1 and Linux/GCC 2.95 define + ULONGLONG_MAX, LONGLONG_MIN, LONGLONG_MAX; we use them if they're defined. + Also on Windows we define these constants by hand in config-win.h. +*/ + +#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) +#define LONGLONG_MIN ((long long) 0x8000000000000000LL) +#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) +#endif + +#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) +/* First check for ANSI C99 definition: */ +#ifdef ULLONG_MAX +#define ULONGLONG_MAX ULLONG_MAX +#else +#define ULONGLONG_MAX ((unsigned long long)(~0ULL)) +#endif +#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ + +#define INT_MIN32 (~0x7FFFFFFFL) +#define INT_MAX32 0x7FFFFFFFL +#define UINT_MAX32 0xFFFFFFFFL +#define INT_MIN24 (~0x007FFFFF) +#define INT_MAX24 0x007FFFFF +#define UINT_MAX24 0x00FFFFFF +#define INT_MIN16 (~0x7FFF) +#define INT_MAX16 0x7FFF +#define UINT_MAX16 0xFFFF +#define INT_MIN8 (~0x7F) +#define INT_MAX8 0x7F +#define UINT_MAX8 0xFF + +/* From limits.h instead */ +#ifndef DBL_MIN +#define DBL_MIN 4.94065645841246544e-324 +#define FLT_MIN ((float)1.40129846432481707e-45) +#endif +#ifndef DBL_MAX +#define DBL_MAX 1.79769313486231470e+308 +#define FLT_MAX ((float)3.40282346638528860e+38) +#endif +#ifndef SSIZE_MAX +#define SSIZE_MAX ((~((size_t) 0)) / 2) +#endif + +#ifndef HAVE_FINITE +#define finite(x) (1.0 / fabs(x) > 0.0) +#endif + +#ifndef HAVE_ISNAN +#define isnan(x) ((x) != (x)) +#endif + +#ifdef HAVE_ISINF +/* isinf() can be used in both C and C++ code */ +#define my_isinf(X) isinf(X) +#else +#define my_isinf(X) (!finite(X) && !isnan(X)) +#endif + +/* Define missing math constants. */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_E +#define M_E 2.7182818284590452354 +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +/* + Max size that must be added to a so that we know Size to make + adressable obj. +*/ +#if SIZEOF_CHARP == 4 +typedef long my_ptrdiff_t; +#else +typedef long long my_ptrdiff_t; +#endif + +#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) +#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) +/* Size to make adressable obj. */ +#define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A),sizeof(t))) + /* Offset of field f in structure t */ +#define OFFSET(t, f) ((size_t)(char *)&((t *)0)->f) +#define ADD_TO_PTR(ptr,size,type) (type) ((byte*) (ptr)+size) +#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((byte*) (A) - (byte*) (B)) + +/* + Custom version of standard offsetof() macro which can be used to get + offsets of members in class for non-POD types (according to the current + version of C++ standard offsetof() macro can't be used in such cases and + attempt to do so causes warnings to be emitted, OTOH in many cases it is + still OK to assume that all instances of the class has the same offsets + for the same members). + + This is temporary solution which should be removed once File_parser class + and related routines are refactored. +*/ + +#define my_offsetof(TYPE, MEMBER) \ + ((size_t)((char *)&(((TYPE *)0x10)->MEMBER) - (char*)0x10)) + +#define NullS (char *) 0 +/* Nowdays we do not support MessyDos */ +#ifndef NEAR +#define NEAR /* Who needs segments ? */ +#define FAR /* On a good machine */ +#ifndef HUGE_PTR +#define HUGE_PTR +#endif +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +/* This was _System _Export but caused a lot of warnings on _AIX43 */ +#define STDCALL +#elif !defined( STDCALL) +#define STDCALL +#endif + +/* Typdefs for easyier portability */ + +#if defined(VOIDTYPE) +typedef void *gptr; /* Generic pointer */ +#else +typedef char *gptr; /* Generic pointer */ +#endif +#ifndef HAVE_INT_8_16_32 +typedef signed char int8; /* Signed integer >= 8 bits */ +typedef short int16; /* Signed integer >= 16 bits */ +#endif +#ifndef HAVE_UCHAR +typedef unsigned char uchar; /* Short for unsigned char */ +#endif +typedef unsigned char uint8; /* Short for unsigned integer >= 8 bits */ +typedef unsigned short uint16; /* Short for unsigned integer >= 16 bits */ + +#if SIZEOF_INT == 4 +#ifndef HAVE_INT_8_16_32 +typedef int int32; +#endif +typedef unsigned int uint32; /* Short for unsigned integer >= 32 bits */ +#elif SIZEOF_LONG == 4 +#ifndef HAVE_INT_8_16_32 +typedef long int32; +#endif +typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */ +#else +#error "Neither int or long is of 4 bytes width" +#endif + +#if !defined(HAVE_ULONG) && !defined(TARGET_OS_LINUX) && !defined(__USE_MISC) +typedef unsigned long ulong; /* Short for unsigned long */ +#endif +#ifndef longlong_defined +#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8 +typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ +typedef long long int longlong; +#else +typedef unsigned long ulonglong; /* ulong or unsigned long long */ +typedef long longlong; +#endif +#endif + +#if defined(NO_CLIENT_LONG_LONG) +typedef unsigned long my_ulonglong; +#elif defined (__WIN__) +typedef unsigned __int64 my_ulonglong; +#else +typedef unsigned long long my_ulonglong; +#endif + +#ifdef USE_RAID +/* + The following is done with a if to not get problems with pre-processors + with late define evaluation +*/ +#if SIZEOF_OFF_T == 4 +#define SYSTEM_SIZEOF_OFF_T 4 +#else +#define SYSTEM_SIZEOF_OFF_T 8 +#endif +#undef SIZEOF_OFF_T +#define SIZEOF_OFF_T 8 +#else +#define SYSTEM_SIZEOF_OFF_T SIZEOF_OFF_T +#endif /* USE_RAID */ + +#if SIZEOF_OFF_T > 4 +typedef ulonglong my_off_t; +#else +typedef unsigned long my_off_t; +#endif +#define MY_FILEPOS_ERROR (~(my_off_t) 0) +#if !defined(__WIN__) && !defined(OS2) +typedef off_t os_off_t; +#endif + +#if defined(__WIN__) +#define socket_errno WSAGetLastError() +#define SOCKET_EINTR WSAEINTR +#define SOCKET_EAGAIN WSAEINPROGRESS +#define SOCKET_ETIMEDOUT WSAETIMEDOUT +#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK +#define SOCKET_EADDRINUSE WSAEADDRINUSE +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#elif defined(OS2) +#define socket_errno sock_errno() +#define SOCKET_EINTR SOCEINTR +#define SOCKET_EAGAIN SOCEINPROGRESS +#define SOCKET_ETIMEDOUT SOCKET_EINTR +#define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK +#define SOCKET_EADDRINUSE SOCEADDRINUSE +#define SOCKET_ENFILE SOCENFILE +#define SOCKET_EMFILE SOCEMFILE +#define closesocket(A) soclose(A) +#else /* Unix */ +#define socket_errno errno +#define closesocket(A) close(A) +#define SOCKET_EINTR EINTR +#define SOCKET_EAGAIN EAGAIN +#define SOCKET_ETIMEDOUT SOCKET_EINTR +#define SOCKET_EWOULDBLOCK EWOULDBLOCK +#define SOCKET_EADDRINUSE EADDRINUSE +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#endif + +typedef uint8 int7; /* Most effective integer 0 <= x <= 127 */ +typedef short int15; /* Most effective integer 0 <= x <= 32767 */ +typedef char *my_string; /* String of characters */ +typedef unsigned long size_s; /* Size of strings (In string-funcs) */ +typedef int myf; /* Type of MyFlags in my_funcs */ +#ifndef byte_defined +typedef char byte; /* Smallest addressable unit */ +#endif +typedef char my_bool; /* Small bool */ +#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus)) +typedef char bool; /* Ordinary boolean values 0 1 */ +#endif + /* Macros for converting *constants* to the right type */ +#define INT8(v) (int8) (v) +#define INT16(v) (int16) (v) +#define INT32(v) (int32) (v) +#define MYF(v) (myf) (v) + +#ifndef LL +#ifdef HAVE_LONG_LONG +#define LL(A) A ## LL +#else +#define LL(A) A ## L +#endif +#endif + +#ifndef ULL +#ifdef HAVE_LONG_LONG +#define ULL(A) A ## ULL +#else +#define ULL(A) A ## UL +#endif +#endif + +/* + Defines to make it possible to prioritize register assignments. No + longer that important with modern compilers. +*/ +#ifndef USING_X +#define reg1 register +#define reg2 register +#define reg3 register +#define reg4 register +#define reg5 register +#define reg6 register +#define reg7 register +#define reg8 register +#define reg9 register +#define reg10 register +#define reg11 register +#define reg12 register +#define reg13 register +#define reg14 register +#define reg15 register +#define reg16 register +#endif + +/* + Sometimes we want to make sure that the variable is not put into + a register in debugging mode so we can see its value in the core +*/ + +#ifndef DBUG_OFF +#define dbug_volatile volatile +#else +#define dbug_volatile +#endif + +/* Defines for time function */ +#define SCALE_SEC 100 +#define SCALE_USEC 10000 +#define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */ +#define MY_HOW_OFTEN_TO_WRITE 1000 /* How often we want info on screen */ + + + +/* + Define-funktions for reading and storing in machine independent format + (low byte first) +*/ + +/* Optimized store functions for Intel x86 */ +#if defined(__i386__) && !defined(_WIN64) +#define sint2korr(A) (*((int16 *) (A))) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (*((long *) (A))) +#define uint2korr(A) (*((uint16 *) (A))) +#ifdef HAVE_purify +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#else +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) +#endif +#define uint4korr(A) (*((uint32 *) (A))) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint8korr(A) (*((ulonglong *) (A))) +#define sint8korr(A) (*((longlong *) (A))) +#define int2store(T,A) *((uint16*) (T))= (uint16) (A) +#define int3store(T,A) do { *(T)= (uchar) ((A));\ + *(T+1)=(uchar) (((uint) (A) >> 8));\ + *(T+2)=(uchar) (((A) >> 16)); } while (0) +#define int4store(T,A) *((long *) (T))= (long) (A) +#define int5store(T,A) do { *(T)= (uchar)((A));\ + *((T)+1)=(uchar) (((A) >> 8));\ + *((T)+2)=(uchar) (((A) >> 16));\ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); } while(0) +#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) + +typedef union { + double v; + long m[2]; +} doubleget_union; +#define doubleget(V,M) \ +do { doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } while(0) +#define doublestore(T,V) do { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ + *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; \ + } while (0) +#define float4get(V,M) do { *((float *) &(V)) = *((float*) (M)); } while(0) +#define float8get(V,M) doubleget((V),(M)) +#define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float)) +#define floatstore(T,V) memcpy((byte*)(T), (byte*)(&V),sizeof(float)) +#define floatget(V,M) memcpy((byte*) &V,(byte*) (M),sizeof(float)) +#define float8store(V,M) doublestore((V),(M)) +#endif /* __i386__ */ + +#ifndef sint2korr +/* + We're here if it's not a IA-32 architecture (Win32 and UNIX IA-32 defines + were done before) +*/ +#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\ + ((int16) ((int16) (A)[1]) << 8)) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\ + (((int32) ((uchar) (A)[1]) << 8)) +\ + (((int32) ((uchar) (A)[2]) << 16)) +\ + (((int32) ((int16) (A)[3]) << 24))) +#define sint8korr(A) (longlong) uint8korr(A) +#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\ + ((uint16) ((uchar) (A)[1]) << 8)) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) (((uint32) ((uchar) (A)[4])) +\ + (((uint32) ((uchar) (A)[5])) << 8) +\ + (((uint32) ((uchar) (A)[6])) << 16) +\ + (((uint32) ((uchar) (A)[7])) << 24))) <<\ + 32)) +#define int2store(T,A) do { uint def_temp= (uint) (A) ;\ + *((uchar*) (T))= (uchar)(def_temp); \ + *((uchar*) (T)+1)=(uchar)((def_temp >> 8)); \ + } while(0) +#define int3store(T,A) do { /*lint -save -e734 */\ + *((uchar*)(T))=(uchar) ((A));\ + *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ + *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ + /*lint -restore */} while(0) +#define int4store(T,A) do { *((char *)(T))=(char) ((A));\ + *(((char *)(T))+1)=(char) (((A) >> 8));\ + *(((char *)(T))+2)=(char) (((A) >> 16));\ + *(((char *)(T))+3)=(char) (((A) >> 24)); } while(0) +#define int5store(T,A) do { *((char *)(T))=((A));\ + *(((char *)(T))+1)=(((A) >> 8));\ + *(((char *)(T))+2)=(((A) >> 16));\ + *(((char *)(T))+3)=(((A) >> 24)); \ + *(((char *)(T))+4)=(((A) >> 32)); } while(0) +#define int8store(T,A) do { uint def_temp= (uint) (A), def_temp2= (uint) ((A) >> 32); \ + int4store((T),def_temp); \ + int4store((T+4),def_temp2); } while(0) +#ifdef WORDS_BIGENDIAN +#define float4store(T,A) do { *(T)= ((byte *) &A)[3];\ + *((T)+1)=(char) ((byte *) &A)[2];\ + *((T)+2)=(char) ((byte *) &A)[1];\ + *((T)+3)=(char) ((byte *) &A)[0]; } while(0) + +#define float4get(V,M) do { float def_temp;\ + ((byte*) &def_temp)[0]=(M)[3];\ + ((byte*) &def_temp)[1]=(M)[2];\ + ((byte*) &def_temp)[2]=(M)[1];\ + ((byte*) &def_temp)[3]=(M)[0];\ + (V)=def_temp; } while(0) +#define float8store(T,V) do { *(T)= ((byte *) &V)[7];\ + *((T)+1)=(char) ((byte *) &V)[6];\ + *((T)+2)=(char) ((byte *) &V)[5];\ + *((T)+3)=(char) ((byte *) &V)[4];\ + *((T)+4)=(char) ((byte *) &V)[3];\ + *((T)+5)=(char) ((byte *) &V)[2];\ + *((T)+6)=(char) ((byte *) &V)[1];\ + *((T)+7)=(char) ((byte *) &V)[0]; } while(0) + +#define float8get(V,M) do { double def_temp;\ + ((byte*) &def_temp)[0]=(M)[7];\ + ((byte*) &def_temp)[1]=(M)[6];\ + ((byte*) &def_temp)[2]=(M)[5];\ + ((byte*) &def_temp)[3]=(M)[4];\ + ((byte*) &def_temp)[4]=(M)[3];\ + ((byte*) &def_temp)[5]=(M)[2];\ + ((byte*) &def_temp)[6]=(M)[1];\ + ((byte*) &def_temp)[7]=(M)[0];\ + (V) = def_temp; } while(0) +#else +#define float4get(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(float)) +#define float4store(V,M) memcpy_fixed((byte*) V,(byte*) (&M),sizeof(float)) + +#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) +#define doublestore(T,V) do { *(((char*)T)+0)=(char) ((byte *) &V)[4];\ + *(((char*)T)+1)=(char) ((byte *) &V)[5];\ + *(((char*)T)+2)=(char) ((byte *) &V)[6];\ + *(((char*)T)+3)=(char) ((byte *) &V)[7];\ + *(((char*)T)+4)=(char) ((byte *) &V)[0];\ + *(((char*)T)+5)=(char) ((byte *) &V)[1];\ + *(((char*)T)+6)=(char) ((byte *) &V)[2];\ + *(((char*)T)+7)=(char) ((byte *) &V)[3]; }\ + while(0) +#define doubleget(V,M) do { double def_temp;\ + ((byte*) &def_temp)[0]=(M)[4];\ + ((byte*) &def_temp)[1]=(M)[5];\ + ((byte*) &def_temp)[2]=(M)[6];\ + ((byte*) &def_temp)[3]=(M)[7];\ + ((byte*) &def_temp)[4]=(M)[0];\ + ((byte*) &def_temp)[5]=(M)[1];\ + ((byte*) &def_temp)[6]=(M)[2];\ + ((byte*) &def_temp)[7]=(M)[3];\ + (V) = def_temp; } while(0) +#endif /* __FLOAT_WORD_ORDER */ + +#define float8get(V,M) doubleget((V),(M)) +#define float8store(V,M) doublestore((V),(M)) +#endif /* WORDS_BIGENDIAN */ + +#endif /* sint2korr */ + +/* + Macro for reading 32-bit integer from network byte order (big-endian) + from unaligned memory location. +*/ +#define int4net(A) (int32) (((uint32) ((uchar) (A)[3])) |\ + (((uint32) ((uchar) (A)[2])) << 8) |\ + (((uint32) ((uchar) (A)[1])) << 16) |\ + (((uint32) ((uchar) (A)[0])) << 24)) +/* + Define-funktions for reading and storing in machine format from/to + short/long to/from some place in memory V should be a (not + register) variable, M is a pointer to byte +*/ + +#ifdef WORDS_BIGENDIAN + +#define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\ + ((uint16) ((uint16) (M)[0]) << 8)); } while(0) +#define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\ + ((short) ((short) (M)[0]) << 8)); } while(0) +#define longget(V,M) do { int32 def_temp;\ + ((byte*) &def_temp)[0]=(M)[0];\ + ((byte*) &def_temp)[1]=(M)[1];\ + ((byte*) &def_temp)[2]=(M)[2];\ + ((byte*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define ulongget(V,M) do { uint32 def_temp;\ + ((byte*) &def_temp)[0]=(M)[0];\ + ((byte*) &def_temp)[1]=(M)[1];\ + ((byte*) &def_temp)[2]=(M)[2];\ + ((byte*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define shortstore(T,A) do { uint def_temp=(uint) (A) ;\ + *(((char*)T)+1)=(char)(def_temp); \ + *(((char*)T)+0)=(char)(def_temp >> 8); } while(0) +#define longstore(T,A) do { *(((char*)T)+3)=((A));\ + *(((char*)T)+2)=(((A) >> 8));\ + *(((char*)T)+1)=(((A) >> 16));\ + *(((char*)T)+0)=(((A) >> 24)); } while(0) + +#define floatget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(float)) +#define floatstore(T,V) memcpy_fixed((byte*) (T),(byte*)(&V),sizeof(float)) +#define doubleget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(double)) +#define doublestore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(double)) +#define longlongget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(ulonglong)) +#define longlongstore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(ulonglong)) + +#else + +#define ushortget(V,M) do { V = uint2korr(M); } while(0) +#define shortget(V,M) do { V = sint2korr(M); } while(0) +#define longget(V,M) do { V = sint4korr(M); } while(0) +#define ulongget(V,M) do { V = uint4korr(M); } while(0) +#define shortstore(T,V) int2store(T,V) +#define longstore(T,V) int4store(T,V) +#ifndef floatstore +#define floatstore(T,V) memcpy_fixed((byte*) (T),(byte*) (&V),sizeof(float)) +#define floatget(V,M) memcpy_fixed((byte*) &V, (byte*) (M), sizeof(float)) +#endif +#ifndef doubleget +#define doubleget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(double)) +#define doublestore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(double)) +#endif /* doubleget */ +#define longlongget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(ulonglong)) +#define longlongstore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(ulonglong)) + +#endif /* WORDS_BIGENDIAN */ + +/* sprintf does not always return the number of bytes :- */ +#ifdef SPRINTF_RETURNS_INT +#define my_sprintf(buff,args) sprintf args +#else +#ifdef SPRINTF_RETURNS_PTR +#define my_sprintf(buff,args) ((int)(sprintf args - buff)) +#else +#define my_sprintf(buff,args) ((ulong) sprintf args, (ulong) strlen(buff)) +#endif +#endif + +#ifndef THREAD +#define thread_safe_increment(V,L) (V)++ +#define thread_safe_add(V,C,L) (V)+=(C) +#define thread_safe_sub(V,C,L) (V)-=(C) +#define statistic_increment(V,L) (V)++ +#define statistic_add(V,C,L) (V)+=(C) +#endif + +#ifdef HAVE_CHARSET_utf8 +#define MYSQL_UNIVERSAL_CLIENT_CHARSET "utf8" +#else +#define MYSQL_UNIVERSAL_CLIENT_CHARSET MYSQL_DEFAULT_CHARSET_NAME +#endif + +#if defined(EMBEDDED_LIBRARY) && !defined(HAVE_EMBEDDED_PRIVILEGE_CONTROL) +#define NO_EMBEDDED_ACCESS_CHECKS +#endif + + +/* Length of decimal number represented by INT32. */ + +#define MY_INT32_NUM_DECIMAL_DIGITS 11 + +/* Length of decimal number represented by INT64. */ + +#define MY_INT64_NUM_DECIMAL_DIGITS 21 + +#endif /* my_global_h */ diff --git a/code/meosdb/mysql50/my_list.h b/code/meosdb/mysql50/my_list.h new file mode 100644 index 0000000..d846955 --- /dev/null +++ b/code/meosdb/mysql50/my_list.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _list_h_ +#define _list_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_list { + struct st_list *prev,*next; + void *data; +} LIST; + +typedef int (*list_walk_action)(void *,void *); + +extern LIST *list_add(LIST *root,LIST *element); +extern LIST *list_delete(LIST *root,LIST *element); +extern LIST *list_cons(void *data,LIST *root); +extern LIST *list_reverse(LIST *root); +extern void list_free(LIST *root,unsigned int free_data); +extern unsigned int list_length(LIST *); +extern int list_walk(LIST *,list_walk_action action,gptr argument); + +#define list_rest(a) ((a)->next) +#define list_push(a,b) (a)=list_cons((b),(a)) +#define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old) ; my_free((gptr) old,MYF(MY_FAE)); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/meosdb/mysql50/my_net.h b/code/meosdb/mysql50/my_net.h new file mode 100644 index 0000000..0da2ee3 --- /dev/null +++ b/code/meosdb/mysql50/my_net.h @@ -0,0 +1,134 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + thread safe version of some common functions: + my_inet_ntoa + + This file is also used to make handling of sockets and ioctl() + portable accross systems. + +*/ + +#ifndef _my_net_h +#define _my_net_h +C_MODE_START + +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_POLL +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__) && !defined(__NETWARE__) +#include +#include +#include +#if !defined(alpha_linux_port) +#include +#endif +#endif + +#if defined(__EMX__) +#include +#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C))) +#undef HAVE_FCNTL +#endif /* defined(__EMX__) */ + +#if defined(MSDOS) || defined(__WIN__) +#define O_NONBLOCK 1 /* For emulation of fcntl() */ + +/* + SHUT_RDWR is called SD_BOTH in windows and + is defined to 2 in winsock2.h + #define SD_BOTH 0x02 +*/ +#define SHUT_RDWR 0x02 + +#endif + +/* + On OSes which don't have the in_addr_t, we guess that using uint32 is the best + possible choice. We guess this from the fact that on HP-UX64bit & FreeBSD64bit + & Solaris64bit, in_addr_t is equivalent to uint32. And on Linux32bit too. +*/ +#ifndef HAVE_IN_ADDR_T +#define in_addr_t uint32 +#endif + +/* On some operating systems (e.g. Solaris) INADDR_NONE is not defined */ +#ifndef INADDR_NONE +#define INADDR_NONE -1 /* Error value from inet_addr */ +#endif + +/* Thread safe or portable version of some functions */ + +void my_inet_ntoa(struct in_addr in, char *buf); + +/* + Handling of gethostbyname_r() +*/ + +#if !defined(HPUX10) +struct hostent; +#endif /* HPUX */ +#if !defined(HAVE_GETHOSTBYNAME_R) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +void my_gethostbyname_r_free(); +#elif defined(HAVE_PTHREAD_ATTR_CREATE) || defined(_AIX) || defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +#define my_gethostbyname_r_free() +#if !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) && !defined(HPUX10) +#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data) +#endif /* !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) */ + +#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT) +#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +#define my_gethostbyname_r_free() +#else +#define my_gethostbyname_r(A,B,C,D,E) gethostbyname_r((A),(B),(C),(D),(E)) +#define my_gethostbyname_r_free() +#endif /* !defined(HAVE_GETHOSTBYNAME_R) */ + +#ifndef GETHOSTBYNAME_BUFF_SIZE +#define GETHOSTBYNAME_BUFF_SIZE 2048 +#endif + +/* On SCO you get a link error when refering to h_errno */ +#ifdef SCO +#undef h_errno +#define h_errno errno +#endif + +C_MODE_END +#endif diff --git a/code/meosdb/mysql50/my_no_pthread.h b/code/meosdb/mysql50/my_no_pthread.h new file mode 100644 index 0000000..ecef74f --- /dev/null +++ b/code/meosdb/mysql50/my_no_pthread.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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(_my_no_pthread_h) && !defined(THREAD) +#define _my_no_pthread_h + + +/* + This block is to access some thread-related type definitions + even in builds which do not need thread functions, + as some variables (based on these types) are declared + even in non-threaded builds. + Case in point: 'mf_keycache.c' +*/ +#if defined(__WIN__) || defined(OS2) + +#elif defined(HAVE_UNIXWARE7_THREADS) +/* #include Currently, not relevant. Enable if needed. */ + +#else /* Normal threads */ +#include + +#endif /* defined(__WIN__) */ + + +/* + This undefs some pthread mutex locks when one isn't using threads + to make thread safe code, that should also work in single thread + environment, easier to use. +*/ +#define pthread_mutex_init(A,B) +#define pthread_mutex_lock(A) +#define pthread_mutex_unlock(A) +#define pthread_mutex_destroy(A) +#define my_rwlock_init(A,B) +#define rw_rdlock(A) +#define rw_wrlock(A) +#define rw_unlock(A) +#define rwlock_destroy(A) + +#endif diff --git a/code/meosdb/mysql50/my_pthread.h b/code/meosdb/mysql50/my_pthread.h new file mode 100644 index 0000000..a91afe4 --- /dev/null +++ b/code/meosdb/mysql50/my_pthread.h @@ -0,0 +1,812 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Defines to make different thread packages compatible */ + +#ifndef _my_pthread_h +#define _my_pthread_h + +#include +#ifndef ETIME +#define ETIME ETIMEDOUT /* For FreeBSD */ +#endif + +#ifdef __cplusplus +#define EXTERNC extern "C" +extern "C" { +#else +#define EXTERNC +#endif /* __cplusplus */ + +/* + BUG#24507: Race conditions inside current NPTL pthread_exit() implementation. + + If macro NPTL_PTHREAD_EXIT_HACK is defined then a hack described in the bug + report will be implemented inside my_thread_global_init() in my_thr_init.c. + + This amounts to spawning a dummy thread which does nothing but executes + pthread_exit(0). + + This bug is fixed in version 2.5 of glibc library. + + TODO: Remove this code when fixed versions of glibc6 are in common use. + */ + +#if defined(TARGET_OS_LINUX) && defined(HAVE_NPTL) && \ + defined(__GLIBC__) && ( __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 5 ) +#define NPTL_PTHREAD_EXIT_BUG 1 +#endif + +#if defined(__WIN__) || defined(OS2) + +#ifdef OS2 +typedef ULONG HANDLE; +typedef ULONG DWORD; +typedef int sigset_t; +#endif + +#ifdef OS2 +typedef HMTX pthread_mutex_t; +#else +typedef CRITICAL_SECTION pthread_mutex_t; +#endif +typedef HANDLE pthread_t; +typedef struct thread_attr { + DWORD dwStackSize ; + DWORD dwCreatingFlag ; + int priority ; +} pthread_attr_t ; + +typedef struct { int dummy; } pthread_condattr_t; + +/* Implementation of posix conditions */ + +typedef struct st_pthread_link { + DWORD thread_id; + struct st_pthread_link *next; +} pthread_link; + +typedef struct { + uint32 waiting; + CRITICAL_SECTION lock_waiting; + + enum { + SIGNAL= 0, + BROADCAST= 1, + MAX_EVENTS= 2 + } EVENTS; + + HANDLE events[MAX_EVENTS]; + HANDLE broadcast_block_event; + +} pthread_cond_t; + +typedef int pthread_mutexattr_t; +#define win_pthread_self my_thread_var->pthread_self +#ifdef OS2 +#define pthread_handler_t EXTERNC void * _Optlink +typedef void * (_Optlink *pthread_handler)(void *); +#else +#define pthread_handler_t EXTERNC void * __cdecl +typedef void * (__cdecl *pthread_handler)(void *); +#endif + +/* + Struct and macros to be used in combination with the + windows implementation of pthread_cond_timedwait +*/ + +/* + Declare a union to make sure FILETIME is properly aligned + so it can be used directly as a 64 bit value. The value + stored is in 100ns units. + */ + union ft64 { + FILETIME ft; + __int64 i64; + }; +struct timespec { + union ft64 tv; + /* The max timeout value in millisecond for pthread_cond_timedwait */ + long max_timeout_msec; +}; +#define set_timespec(ABSTIME,SEC) { \ + GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \ + (ABSTIME).tv.i64+= (__int64)(SEC)*10000000; \ + (ABSTIME).max_timeout_msec= (long)((SEC)*1000); \ +} +#define set_timespec_nsec(ABSTIME,NSEC) { \ + GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \ + (ABSTIME).tv.i64+= (__int64)(NSEC)/100; \ + (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \ +} + +void win_pthread_init(void); +int win_pthread_setspecific(void *A,void *B,uint length); +int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *); +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_cond_destroy(pthread_cond_t *cond); +int pthread_attr_init(pthread_attr_t *connect_att); +int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack); +int pthread_attr_setprio(pthread_attr_t *connect_att,int priority); +int pthread_attr_destroy(pthread_attr_t *connect_att); +struct tm *localtime_r(const time_t *timep,struct tm *tmp); +struct tm *gmtime_r(const time_t *timep,struct tm *tmp); + + +void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ + +#ifndef OS2 +#define ETIMEDOUT 145 /* Win32 doesn't have this */ +#define getpid() GetCurrentThreadId() +#endif +#define pthread_self() win_pthread_self +#define HAVE_LOCALTIME_R 1 +#define _REENTRANT 1 +#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 + +#ifdef USE_TLS /* For LIBMYSQL.DLL */ +#undef SAFE_MUTEX /* This will cause conflicts */ +#define pthread_key(T,V) DWORD V +#define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) +#define pthread_key_delete(A) TlsFree(A) +#define pthread_getspecific(A) (TlsGetValue(A)) +#define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) +#define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) +#define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) +#define pthread_setspecific(A,B) (!TlsSetValue((A),(B))) +#else +#define pthread_key(T,V) __declspec(thread) T V +#define pthread_key_create(A,B) pthread_dummy(0) +#define pthread_key_delete(A) pthread_dummy(0) +#define pthread_getspecific(A) (&(A)) +#define my_pthread_getspecific(T,A) (&(A)) +#define my_pthread_getspecific_ptr(T,V) (V) +#define my_pthread_setspecific_ptr(T,V) ((T)=(V),0) +#define pthread_setspecific(A,B) win_pthread_setspecific(&(A),(B),sizeof(A)) +#endif /* USE_TLS */ + +#define pthread_equal(A,B) ((A) == (B)) +#ifdef OS2 +extern int pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); +extern int pthread_mutex_lock (pthread_mutex_t *); +extern int pthread_mutex_unlock (pthread_mutex_t *); +extern int pthread_mutex_destroy (pthread_mutex_t *); +#define my_pthread_setprio(A,B) DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE, B, A) +#define pthread_kill(A,B) raise(B) +#define pthread_exit(A) pthread_dummy() +#else +#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) +#define pthread_mutex_lock(A) (EnterCriticalSection(A),0) +#define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) +#define pthread_mutex_unlock(A) LeaveCriticalSection(A) +#define pthread_mutex_destroy(A) DeleteCriticalSection(A) +#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B)) +#define pthread_kill(A,B) pthread_dummy(0) +#endif /* OS2 */ + +/* Dummy defines for easier code */ +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define my_pthread_attr_setprio(A,B) pthread_attr_setprio(A,B) +#define pthread_attr_setscope(A,B) +#define pthread_detach_this_thread() +#define pthread_condattr_init(A) +#define pthread_condattr_destroy(A) + +#define my_pthread_getprio(thread_id) pthread_dummy(0) + +#elif defined(HAVE_UNIXWARE7_THREADS) + +#include +#include + +#ifndef _REENTRANT +#define _REENTRANT +#endif + +#define HAVE_NONPOSIX_SIGWAIT +#define pthread_t thread_t +#define pthread_cond_t cond_t +#define pthread_mutex_t mutex_t +#define pthread_key_t thread_key_t +typedef int pthread_attr_t; /* Needed by Unixware 7.0.0 */ + +#define pthread_key_create(A,B) thr_keycreate((A),(B)) +#define pthread_key_delete(A) thr_keydelete(A) + +#define pthread_handler_t EXTERNC void * +#define pthread_key(T,V) pthread_key_t V + +void * my_pthread_getspecific_imp(pthread_key_t key); +#define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B)) +#define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,V) + +#define pthread_setspecific(A,B) thr_setspecific(A,B) +#define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,V) + +#define pthread_create(A,B,C,D) thr_create(NULL,65536L,(C),(D),THR_DETACHED,(A)) +#define pthread_cond_init(a,b) cond_init((a),USYNC_THREAD,NULL) +#define pthread_cond_destroy(a) cond_destroy(a) +#define pthread_cond_signal(a) cond_signal(a) +#define pthread_cond_wait(a,b) cond_wait((a),(b)) +#define pthread_cond_timedwait(a,b,c) cond_timedwait((a),(b),(c)) +#define pthread_cond_broadcast(a) cond_broadcast(a) + +#define pthread_mutex_init(a,b) mutex_init((a),USYNC_THREAD,NULL) +#define pthread_mutex_lock(a) mutex_lock(a) +#define pthread_mutex_unlock(a) mutex_unlock(a) +#define pthread_mutex_destroy(a) mutex_destroy(a) + +#define pthread_self() thr_self() +#define pthread_exit(A) thr_exit(A) +#define pthread_equal(A,B) (((A) == (B)) ? 1 : 0) +#define pthread_kill(A,B) thr_kill((A),(B)) +#define HAVE_PTHREAD_KILL + +#define pthread_sigmask(A,B,C) thr_sigsetmask((A),(B),(C)) + +extern int my_sigwait(const sigset_t *set,int *sig); + +#define pthread_detach_this_thread() pthread_dummy(0) + +#define pthread_attr_init(A) pthread_dummy(0) +#define pthread_attr_destroy(A) pthread_dummy(0) +#define pthread_attr_setscope(A,B) pthread_dummy(0) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define my_pthread_setprio(A,B) pthread_dummy (0) +#define my_pthread_getprio(A) pthread_dummy (0) +#define my_pthread_attr_setprio(A,B) pthread_dummy(0) + +#else /* Normal threads */ + +#ifdef HAVE_rts_threads +#define sigwait org_sigwait +#include +#undef sigwait +#endif +#include +#ifndef _REENTRANT +#define _REENTRANT +#endif +#ifdef HAVE_THR_SETCONCURRENCY +#include /* Probably solaris */ +#endif +#ifdef HAVE_SCHED_H +#include +#endif +#ifdef HAVE_SYNCH_H +#include +#endif +#if defined(__EMX__) && (!defined(EMX_PTHREAD_REV) || (EMX_PTHREAD_REV < 2)) +#error Requires at least rev 2 of EMX pthreads library. +#endif + +#ifdef __NETWARE__ +void my_pthread_exit(void *status); +#define pthread_exit(A) my_pthread_exit(A) +#endif + +extern int my_pthread_getprio(pthread_t thread_id); + +#define pthread_key(T,V) pthread_key_t V +#define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) +#define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) +#define pthread_detach_this_thread() +#define pthread_handler_t EXTERNC void * +typedef void *(* pthread_handler)(void *); + +/* Test first for RTS or FSU threads */ + +#if defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) +#define HAVE_rts_threads +extern int my_pthread_create_detached; +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define PTHREAD_CREATE_DETACHED &my_pthread_create_detached +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL +#define USE_ALARM_THREAD +#elif defined(HAVE_mit_thread) +#define USE_ALARM_THREAD +#undef HAVE_LOCALTIME_R +#define HAVE_LOCALTIME_R +#undef HAVE_GMTIME_R +#define HAVE_GMTIME_R +#undef HAVE_PTHREAD_ATTR_SETSCOPE +#define HAVE_PTHREAD_ATTR_SETSCOPE +#undef HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE /* If we are running linux */ +#undef HAVE_RWLOCK_T +#undef HAVE_RWLOCK_INIT +#undef HAVE_PTHREAD_RWLOCK_RDLOCK +#undef HAVE_SNPRINTF + +#define my_pthread_attr_setprio(A,B) +#endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */ + +#if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910 +int sigwait(sigset_t *set, int *sig); +#endif + +#ifndef HAVE_NONPOSIX_SIGWAIT +#define my_sigwait(A,B) sigwait((A),(B)) +#else +int my_sigwait(const sigset_t *set,int *sig); +#endif + +#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT +#ifndef SAFE_MUTEX +#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b)) +extern int my_pthread_mutex_init(pthread_mutex_t *mp, + const pthread_mutexattr_t *attr); +#endif /* SAFE_MUTEX */ +#define pthread_cond_init(a,b) my_pthread_cond_init((a),(b)) +extern int my_pthread_cond_init(pthread_cond_t *mp, + const pthread_condattr_t *attr); +#endif /* HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */ + +#if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK) +#define pthread_sigmask(A,B,C) sigthreadmask((A),(B),(C)) +#endif + +#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX) +int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */ +#endif + + +/* + We define my_sigset() and use that instead of the system sigset() so that + we can favor an implementation based on sigaction(). On some systems, such + as Mac OS X, sigset() results in flags such as SA_RESTART being set, and + we want to make sure that no such flags are set. +*/ +#if defined(HAVE_SIGACTION) && !defined(my_sigset) +#define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; int l_rc; \ + DBUG_ASSERT((A) != 0); \ + sigemptyset(&l_set); \ + l_s.sa_handler = (B); \ + l_s.sa_mask = l_set; \ + l_s.sa_flags = 0; \ + l_rc= sigaction((A), &l_s, (struct sigaction *) NULL);\ + DBUG_ASSERT(l_rc == 0); \ + } while (0) +#elif defined(HAVE_SIGSET) && !defined(my_sigset) +#define my_sigset(A,B) sigset((A),(B)) +#elif !defined(my_sigset) +#define my_sigset(A,B) signal((A),(B)) +#endif + +#ifndef my_pthread_setprio +#if defined(HAVE_PTHREAD_SETPRIO_NP) /* FSU threads */ +#define my_pthread_setprio(A,B) pthread_setprio_np((A),(B)) +#elif defined(HAVE_PTHREAD_SETPRIO) +#define my_pthread_setprio(A,B) pthread_setprio((A),(B)) +#else +extern void my_pthread_setprio(pthread_t thread_id,int prior); +#endif +#endif + +#ifndef my_pthread_attr_setprio +#ifdef HAVE_PTHREAD_ATTR_SETPRIO +#define my_pthread_attr_setprio(A,B) pthread_attr_setprio((A),(B)) +#else +extern void my_pthread_attr_setprio(pthread_attr_t *attr, int priority); +#endif +#endif + +#if !defined(HAVE_PTHREAD_ATTR_SETSCOPE) || defined(HAVE_DEC_3_2_THREADS) +#define pthread_attr_setscope(A,B) +#undef HAVE_GETHOSTBYADDR_R /* No definition */ +#endif + +#if defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT) && !defined(SAFE_MUTEX) +extern int my_pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + struct timespec *abstime); +#define pthread_cond_timedwait(A,B,C) my_pthread_cond_timedwait((A),(B),(C)) +#endif + +#if defined(OS2) +#define my_pthread_getspecific(T,A) ((T) &(A)) +#define pthread_setspecific(A,B) win_pthread_setspecific(&(A),(B),sizeof(A)) +#elif !defined( HAVE_NONPOSIX_PTHREAD_GETSPECIFIC) +#define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B)) +#else +#define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B)) +void *my_pthread_getspecific_imp(pthread_key_t key); +#endif /* OS2 */ + +#ifndef HAVE_LOCALTIME_R +struct tm *localtime_r(const time_t *clock, struct tm *res); +#endif + +#ifndef HAVE_GMTIME_R +struct tm *gmtime_r(const time_t *clock, struct tm *res); +#endif + +#ifdef HAVE_PTHREAD_CONDATTR_CREATE +/* DCE threads on HPUX 10.20 */ +#define pthread_condattr_init pthread_condattr_create +#define pthread_condattr_destroy pthread_condattr_delete +#endif + +/* FSU THREADS */ +#if !defined(HAVE_PTHREAD_KEY_DELETE) && !defined(pthread_key_delete) +#define pthread_key_delete(A) pthread_dummy(0) +#endif + +#ifdef HAVE_CTHREADS_WRAPPER /* For MacOSX */ +#define pthread_cond_destroy(A) pthread_dummy(0) +#define pthread_mutex_destroy(A) pthread_dummy(0) +#define pthread_attr_delete(A) pthread_dummy(0) +#define pthread_condattr_delete(A) pthread_dummy(0) +#define pthread_attr_setstacksize(A,B) pthread_dummy(0) +#define pthread_equal(A,B) ((A) == (B)) +#define pthread_cond_timedwait(a,b,c) pthread_cond_wait((a),(b)) +#define pthread_attr_init(A) pthread_attr_create(A) +#define pthread_attr_destroy(A) pthread_attr_delete(A) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define pthread_kill(A,B) pthread_dummy(0) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } +#endif + +#ifdef HAVE_DARWIN5_THREADS +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define pthread_kill(A,B) pthread_dummy(0) +#define pthread_condattr_init(A) pthread_dummy(0) +#define pthread_condattr_destroy(A) pthread_dummy(0) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(tmp); } +#endif + +#if ((defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT)) || defined(HAVE_DEC_3_2_THREADS)) && !defined(HAVE_CTHREADS_WRAPPER) +/* This is set on AIX_3_2 and Siemens unix (and DEC OSF/1 3.2 too) */ +#define pthread_key_create(A,B) \ + pthread_keycreate(A,(B) ?\ + (pthread_destructor_t) (B) :\ + (pthread_destructor_t) pthread_dummy) +#define pthread_attr_init(A) pthread_attr_create(A) +#define pthread_attr_destroy(A) pthread_attr_delete(A) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) +#ifndef pthread_sigmask +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#endif +#define pthread_kill(A,B) pthread_dummy(0) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } +#elif !defined(__NETWARE__) /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */ +#define HAVE_PTHREAD_KILL +#endif + +#endif /* defined(__WIN__) */ + +#if defined(HPUX10) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_cond_timedwait +#define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c)) +int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +#endif + +#if defined(HPUX10) +#define pthread_attr_getstacksize(A,B) my_pthread_attr_getstacksize(A,B) +void my_pthread_attr_getstacksize(pthread_attr_t *attrib, size_t *size); +#endif + +#if defined(HAVE_POSIX1003_4a_MUTEX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_mutex_trylock +#define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a)) +int my_pthread_mutex_trylock(pthread_mutex_t *mutex); +#endif + +/* + The defines set_timespec and set_timespec_nsec should be used + for calculating an absolute time at which + pthread_cond_timedwait should timeout +*/ +#ifdef HAVE_TIMESPEC_TS_SEC +#ifndef set_timespec +#define set_timespec(ABSTIME,SEC) \ +{ \ + (ABSTIME).ts_sec=time(0) + (time_t) (SEC); \ + (ABSTIME).ts_nsec=0; \ +} +#endif /* !set_timespec */ +#ifndef set_timespec_nsec +#define set_timespec_nsec(ABSTIME,NSEC) \ +{ \ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).ts_sec= (now / ULL(10000000)); \ + (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ +} +#endif /* !set_timespec_nsec */ +#else +#ifndef set_timespec +#define set_timespec(ABSTIME,SEC) \ +{\ + struct timeval tv;\ + gettimeofday(&tv,0);\ + (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\ + (ABSTIME).tv_nsec=tv.tv_usec*1000;\ +} +#endif /* !set_timespec */ +#ifndef set_timespec_nsec +#define set_timespec_nsec(ABSTIME,NSEC) \ +{\ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).tv_sec= (time_t) (now / ULL(10000000)); \ + (ABSTIME).tv_nsec= (long) (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ +} +#endif /* !set_timespec_nsec */ +#endif /* HAVE_TIMESPEC_TS_SEC */ + + /* safe_mutex adds checking to mutex for easier debugging */ + +#if defined(__NETWARE__) && !defined(SAFE_MUTEX_DETECT_DESTROY) +#define SAFE_MUTEX_DETECT_DESTROY +#endif + +typedef struct st_safe_mutex_t +{ + pthread_mutex_t global,mutex; + const char *file; + uint line,count; + pthread_t thread; +#ifdef SAFE_MUTEX_DETECT_DESTROY + struct st_safe_mutex_info_t *info; /* to track destroying of mutexes */ +#endif +} safe_mutex_t; + +#ifdef SAFE_MUTEX_DETECT_DESTROY +/* + Used to track the destroying of mutexes. This needs to be a seperate + structure because the safe_mutex_t structure could be freed before + the mutexes are destroyed. +*/ + +typedef struct st_safe_mutex_info_t +{ + struct st_safe_mutex_info_t *next; + struct st_safe_mutex_info_t *prev; + const char *init_file; + uint32 init_line; +} safe_mutex_info_t; +#endif /* SAFE_MUTEX_DETECT_DESTROY */ + +int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, + const char *file, uint line); +int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line); +int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); +int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); +int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, + uint line); +int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, + struct timespec *abstime, const char *file, uint line); +void safe_mutex_global_init(void); +void safe_mutex_end(FILE *file); + + /* Wrappers if safe mutex is actually used */ +#ifdef SAFE_MUTEX +#undef pthread_mutex_init +#undef pthread_mutex_lock +#undef pthread_mutex_unlock +#undef pthread_mutex_destroy +#undef pthread_mutex_wait +#undef pthread_mutex_timedwait +#undef pthread_mutex_t +#undef pthread_cond_wait +#undef pthread_cond_timedwait +#undef pthread_mutex_trylock +#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__) +#define pthread_mutex_lock(A) safe_mutex_lock((A),__FILE__,__LINE__) +#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__) +#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) +#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) +#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) +#define pthread_mutex_trylock(A) pthread_mutex_lock(A) +#define pthread_mutex_t safe_mutex_t +#define safe_mutex_assert_owner(mp) \ + DBUG_ASSERT((mp)->count > 0 && \ + pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_assert_not_owner(mp) \ + DBUG_ASSERT(! (mp)->count || \ + ! pthread_equal(pthread_self(), (mp)->thread)) +#else +#define safe_mutex_assert_owner(mp) +#define safe_mutex_assert_not_owner(mp) +#endif /* SAFE_MUTEX */ + + /* READ-WRITE thread locking */ + +#ifdef HAVE_BROKEN_RWLOCK /* For OpenUnix */ +#undef HAVE_PTHREAD_RWLOCK_RDLOCK +#undef HAVE_RWLOCK_INIT +#undef HAVE_RWLOCK_T +#endif + +#if defined(USE_MUTEX_INSTEAD_OF_RW_LOCKS) +/* use these defs for simple mutex locking */ +#define rw_lock_t pthread_mutex_t +#define my_rwlock_init(A,B) pthread_mutex_init((A),(B)) +#define rw_rdlock(A) pthread_mutex_lock((A)) +#define rw_wrlock(A) pthread_mutex_lock((A)) +#define rw_tryrdlock(A) pthread_mutex_trylock((A)) +#define rw_trywrlock(A) pthread_mutex_trylock((A)) +#define rw_unlock(A) pthread_mutex_unlock((A)) +#define rwlock_destroy(A) pthread_mutex_destroy((A)) +#elif defined(HAVE_PTHREAD_RWLOCK_RDLOCK) +#define rw_lock_t pthread_rwlock_t +#define my_rwlock_init(A,B) pthread_rwlock_init((A),(B)) +#define rw_rdlock(A) pthread_rwlock_rdlock(A) +#define rw_wrlock(A) pthread_rwlock_wrlock(A) +#define rw_tryrdlock(A) pthread_rwlock_tryrdlock((A)) +#define rw_trywrlock(A) pthread_rwlock_trywrlock((A)) +#define rw_unlock(A) pthread_rwlock_unlock(A) +#define rwlock_destroy(A) pthread_rwlock_destroy(A) +#elif defined(HAVE_RWLOCK_INIT) +#ifdef HAVE_RWLOCK_T /* For example Solaris 2.6-> */ +#define rw_lock_t rwlock_t +#endif +#define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) +#else +/* Use our own version of read/write locks */ +typedef struct _my_rw_lock_t { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ +} my_rw_lock_t; + +#define rw_lock_t my_rw_lock_t +#define rw_rdlock(A) my_rw_rdlock((A)) +#define rw_wrlock(A) my_rw_wrlock((A)) +#define rw_tryrdlock(A) my_rw_tryrdlock((A)) +#define rw_trywrlock(A) my_rw_trywrlock((A)) +#define rw_unlock(A) my_rw_unlock((A)) +#define rwlock_destroy(A) my_rwlock_destroy((A)) + +extern int my_rwlock_init(my_rw_lock_t *, void *); +extern int my_rwlock_destroy(my_rw_lock_t *); +extern int my_rw_rdlock(my_rw_lock_t *); +extern int my_rw_wrlock(my_rw_lock_t *); +extern int my_rw_unlock(my_rw_lock_t *); +extern int my_rw_tryrdlock(my_rw_lock_t *); +extern int my_rw_trywrlock(my_rw_lock_t *); +#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ + +#define GETHOSTBYADDR_BUFF_SIZE 2048 + +#ifndef HAVE_THR_SETCONCURRENCY +#define thr_setconcurrency(A) pthread_dummy(0) +#endif +#if !defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && ! defined(pthread_attr_setstacksize) +#define pthread_attr_setstacksize(A,B) pthread_dummy(0) +#endif + +/* Define mutex types, see my_thr_init.c */ +#define MY_MUTEX_INIT_SLOW NULL +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_fast_mutexattr; +#define MY_MUTEX_INIT_FAST &my_fast_mutexattr +#else +#define MY_MUTEX_INIT_FAST NULL +#endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_errorcheck_mutexattr; +#define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr +#else +#define MY_MUTEX_INIT_ERRCHK NULL +#endif + +extern my_bool my_thread_global_init(void); +extern void my_thread_global_end(void); +extern my_bool my_thread_init(void); +extern void my_thread_end(void); +extern const char *my_thread_name(void); +extern long my_thread_id(void); +extern int pthread_no_free(void *); +extern int pthread_dummy(int); + +/* All thread specific variables are in the following struct */ + +#define THREAD_NAME_SIZE 10 +#ifndef DEFAULT_THREAD_STACK +#if SIZEOF_CHARP > 4 +/* + MySQL can survive with 32K, but some glibc libraries require > 128K stack + To resolve hostnames. Also recursive stored procedures needs stack. +*/ +#define DEFAULT_THREAD_STACK (256*1024L) +#else +#define DEFAULT_THREAD_STACK (192*1024) +#endif +#endif + +struct st_my_thread_var +{ + int thr_errno; + pthread_cond_t suspend; + pthread_mutex_t mutex; + pthread_mutex_t * volatile current_mutex; + pthread_cond_t * volatile current_cond; + pthread_t pthread_self; + long id; + int cmp_length; + int volatile abort; + my_bool init; + struct st_my_thread_var *next,**prev; + void *opt_info; +#ifndef DBUG_OFF + gptr dbug; + char name[THREAD_NAME_SIZE+1]; +#endif +}; + +extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const)); +extern uint my_thread_end_wait_time; +#define my_thread_var (_my_thread_var()) +#define my_errno my_thread_var->thr_errno +/* + Keep track of shutdown,signal, and main threads so that my_end() will not + report errors with them +*/ + +/* Which kind of thread library is in use */ + +#define THD_LIB_OTHER 1 +#define THD_LIB_NPTL 2 +#define THD_LIB_LT 4 + +extern uint thd_lib_detected; + + /* statistics_xxx functions are for not essential statistic */ + +#ifndef thread_safe_increment +#ifdef HAVE_ATOMIC_ADD +#define thread_safe_increment(V,L) atomic_inc((atomic_t*) &V) +#define thread_safe_decrement(V,L) atomic_dec((atomic_t*) &V) +#define thread_safe_add(V,C,L) atomic_add((C),(atomic_t*) &V) +#define thread_safe_sub(V,C,L) atomic_sub((C),(atomic_t*) &V) +#else +#define thread_safe_increment(V,L) \ + (pthread_mutex_lock((L)), (V)++, pthread_mutex_unlock((L))) +#define thread_safe_decrement(V,L) \ + (pthread_mutex_lock((L)), (V)--, pthread_mutex_unlock((L))) +#define thread_safe_add(V,C,L) (pthread_mutex_lock((L)), (V)+=(C), pthread_mutex_unlock((L))) +#define thread_safe_sub(V,C,L) \ + (pthread_mutex_lock((L)), (V)-=(C), pthread_mutex_unlock((L))) +#endif /* HAVE_ATOMIC_ADD */ +#ifdef SAFE_STATISTICS +#define statistic_increment(V,L) thread_safe_increment((V),(L)) +#define statistic_decrement(V,L) thread_safe_decrement((V),(L)) +#define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) +#else +#define statistic_decrement(V,L) (V)-- +#define statistic_increment(V,L) (V)++ +#define statistic_add(V,C,L) (V)+=(C) +#endif /* SAFE_STATISTICS */ +#endif /* thread_safe_increment */ + +#ifdef __cplusplus +} +#endif +#endif /* _my_ptread_h */ diff --git a/code/meosdb/mysql50/my_sys.h b/code/meosdb/mysql50/my_sys.h new file mode 100644 index 0000000..9fd600f --- /dev/null +++ b/code/meosdb/mysql50/my_sys.h @@ -0,0 +1,924 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_sys_h +#define _my_sys_h +C_MODE_START + +#ifdef HAVE_AIOWAIT +#include /* Used by record-cache */ +typedef struct my_aio_result { + aio_result_t result; + int pending; +} my_aio_result; +#endif + +#ifndef THREAD +extern int NEAR my_errno; /* Last error in mysys */ +#else +#include +#endif + +#include /* for CHARSET_INFO */ +#include +#include + +#define MYSYS_PROGRAM_USES_CURSES() { error_handler_hook = my_message_curses; mysys_uses_curses=1; } +#define MYSYS_PROGRAM_DONT_USE_CURSES() { error_handler_hook = my_message_no_curses; mysys_uses_curses=0;} +#define MY_INIT(name); { my_progname= name; my_init(); } + +#define ERRMSGSIZE (SC_MAXWIDTH) /* Max length of a error message */ +#define NRERRBUFFS (2) /* Buffers for parameters */ +#define MY_FILE_ERROR ((uint) ~0) + + /* General bitmaps for my_func's */ +#define MY_FFNF 1 /* Fatal if file not found */ +#define MY_FNABP 2 /* Fatal if not all bytes read/writen */ +#define MY_NABP 4 /* Error if not all bytes read/writen */ +#define MY_FAE 8 /* Fatal if any error */ +#define MY_WME 16 /* Write message on error */ +#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */ +#define MY_IGNORE_BADFD 32 /* my_sync: ignore 'bad descriptor' errors */ +#define MY_RAID 64 /* Support for RAID */ +#define MY_FULL_IO 512 /* For my_read - loop intil I/O is complete */ +#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */ +#define MY_LINK_WARNING 32 /* my_redel() gives warning if links */ +#define MY_COPYTIME 64 /* my_redel() copys time */ +#define MY_DELETE_OLD 256 /* my_create_with_symlink() */ +#define MY_RESOLVE_LINK 128 /* my_realpath(); Only resolve links */ +#define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */ +#define MY_REDEL_MAKE_BACKUP 256 +#define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */ +#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */ +#define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */ +#define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */ +#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */ +#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ +#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy: Don't overwrite file */ +#define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ + +#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ +#define MY_GIVE_INFO 2 /* Give time info about process*/ +#define MY_DONT_FREE_DBUG 4 /* Do not call DBUG_END() in my_end() */ + +#define ME_HIGHBYTE 8 /* Shift for colours */ +#define ME_NOCUR 1 /* Don't use curses message */ +#define ME_OLDWIN 2 /* Use old window */ +#define ME_BELL 4 /* Ring bell then printing message */ +#define ME_HOLDTANG 8 /* Don't delete last keys */ +#define ME_WAITTOT 16 /* Wait for errtime secs of for a action */ +#define ME_WAITTANG 32 /* Wait for a user action */ +#define ME_NOREFRESH 64 /* Dont refresh screen */ +#define ME_NOINPUT 128 /* Dont use the input libary */ +#define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */ +#define ME_COLOUR2 ((2 << ME_HIGHBYTE)) +#define ME_COLOUR3 ((3 << ME_HIGHBYTE)) + + /* Bits in last argument to fn_format */ +#define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */ +#define MY_REPLACE_EXT 2 /* replace extension with 'ext' */ +#define MY_UNPACK_FILENAME 4 /* Unpack name (~ -> home) */ +#define MY_PACK_FILENAME 8 /* Pack name (home -> ~) */ +#define MY_RESOLVE_SYMLINKS 16 /* Resolve all symbolic links */ +#define MY_RETURN_REAL_PATH 32 /* return full path for file */ +#define MY_SAFE_PATH 64 /* Return NULL if too long path */ +#define MY_RELATIVE_PATH 128 /* name is relative to 'dir' */ + + /* My seek flags */ +#define MY_SEEK_SET 0 +#define MY_SEEK_CUR 1 +#define MY_SEEK_END 2 + + /* Some constants */ +#define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */ +#define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */ +#define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */ +#define DFLT_INIT_HITS 3 + + /* root_alloc flags */ +#define MY_KEEP_PREALLOC 1 +#define MY_MARK_BLOCKS_FREE 2 /* move used to free list and reuse them */ + + /* Internal error numbers (for assembler functions) */ +#define MY_ERRNO_EDOM 33 +#define MY_ERRNO_ERANGE 34 + + /* Bits for get_date timeflag */ +#define GETDATE_DATE_TIME 1 +#define GETDATE_SHORT_DATE 2 +#define GETDATE_HHMMSSTIME 4 +#define GETDATE_GMT 8 +#define GETDATE_FIXEDLENGTH 16 + + /* defines when allocating data */ +#ifdef SAFEMALLOC +#define my_malloc(SZ,FLAG) _mymalloc((SZ), __FILE__, __LINE__, FLAG ) +#define my_malloc_ci(SZ,FLAG) _mymalloc((SZ), sFile, uLine, FLAG ) +#define my_realloc(PTR,SZ,FLAG) _myrealloc((PTR), (SZ), __FILE__, __LINE__, FLAG ) +#define my_checkmalloc() _sanity( __FILE__, __LINE__ ) +#define my_free(PTR,FLAG) _myfree((PTR), __FILE__, __LINE__,FLAG) +#define my_memdup(A,B,C) _my_memdup((A),(B), __FILE__,__LINE__,C) +#define my_strdup(A,C) _my_strdup((A), __FILE__,__LINE__,C) +#define my_strdup_with_length(A,B,C) _my_strdup_with_length((A),(B),__FILE__,__LINE__,C) +#define TRASH(A,B) bfill(A, B, 0x8F) +#define QUICK_SAFEMALLOC sf_malloc_quick=1 +#define NORMAL_SAFEMALLOC sf_malloc_quick=0 +extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick; +extern ulonglong sf_malloc_mem_limit; + +#define CALLER_INFO_PROTO , const char *sFile, uint uLine +#define CALLER_INFO , __FILE__, __LINE__ +#define ORIG_CALLER_INFO , sFile, uLine +#else +#define my_checkmalloc() +#undef TERMINATE +#define TERMINATE(A) {} +#define QUICK_SAFEMALLOC +#define NORMAL_SAFEMALLOC +extern gptr my_malloc(uint Size,myf MyFlags); +#define my_malloc_ci(SZ,FLAG) my_malloc( SZ, FLAG ) +extern gptr my_realloc(gptr oldpoint,uint Size,myf MyFlags); +extern void my_no_flags_free(gptr ptr); +extern gptr my_memdup(const byte *from,uint length,myf MyFlags); +extern char *my_strdup(const char *from,myf MyFlags); +extern char *my_strdup_with_length(const char *from, uint length, + myf MyFlags); +/* we do use FG (as a no-op) in below so that a typo on FG is caught */ +#define my_free(PTR,FG) ((void)FG,my_no_flags_free(PTR)) +#define CALLER_INFO_PROTO /* nothing */ +#define CALLER_INFO /* nothing */ +#define ORIG_CALLER_INFO /* nothing */ +#define TRASH(A,B) /* nothing */ +#endif + +#ifdef HAVE_LARGE_PAGES +extern uint my_get_large_page_size(void); +extern gptr my_large_malloc(uint size, myf my_flags); +extern void my_large_free(gptr ptr, myf my_flags); +#else +#define my_get_large_page_size() (0) +#define my_large_malloc(A,B) my_malloc_lock((A),(B)) +#define my_large_free(A,B) my_free_lock((A),(B)) +#endif /* HAVE_LARGE_PAGES */ + +#ifdef HAVE_ALLOCA +#if defined(_AIX) && !defined(__GNUC__) && !defined(_AIX43) +#pragma alloca +#endif /* _AIX */ +#if defined(__MWERKS__) +#undef alloca +#define alloca _alloca +#endif /* __MWERKS__ */ +#if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) && ! defined(alloca) +#define alloca __builtin_alloca +#endif /* GNUC */ +#define my_alloca(SZ) alloca((size_t) (SZ)) +#define my_afree(PTR) {} +#else +#define my_alloca(SZ) my_malloc(SZ,MYF(0)) +#define my_afree(PTR) my_free(PTR,MYF(MY_WME)) +#endif /* HAVE_ALLOCA */ + +#ifdef MSDOS +#ifdef __ZTC__ +void * __CDECL halloc(long count,size_t length); +void __CDECL hfree(void *ptr); +#endif +#if defined(USE_HALLOC) +#if defined(_VCM_) || defined(M_IC80386) +#undef USE_HALLOC +#endif +#endif +#ifdef USE_HALLOC +#define malloc(a) halloc((long) (a),1) +#define free(a) hfree(a) +#endif +#endif /* MSDOS */ + +#ifndef errno /* did we already get it? */ +#ifdef HAVE_ERRNO_AS_DEFINE +#include /* errno is a define */ +#else +extern int errno; /* declare errno */ +#endif +#endif /* #ifndef errno */ +extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; +extern char *home_dir; /* Home directory for user */ +extern const char *my_progname; /* program-name (printed in errors) */ +extern char NEAR curr_dir[]; /* Current directory for user */ +extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); +extern int (*fatal_error_handler_hook)(uint my_err, const char *str, + myf MyFlags); +extern uint my_file_limit; + +#ifdef HAVE_LARGE_PAGES +extern my_bool my_use_large_pages; +extern uint my_large_page_size; +#endif + +/* charsets */ +extern CHARSET_INFO *default_charset_info; +extern CHARSET_INFO *all_charsets[256]; +extern CHARSET_INFO compiled_charsets[]; + +/* statistics */ +extern ulong my_file_opened,my_stream_opened, my_tmp_file_created; +extern uint mysys_usage_id; +extern my_bool my_init_done; + + /* Point to current my_message() */ +extern void (*my_sigtstp_cleanup)(void), + /* Executed before jump to shell */ + (*my_sigtstp_restart)(void), + (*my_abort_hook)(int); + /* Executed when comming from shell */ +extern int NEAR my_umask, /* Default creation mask */ + NEAR my_umask_dir, + NEAR my_recived_signals, /* Signals we have got */ + NEAR my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ + NEAR my_dont_interrupt; /* call remember_intr when set */ +extern my_bool NEAR mysys_uses_curses, my_use_symdir; +extern ulong sf_malloc_cur_memory, sf_malloc_max_memory; + +extern ulong my_default_record_cache_size; +extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io, + NEAR my_disable_flush_key_blocks, NEAR my_disable_symlinks; +extern char wild_many,wild_one,wild_prefix; +extern const char *charsets_dir; +/* from default.c */ +extern char *my_defaults_extra_file; +extern const char *my_defaults_group_suffix; +extern const char *my_defaults_file; + +extern my_bool timed_mutexes; + +typedef struct wild_file_pack /* Struct to hold info when selecting files */ +{ + uint wilds; /* How many wildcards */ + uint not_pos; /* Start of not-theese-files */ + my_string *wild; /* Pointer to wildcards */ +} WF_PACK; + +enum loglevel { + ERROR_LEVEL, + WARNING_LEVEL, + INFORMATION_LEVEL +}; + +enum cache_type +{ + TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE, + SEQ_READ_APPEND /* sequential read or append */, + READ_FIFO, READ_NET,WRITE_NET}; + +enum flush_type +{ + FLUSH_KEEP, FLUSH_RELEASE, FLUSH_IGNORE_CHANGED, FLUSH_FORCE_WRITE +}; + +typedef struct st_record_cache /* Used when cacheing records */ +{ + File file; + int rc_seek,error,inited; + uint rc_length,read_length,reclength; + my_off_t rc_record_pos,end_of_file; + byte *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos; +#ifdef HAVE_AIOWAIT + int use_async_io; + my_aio_result aio_result; +#endif + enum cache_type type; +} RECORD_CACHE; + +enum file_type +{ + UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, STREAM_BY_FOPEN, STREAM_BY_FDOPEN, + FILE_BY_MKSTEMP, FILE_BY_DUP +}; + +struct st_my_file_info +{ + my_string name; + enum file_type type; +#if defined(THREAD) && !defined(HAVE_PREAD) + pthread_mutex_t mutex; +#endif +}; + +extern struct st_my_file_info *my_file_info; + +typedef struct st_dynamic_array +{ + char *buffer; + uint elements,max_element; + uint alloc_increment; + uint size_of_element; +} DYNAMIC_ARRAY; + +typedef struct st_my_tmpdir +{ + DYNAMIC_ARRAY full_list; + char **list; + uint cur, max; +#ifdef THREAD + pthread_mutex_t mutex; +#endif +} MY_TMPDIR; + +typedef struct st_dynamic_string +{ + char *str; + uint length,max_length,alloc_increment; +} DYNAMIC_STRING; + +struct st_io_cache; +typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*); + +#ifdef THREAD +typedef struct st_io_cache_share +{ + pthread_mutex_t mutex; /* To sync on reads into buffer. */ + pthread_cond_t cond; /* To wait for signals. */ + pthread_cond_t cond_writer; /* For a synchronized writer. */ + /* Offset in file corresponding to the first byte of buffer. */ + my_off_t pos_in_file; + /* If a synchronized write cache is the source of the data. */ + struct st_io_cache *source_cache; + byte *buffer; /* The read buffer. */ + byte *read_end; /* Behind last valid byte of buffer. */ + int running_threads; /* threads not in lock. */ + int total_threads; /* threads sharing the cache. */ + int error; /* Last error. */ +#ifdef NOT_YET_IMPLEMENTED + /* whether the structure should be free'd */ + my_bool alloced; +#endif +} IO_CACHE_SHARE; +#endif + +typedef struct st_io_cache /* Used when cacheing files */ +{ + /* Offset in file corresponding to the first byte of byte* buffer. */ + my_off_t pos_in_file; + /* + The offset of end of file for READ_CACHE and WRITE_CACHE. + For SEQ_READ_APPEND it the maximum of the actual end of file and + the position represented by read_end. + */ + my_off_t end_of_file; + /* Points to current read position in the buffer */ + byte *read_pos; + /* the non-inclusive boundary in the buffer for the currently valid read */ + byte *read_end; + byte *buffer; /* The read buffer */ + /* Used in ASYNC_IO */ + byte *request_pos; + + /* Only used in WRITE caches and in SEQ_READ_APPEND to buffer writes */ + byte *write_buffer; + /* + Only used in SEQ_READ_APPEND, and points to the current read position + in the write buffer. Note that reads in SEQ_READ_APPEND caches can + happen from both read buffer (byte* buffer) and write buffer + (byte* write_buffer). + */ + byte *append_read_pos; + /* Points to current write position in the write buffer */ + byte *write_pos; + /* The non-inclusive boundary of the valid write area */ + byte *write_end; + + /* + Current_pos and current_end are convenience variables used by + my_b_tell() and other routines that need to know the current offset + current_pos points to &write_pos, and current_end to &write_end in a + WRITE_CACHE, and &read_pos and &read_end respectively otherwise + */ + byte **current_pos, **current_end; +#ifdef THREAD + /* + The lock is for append buffer used in SEQ_READ_APPEND cache + need mutex copying from append buffer to read buffer. + */ + pthread_mutex_t append_buffer_lock; + /* + The following is used when several threads are reading the + same file in parallel. They are synchronized on disk + accesses reading the cached part of the file asynchronously. + It should be set to NULL to disable the feature. Only + READ_CACHE mode is supported. + */ + IO_CACHE_SHARE *share; +#endif + /* + A caller will use my_b_read() macro to read from the cache + if the data is already in cache, it will be simply copied with + memcpy() and internal variables will be accordinging updated with + no functions invoked. However, if the data is not fully in the cache, + my_b_read() will call read_function to fetch the data. read_function + must never be invoked directly. + */ + int (*read_function)(struct st_io_cache *,byte *,uint); + /* + Same idea as in the case of read_function, except my_b_write() needs to + be replaced with my_b_append() for a SEQ_READ_APPEND cache + */ + int (*write_function)(struct st_io_cache *,const byte *,uint); + /* + Specifies the type of the cache. Depending on the type of the cache + certain operations might not be available and yield unpredicatable + results. Details to be documented later + */ + enum cache_type type; + /* + Callbacks when the actual read I/O happens. These were added and + are currently used for binary logging of LOAD DATA INFILE - when a + block is read from the file, we create a block create/append event, and + when IO_CACHE is closed, we create an end event. These functions could, + of course be used for other things + */ + IO_CACHE_CALLBACK pre_read; + IO_CACHE_CALLBACK post_read; + IO_CACHE_CALLBACK pre_close; + /* + Counts the number of times, when we were forced to use disk. We use it to + increase the binlog_cache_disk_use status variable. + */ + ulong disk_writes; + void* arg; /* for use by pre/post_read */ + char *file_name; /* if used with 'open_cached_file' */ + char *dir,*prefix; + File file; /* file descriptor */ + /* + seek_not_done is set by my_b_seek() to inform the upcoming read/write + operation that a seek needs to be preformed prior to the actual I/O + error is 0 if the cache operation was successful, -1 if there was a + "hard" error, and the actual number of I/O-ed bytes if the read/write was + partial. + */ + int seek_not_done,error; + /* buffer_length is memory size allocated for buffer or write_buffer */ + uint buffer_length; + /* read_length is the same as buffer_length except when we use async io */ + uint read_length; + myf myflags; /* Flags used to my_read/my_write */ + /* + alloced_buffer is 1 if the buffer was allocated by init_io_cache() and + 0 if it was supplied by the user. + Currently READ_NET is the only one that will use a buffer allocated + somewhere else + */ + my_bool alloced_buffer; +#ifdef HAVE_AIOWAIT + /* + As inidicated by ifdef, this is for async I/O, which is not currently + used (because it's not reliable on all systems) + */ + uint inited; + my_off_t aio_read_pos; + my_aio_result aio_result; +#endif +} IO_CACHE; + +typedef int (*qsort2_cmp)(const void *, const void *, const void *); + + /* defines for mf_iocache */ + + /* Test if buffer is inited */ +#define my_b_clear(info) (info)->buffer=0 +#define my_b_inited(info) (info)->buffer +#define my_b_EOF INT_MIN + +#define my_b_read(info,Buffer,Count) \ + ((info)->read_pos + (Count) <= (info)->read_end ?\ + (memcpy(Buffer,(info)->read_pos,(size_t) (Count)), \ + ((info)->read_pos+=(Count)),0) :\ + (*(info)->read_function)((info),Buffer,Count)) + +#define my_b_write(info,Buffer,Count) \ + ((info)->write_pos + (Count) <=(info)->write_end ?\ + (memcpy((info)->write_pos, (Buffer), (size_t)(Count)),\ + ((info)->write_pos+=(Count)),0) : \ + (*(info)->write_function)((info),(Buffer),(Count))) + +#define my_b_get(info) \ + ((info)->read_pos != (info)->read_end ?\ + ((info)->read_pos++, (int) (uchar) (info)->read_pos[-1]) :\ + _my_b_get(info)) + + /* my_b_write_byte dosn't have any err-check */ +#define my_b_write_byte(info,chr) \ + (((info)->write_pos < (info)->write_end) ?\ + ((*(info)->write_pos++)=(chr)) :\ + (_my_b_write(info,0,0) , ((*(info)->write_pos++)=(chr)))) + +#define my_b_fill_cache(info) \ + (((info)->read_end=(info)->read_pos),(*(info)->read_function)(info,0,0)) + +#define my_b_tell(info) ((info)->pos_in_file + \ + (uint) (*(info)->current_pos - (info)->request_pos)) + +/* tell write offset in the SEQ_APPEND cache */ +my_off_t my_b_append_tell(IO_CACHE* info); +my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ + +#define my_b_bytes_in_cache(info) (uint) (*(info)->current_end - \ + *(info)->current_pos) + +typedef uint32 ha_checksum; + +/* Define the type of function to be passed to process_default_option_files */ +typedef int (*Process_option_func)(void *ctx, const char *group_name, + const char *option); + +#include + + + /* Prototypes for mysys and my_func functions */ + +extern int my_copy(const char *from,const char *to,myf MyFlags); +extern int my_append(const char *from,const char *to,myf MyFlags); +extern int my_delete(const char *name,myf MyFlags); +extern int my_getwd(my_string buf,uint size,myf MyFlags); +extern int my_setwd(const char *dir,myf MyFlags); +extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags); +extern gptr my_once_alloc(uint Size,myf MyFlags); +extern void my_once_free(void); +extern char *my_once_strdup(const char *src,myf myflags); +extern char *my_once_memdup(const char *src, uint len, myf myflags); +extern File my_open(const char *FileName,int Flags,myf MyFlags); +extern File my_register_filename(File fd, const char *FileName, + enum file_type type_of_file, + uint error_message_number, myf MyFlags); +extern File my_create(const char *FileName,int CreateFlags, + int AccsesFlags, myf MyFlags); +extern int my_close(File Filedes,myf MyFlags); +extern File my_dup(File file, myf MyFlags); +extern int my_mkdir(const char *dir, int Flags, myf MyFlags); +extern int my_readlink(char *to, const char *filename, myf MyFlags); +extern int my_realpath(char *to, const char *filename, myf MyFlags); +extern File my_create_with_symlink(const char *linkname, const char *filename, + int createflags, int access_flags, + myf MyFlags); +extern int my_delete_with_symlink(const char *name, myf MyFlags); +extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags); +extern int my_symlink(const char *content, const char *linkname, myf MyFlags); +extern uint my_read(File Filedes,byte *Buffer,uint Count,myf MyFlags); +extern uint my_pread(File Filedes,byte *Buffer,uint Count,my_off_t offset, + myf MyFlags); +extern int my_rename(const char *from,const char *to,myf MyFlags); +extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_tell(File fd,myf MyFlags); +extern uint my_write(File Filedes,const byte *Buffer,uint Count, + myf MyFlags); +extern uint my_pwrite(File Filedes,const byte *Buffer,uint Count, + my_off_t offset,myf MyFlags); +extern uint my_fread(FILE *stream,byte *Buffer,uint Count,myf MyFlags); +extern uint my_fwrite(FILE *stream,const byte *Buffer,uint Count, + myf MyFlags); +extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_ftell(FILE *stream,myf MyFlags); +extern gptr _mymalloc(uint uSize,const char *sFile, + uint uLine, myf MyFlag); +extern gptr _myrealloc(gptr pPtr,uint uSize,const char *sFile, + uint uLine, myf MyFlag); +extern gptr my_multi_malloc _VARARGS((myf MyFlags, ...)); +extern void _myfree(gptr pPtr,const char *sFile,uint uLine, myf MyFlag); +extern int _sanity(const char *sFile,unsigned int uLine); +extern gptr _my_memdup(const byte *from,uint length, + const char *sFile, uint uLine,myf MyFlag); +extern my_string _my_strdup(const char *from, const char *sFile, uint uLine, + myf MyFlag); +extern char *_my_strdup_with_length(const char *from, uint length, + const char *sFile, uint uLine, + myf MyFlag); + +/* implemented in my_memmem.c */ +extern void *my_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); + + +#ifdef __WIN__ +extern int my_access(const char *path, int amode); +extern File my_sopen(const char *path, int oflag, int shflag, int pmode); +#else +#define my_access access +#endif +extern int check_if_legal_filename(const char *path); + +#if defined(__WIN__) && defined(__NT__) +extern int nt_share_delete(const char *name,myf MyFlags); +#define my_delete_allow_opened(fname,flags) nt_share_delete((fname),(flags)) +#else +#define my_delete_allow_opened(fname,flags) my_delete((fname),(flags)) +#endif + +#ifndef TERMINATE +extern void TERMINATE(FILE *file); +#endif +extern void init_glob_errs(void); +extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); +extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); +extern int my_fclose(FILE *fd,myf MyFlags); +extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); +extern int my_sync(File fd, myf my_flags); +extern int my_error _VARARGS((int nr,myf MyFlags, ...)); +extern int my_printf_error _VARARGS((uint my_err, const char *format, + myf MyFlags, ...)) + ATTRIBUTE_FORMAT(printf, 2, 4); +extern int my_error_register(const char **errmsgs, int first, int last); +extern const char **my_error_unregister(int first, int last); +extern int my_message(uint my_err, const char *str,myf MyFlags); +extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); +extern int my_message_curses(uint my_err, const char *str,myf MyFlags); +extern my_bool my_init(void); +extern void my_end(int infoflag); +extern int my_redel(const char *from, const char *to, int MyFlags); +extern int my_copystat(const char *from, const char *to, int MyFlags); +extern my_string my_filename(File fd); + +#ifndef THREAD +extern void dont_break(void); +extern void allow_break(void); +#else +#define dont_break() +#define allow_break() +#endif + +extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist); +extern char *my_tmpdir(MY_TMPDIR *tmpdir); +extern void free_tmpdir(MY_TMPDIR *tmpdir); + +extern void my_remember_signal(int signal_number,sig_handler (*func)(int)); +extern uint dirname_part(my_string to,const char *name); +extern uint dirname_length(const char *name); +#define base_name(A) (A+dirname_length(A)) +extern int test_if_hard_path(const char *dir_name); +extern my_bool has_path(const char *name); +extern char *convert_dirname(char *to, const char *from, const char *from_end); +extern void to_unix_path(my_string name); +extern my_string fn_ext(const char *name); +extern my_string fn_same(my_string toname,const char *name,int flag); +extern my_string fn_format(my_string to,const char *name,const char *dir, + const char *form, uint flag); +extern size_s strlength(const char *str); +extern void pack_dirname(my_string to,const char *from); +extern uint unpack_dirname(my_string to,const char *from); +extern uint cleanup_dirname(my_string to,const char *from); +extern uint system_filename(my_string to,const char *from); +extern uint unpack_filename(my_string to,const char *from); +extern my_string intern_filename(my_string to,const char *from); +extern my_string directory_file_name(my_string dst, const char *src); +extern int pack_filename(my_string to, const char *name, size_s max_length); +extern my_string my_path(my_string to,const char *progname, + const char *own_pathname_part); +extern my_string my_load_path(my_string to, const char *path, + const char *own_path_prefix); +extern int wild_compare(const char *str,const char *wildstr,pbool str_is_pattern); +extern WF_PACK *wf_comp(my_string str); +extern int wf_test(struct wild_file_pack *wf_pack,const char *name); +extern void wf_end(struct wild_file_pack *buffer); +extern size_s strip_sp(my_string str); +extern void get_date(my_string to,int timeflag,time_t use_time); +extern void soundex(CHARSET_INFO *, my_string out_pntr, my_string in_pntr,pbool remove_garbage); +extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file, + uint reclength,enum cache_type type, + pbool use_async_io); +extern int read_cache_record(RECORD_CACHE *info,byte *to); +extern int end_record_cache(RECORD_CACHE *info); +extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos, + const byte *record,uint length); +extern int flush_write_cache(RECORD_CACHE *info); +extern long my_clock(void); +extern sig_handler sigtstp_handler(int signal_number); +extern void handle_recived_signals(void); + +extern sig_handler my_set_alarm_variable(int signo); +extern void my_string_ptr_sort(void *base,uint items,size_s size); +extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, + size_s size_of_element,uchar *buffer[]); +extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); +extern qsort2_cmp get_ptr_compare(uint); +void my_store_ptr(byte *buff, uint pack_length, my_off_t pos); +my_off_t my_get_ptr(byte *ptr, uint pack_length); +extern int init_io_cache(IO_CACHE *info,File file,uint cachesize, + enum cache_type type,my_off_t seek_offset, + pbool use_async_io, myf cache_myflags); +extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, + my_off_t seek_offset,pbool use_async_io, + pbool clear_cache); +extern void setup_io_cache(IO_CACHE* info); +extern int _my_b_read(IO_CACHE *info,byte *Buffer,uint Count); +#ifdef THREAD +extern int _my_b_read_r(IO_CACHE *info,byte *Buffer,uint Count); +extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, + IO_CACHE *write_cache, uint num_threads); +extern void remove_io_thread(IO_CACHE *info); +#endif +extern int _my_b_seq_read(IO_CACHE *info,byte *Buffer,uint Count); +extern int _my_b_net_read(IO_CACHE *info,byte *Buffer,uint Count); +extern int _my_b_get(IO_CACHE *info); +extern int _my_b_async_read(IO_CACHE *info,byte *Buffer,uint Count); +extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count); +extern int my_b_append(IO_CACHE *info,const byte *Buffer,uint Count); +extern int my_b_safe_write(IO_CACHE *info,const byte *Buffer,uint Count); + +extern int my_block_write(IO_CACHE *info, const byte *Buffer, + uint Count, my_off_t pos); +extern int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock); + +#define flush_io_cache(info) my_b_flush_io_cache((info),1) + +extern int end_io_cache(IO_CACHE *info); +extern uint my_b_fill(IO_CACHE *info); +extern void my_b_seek(IO_CACHE *info,my_off_t pos); +extern uint my_b_gets(IO_CACHE *info, char *to, uint max_length); +extern my_off_t my_b_filelength(IO_CACHE *info); +extern uint my_b_printf(IO_CACHE *info, const char* fmt, ...); +extern uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); +extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, + const char *prefix, uint cache_size, + myf cache_myflags); +extern my_bool real_open_cached_file(IO_CACHE *cache); +extern void close_cached_file(IO_CACHE *cache); +File create_temp_file(char *to, const char *dir, const char *pfx, + int mode, myf MyFlags); +#define my_init_dynamic_array(A,B,C,D) init_dynamic_array(A,B,C,D CALLER_INFO) +#define my_init_dynamic_array_ci(A,B,C,D) init_dynamic_array(A,B,C,D ORIG_CALLER_INFO) +extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size, + uint init_alloc,uint alloc_increment + CALLER_INFO_PROTO); +extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element); +extern byte *alloc_dynamic(DYNAMIC_ARRAY *array); +extern byte *pop_dynamic(DYNAMIC_ARRAY*); +extern my_bool set_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index); +extern void get_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index); +extern void delete_dynamic(DYNAMIC_ARRAY *array); +extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index); +extern void freeze_size(DYNAMIC_ARRAY *array); +#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element) +#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) +#define push_dynamic(A,B) insert_dynamic(A,B) +#define reset_dynamic(array) ((array)->elements= 0) + +extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, + uint init_alloc,uint alloc_increment); +extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append); +my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, + uint length); +extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, + ...); +extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str); +extern my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size); +extern void dynstr_free(DYNAMIC_STRING *str); +#ifdef HAVE_MLOCK +extern byte *my_malloc_lock(uint length,myf flags); +extern void my_free_lock(byte *ptr,myf flags); +#else +#define my_malloc_lock(A,B) my_malloc((A),(B)) +#define my_free_lock(A,B) my_free((A),(B)) +#endif +#define alloc_root_inited(A) ((A)->min_malloc != 0) +#define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8) +#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; (A)->min_malloc=0;} while(0) +extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size, + uint pre_alloc_size); +extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); +extern gptr multi_alloc_root(MEM_ROOT *mem_root, ...); +extern void free_root(MEM_ROOT *root, myf MyFLAGS); +extern void set_prealloc_root(MEM_ROOT *root, char *ptr); +extern void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, + uint prealloc_size); +extern char *strdup_root(MEM_ROOT *root,const char *str); +extern char *strmake_root(MEM_ROOT *root,const char *str,uint len); +extern char *memdup_root(MEM_ROOT *root,const char *str,uint len); +extern int get_defaults_options(int argc, char **argv, + char **defaults, char **extra_defaults, + char **group_suffix); +extern int load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv); +extern int modify_defaults_file(const char *file_location, const char *option, + const char *option_value, + const char *section_name, int remove_option); +extern int my_search_option_files(const char *conf_file, int *argc, + char ***argv, uint *args_used, + Process_option_func func, void *func_ctx); +extern void free_defaults(char **argv); +extern void my_print_default_files(const char *conf_file); +extern void print_defaults(const char *conf_file, const char **groups); +extern my_bool my_compress(byte *, ulong *, ulong *); +extern my_bool my_uncompress(byte *, ulong *, ulong *); +extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen); +extern ha_checksum my_checksum(ha_checksum crc, const byte *mem, uint count); +extern uint my_bit_log2(ulong value); +extern uint my_count_bits(ulonglong v); +extern uint my_count_bits_ushort(ushort v); +extern void my_sleep(ulong m_seconds); +extern ulong crc32(ulong crc, const uchar *buf, uint len); +extern uint my_set_max_open_files(uint files); +void my_free_open_file_info(void); + +ulonglong my_getsystime(void); +my_bool my_gethwaddr(uchar *to); + +#ifdef HAVE_SYS_MMAN_H +#include + +#ifndef MAP_NOSYNC +#define MAP_NOSYNC 0 +#endif + +#define my_mmap(a,b,c,d,e,f) mmap(a,b,c,d,e,f) +#define my_munmap(a,b) munmap((a),(b)) + +#else +/* not a complete set of mmap() flags, but only those that nesessary */ +#define PROT_READ 1 +#define PROT_WRITE 2 +#define MAP_SHARED 0x0001 +#define MAP_NOSYNC 0x0800 +#define MAP_FAILED ((void *)-1) +#define MS_SYNC 0x0000 + +#ifndef __NETWARE__ +#define HAVE_MMAP +#endif + +void *my_mmap(void *, size_t, int, int, int, my_off_t); +int my_munmap(void *, size_t); +#endif + +/* my_getpagesize */ +#ifdef HAVE_GETPAGESIZE +#define my_getpagesize() getpagesize() +#else +int my_getpagesize(void); +#endif + +int my_msync(int, void *, size_t, int); + +/* character sets */ +extern uint get_charset_number(const char *cs_name, uint cs_flags); +extern uint get_collation_number(const char *name); +extern const char *get_charset_name(uint cs_number); + +extern CHARSET_INFO *get_charset(uint cs_number, myf flags); +extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); +extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, + uint cs_flags, myf my_flags); +extern void free_charsets(void); +extern char *get_charsets_dir(char *buf); +extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); +extern my_bool init_compiled_charsets(myf flags); +extern void add_compiled_collation(CHARSET_INFO *cs); +extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, + char *to, ulong to_length, + const char *from, ulong length); +#ifdef __WIN__ +#define BACKSLASH_MBTAIL +/* File system character set */ +extern CHARSET_INFO *fs_character_set(void); +#endif +extern ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info, + char *to, ulong to_length, + const char *from, ulong length); + +extern void thd_increment_bytes_sent(ulong length); +extern void thd_increment_bytes_received(ulong length); +extern void thd_increment_net_big_packet_count(ulong length); + +#ifdef __WIN__ +extern my_bool have_tcpip; /* Is set if tcpip is used */ + +/* implemented in my_windac.c */ + +int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror, + DWORD owner_rights, DWORD everybody_rights); + +void my_security_attr_free(SECURITY_ATTRIBUTES *sa); + +/* implemented in my_conio.c */ +char* my_cgets(char *string, unsigned long clen, unsigned long* plen); + +#endif +#ifdef __NETWARE__ +void netware_reg_user(const char *ip, const char *user, + const char *application); +#endif + +C_MODE_END +#include "raid.h" +#endif /* _my_sys_h */ diff --git a/code/meosdb/mysql50/my_xml.h b/code/meosdb/mysql50/my_xml.h new file mode 100644 index 0000000..0e728ba --- /dev/null +++ b/code/meosdb/mysql50/my_xml.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + + +#ifndef _my_xml_h +#define _my_xml_h + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MY_XML_OK 0 +#define MY_XML_ERROR 1 + +typedef struct xml_stack_st +{ + char errstr[128]; + char attr[128]; + char *attrend; + const char *beg; + const char *cur; + const char *end; + void *user_data; + int (*enter)(struct xml_stack_st *st,const char *val, uint len); + int (*value)(struct xml_stack_st *st,const char *val, uint len); + int (*leave_xml)(struct xml_stack_st *st,const char *val, uint len); +} MY_XML_PARSER; + +void my_xml_parser_create(MY_XML_PARSER *st); +void my_xml_parser_free(MY_XML_PARSER *st); +int my_xml_parse(MY_XML_PARSER *st,const char *str, uint len); + +void my_xml_set_value_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + uint len)); +void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + uint len)); +void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + uint len)); +void my_xml_set_user_data(MY_XML_PARSER *st, void *); + +uint my_xml_error_pos(MY_XML_PARSER *st); +uint my_xml_error_lineno(MY_XML_PARSER *st); + +const char *my_xml_error_string(MY_XML_PARSER *st); + +#ifdef __cplusplus +} +#endif + +#endif /* _my_xml_h */ diff --git a/code/meosdb/mysql50/mysql.h b/code/meosdb/mysql50/mysql.h new file mode 100644 index 0000000..aec3345 --- /dev/null +++ b/code/meosdb/mysql50/mysql.h @@ -0,0 +1,864 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + This file defines the client API to MySQL and also the ABI of the + dynamically linked libmysqlclient. + + The ABI should never be changed in a released product of MySQL + thus you need to take great care when changing the file. In case + the file is changed so the ABI is broken, you must also + update the SHAREDLIB_MAJOR_VERSION in configure.in . + +*/ + +#ifndef _mysql_h +#define _mysql_h + +#ifdef __CYGWIN__ /* CYGWIN implements a UNIX API */ +#undef WIN +#undef _WIN +#undef _WIN32 +#undef _WIN64 +#undef __WIN__ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _global_h /* If not standard header */ +#include +#ifdef __LCC__ +#include /* For windows */ +#endif +typedef char my_bool; +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__WIN__) +#define __WIN__ +#endif +#if !defined(__WIN__) +#define STDCALL +#else +#define STDCALL __stdcall +#endif +typedef char * gptr; + +#ifndef my_socket_defined +#ifdef __WIN__ +#define my_socket SOCKET +#else +typedef int my_socket; +#endif /* __WIN__ */ +#endif /* my_socket_defined */ +#endif /* _global_h */ + +#include "mysql_version.h" +#include "mysql_com.h" +#include "mysql_time.h" +#include "typelib.h" + +#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ + +extern unsigned int mysql_port; +extern char *mysql_unix_port; + +#define CLIENT_NET_READ_TIMEOUT 365*24*3600 /* Timeout on read */ +#define CLIENT_NET_WRITE_TIMEOUT 365*24*3600 /* Timeout on write */ + +#ifdef __NETWARE__ +#pragma pack(push, 8) /* 8 byte alignment */ +#endif + +#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) +#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) +#define IS_BLOB(n) ((n) & BLOB_FLAG) +#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR || (t) == FIELD_TYPE_NEWDECIMAL) +#define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG) +#define INTERNAL_NUM_FIELD(f) (((f)->type <= FIELD_TYPE_INT24 && ((f)->type != FIELD_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == FIELD_TYPE_YEAR) +#define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING) + + +typedef struct st_mysql_field { + char *name; /* Name of column */ + char *org_name; /* Original column name, if an alias */ + char *table; /* Table of column if column was a field */ + char *org_table; /* Org table name, if table was an alias */ + char *db; /* Database for table */ + char *catalog; /* Catalog for table */ + char *def; /* Default value (set by mysql_list_fields) */ + unsigned long length; /* Width of column (create length) */ + unsigned long max_length; /* Max width for selected set */ + unsigned int name_length; + unsigned int org_name_length; + unsigned int table_length; + unsigned int org_table_length; + unsigned int db_length; + unsigned int catalog_length; + unsigned int def_length; + unsigned int flags; /* Div flags */ + unsigned int decimals; /* Number of decimals in field */ + unsigned int charsetnr; /* Character set */ + enum enum_field_types type; /* Type of field. See mysql_com.h for types */ +} MYSQL_FIELD; + +typedef char **MYSQL_ROW; /* return data as array of strings */ +typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */ + +#ifndef _global_h +#if defined(NO_CLIENT_LONG_LONG) +typedef unsigned long my_ulonglong; +#elif defined (__WIN__) +typedef unsigned __int64 my_ulonglong; +#else +typedef unsigned long long my_ulonglong; +#endif +#endif + +#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0) + +/* backward compatibility define - to be removed eventually */ +#define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED + +typedef struct st_mysql_rows { + struct st_mysql_rows *next; /* list of rows */ + MYSQL_ROW data; + unsigned long length; +} MYSQL_ROWS; + +typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ + +#include "my_alloc.h" + +typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; +typedef struct st_mysql_data { + my_ulonglong rows; + unsigned int fields; + MYSQL_ROWS *data; + MEM_ROOT alloc; + /* extra info for embedded library */ + struct embedded_query_result *embedded_info; +} MYSQL_DATA; + +enum mysql_option +{ + MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, + MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, + MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, + MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, + MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, + MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT +}; + +struct st_mysql_options { + unsigned int connect_timeout, read_timeout, write_timeout; + unsigned int port, protocol; + unsigned long client_flag; + char *host,*user,*password,*unix_socket,*db; + struct st_dynamic_array *init_commands; + char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; + char *ssl_key; /* PEM key file */ + char *ssl_cert; /* PEM cert file */ + char *ssl_ca; /* PEM CA file */ + char *ssl_capath; /* PEM directory of CA-s? */ + char *ssl_cipher; /* cipher to use */ + char *shared_memory_base_name; + unsigned long max_allowed_packet; + my_bool use_ssl; /* if to use SSL or not */ + my_bool compress,named_pipe; + /* + On connect, find out the replication role of the server, and + establish connections to all the peers + */ + my_bool rpl_probe; + /* + Each call to mysql_real_query() will parse it to tell if it is a read + or a write, and direct it to the slave or the master + */ + my_bool rpl_parse; + /* + If set, never read from a master, only from slave, when doing + a read that is replication-aware + */ + my_bool no_master_reads; +#if !defined(CHECK_EMBEDDED_DIFFERENCES) || defined(EMBEDDED_LIBRARY) + my_bool separate_thread; +#endif + enum mysql_option methods_to_use; + char *client_ip; + /* Refuse client connecting to server if it uses old (pre-4.1.1) protocol */ + my_bool secure_auth; + /* 0 - never report, 1 - always report (default) */ + my_bool report_data_truncation; + + /* function pointers for local infile support */ + int (*local_infile_init)(void **, const char *, void *); + int (*local_infile_read)(void *, char *, unsigned int); + void (*local_infile_end)(void *); + int (*local_infile_error)(void *, char *, unsigned int); + void *local_infile_userdata; +}; + +enum mysql_status +{ + MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,MYSQL_STATUS_USE_RESULT +}; + +enum mysql_protocol_type +{ + MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET, + MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY +}; +/* + There are three types of queries - the ones that have to go to + the master, the ones that go to a slave, and the adminstrative + type which must happen on the pivot connectioin +*/ +enum mysql_rpl_type +{ + MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, MYSQL_RPL_ADMIN +}; + +typedef struct character_set +{ + unsigned int number; /* character set number */ + unsigned int state; /* character set state */ + const char *csname; /* collation name */ + const char *name; /* character set name */ + const char *comment; /* comment */ + const char *dir; /* character set directory */ + unsigned int mbminlen; /* min. length for multibyte strings */ + unsigned int mbmaxlen; /* max. length for multibyte strings */ +} MY_CHARSET_INFO; + +struct st_mysql_methods; +struct st_mysql_stmt; + +typedef struct st_mysql +{ + NET net; /* Communication parameters */ + gptr connector_fd; /* ConnectorFd for SSL */ + char *host,*user,*passwd,*unix_socket,*server_version,*host_info,*info; + char *db; + struct charset_info_st *charset; + MYSQL_FIELD *fields; + MEM_ROOT field_alloc; + my_ulonglong affected_rows; + my_ulonglong insert_id; /* id if insert on table with NEXTNR */ + my_ulonglong extra_info; /* Not used */ + unsigned long thread_id; /* Id for connection in server */ + unsigned long packet_length; + unsigned int port; + unsigned long client_flag,server_capabilities; + unsigned int protocol_version; + unsigned int field_count; + unsigned int server_status; + unsigned int server_language; + unsigned int warning_count; + struct st_mysql_options options; + enum mysql_status status; + my_bool free_me; /* If free in mysql_close */ + my_bool reconnect; /* set to 1 if automatic reconnect */ + + /* session-wide random string */ + char scramble[SCRAMBLE_LENGTH+1]; + + /* + Set if this is the original connection, not a master or a slave we have + added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave() + */ + my_bool rpl_pivot; + /* + Pointers to the master, and the next slave connections, points to + itself if lone connection. + */ + struct st_mysql* master, *next_slave; + + struct st_mysql* last_used_slave; /* needed for round-robin slave pick */ + /* needed for send/read/store/use result to work correctly with replication */ + struct st_mysql* last_used_con; + + LIST *stmts; /* list of all statements */ + const struct st_mysql_methods *methods; + void *thd; + /* + Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag + from mysql_stmt_close if close had to cancel result set of this object. + */ + my_bool *unbuffered_fetch_owner; +#if defined(EMBEDDED_LIBRARY) || defined(EMBEDDED_LIBRARY_COMPATIBLE) || MYSQL_VERSION_ID >= 50100 + /* needed for embedded server - no net buffer to store the 'info' */ + char *info_buffer; +#endif +} MYSQL; + +typedef struct st_mysql_res { + my_ulonglong row_count; + MYSQL_FIELD *fields; + MYSQL_DATA *data; + MYSQL_ROWS *data_cursor; + unsigned long *lengths; /* column lengths of current row */ + MYSQL *handle; /* for unbuffered reads */ + MEM_ROOT field_alloc; + unsigned int field_count, current_field; + MYSQL_ROW row; /* If unbuffered read */ + MYSQL_ROW current_row; /* buffer to current row */ + my_bool eof; /* Used by mysql_fetch_row */ + /* mysql_stmt_close() had to cancel this result */ + my_bool unbuffered_fetch_cancelled; + const struct st_mysql_methods *methods; +} MYSQL_RES; + +#define MAX_MYSQL_MANAGER_ERR 256 +#define MAX_MYSQL_MANAGER_MSG 256 + +#define MANAGER_OK 200 +#define MANAGER_INFO 250 +#define MANAGER_ACCESS 401 +#define MANAGER_CLIENT_ERR 450 +#define MANAGER_INTERNAL_ERR 500 + +#if !defined(MYSQL_SERVER) && !defined(MYSQL_CLIENT) +#define MYSQL_CLIENT +#endif + + +typedef struct st_mysql_manager +{ + NET net; + char *host,*user,*passwd; + unsigned int port; + my_bool free_me; + my_bool eof; + int cmd_status; + int last_errno; + char* net_buf,*net_buf_pos,*net_data_end; + int net_buf_size; + char last_error[MAX_MYSQL_MANAGER_ERR]; +} MYSQL_MANAGER; + +typedef struct st_mysql_parameters +{ + unsigned long *p_max_allowed_packet; + unsigned long *p_net_buffer_length; +} MYSQL_PARAMETERS; + +#if !defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) +#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet) +#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length) +#endif + +/* + Set up and bring down the server; to ensure that applications will + work when linked against either the standard client library or the + embedded server library, these functions should be called. +*/ +int STDCALL mysql_server_init(int argc, char **argv, char **groups); +void STDCALL mysql_server_end(void); +/* + mysql_server_init/end need to be called when using libmysqld or + libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so + you don't need to call it explicitely; but you need to call + mysql_server_end() to free memory). The names are a bit misleading + (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general + names which suit well whether you're using libmysqld or libmysqlclient. We + intend to promote these aliases over the mysql_server* ones. +*/ +#define mysql_library_init mysql_server_init +#define mysql_library_end mysql_server_end + +MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); + +/* + Set up and bring down a thread; these function should be called + for each thread in an application which opens at least one MySQL + connection. All uses of the connection(s) should be between these + function calls. +*/ +my_bool STDCALL mysql_thread_init(void); +void STDCALL mysql_thread_end(void); + +/* + Functions to get information from the MYSQL and MYSQL_RES structures + Should definitely be used if one uses shared libraries. +*/ + +my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res); +unsigned int STDCALL mysql_num_fields(MYSQL_RES *res); +my_bool STDCALL mysql_eof(MYSQL_RES *res); +MYSQL_FIELD *STDCALL mysql_fetch_field_direct(MYSQL_RES *res, + unsigned int fieldnr); +MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res); +MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res); +MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res); + +unsigned int STDCALL mysql_field_count(MYSQL *mysql); +my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); +my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); +unsigned int STDCALL mysql_errno(MYSQL *mysql); +const char * STDCALL mysql_error(MYSQL *mysql); +const char *STDCALL mysql_sqlstate(MYSQL *mysql); +unsigned int STDCALL mysql_warning_count(MYSQL *mysql); +const char * STDCALL mysql_info(MYSQL *mysql); +unsigned long STDCALL mysql_thread_id(MYSQL *mysql); +const char * STDCALL mysql_character_set_name(MYSQL *mysql); +int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); + +MYSQL * STDCALL mysql_init(MYSQL *mysql); +my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, + const char *cert, const char *ca, + const char *capath, const char *cipher); +const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); +my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, + const char *passwd, const char *db); +MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, + const char *user, + const char *passwd, + const char *db, + unsigned int port, + const char *unix_socket, + unsigned long clientflag); +int STDCALL mysql_select_db(MYSQL *mysql, const char *db); +int STDCALL mysql_query(MYSQL *mysql, const char *q); +int STDCALL mysql_send_query(MYSQL *mysql, const char *q, + unsigned long length); +int STDCALL mysql_real_query(MYSQL *mysql, const char *q, + unsigned long length); +MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); + +/* perform query on master */ +my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q, + unsigned long length); +/* perform query on slave */ +my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, + unsigned long length); +void STDCALL mysql_get_character_set_info(MYSQL *mysql, + MY_CHARSET_INFO *charset); + +/* local infile support */ + +#define LOCAL_INFILE_ERROR_LEN 512 + +void +mysql_set_local_infile_handler(MYSQL *mysql, + int (*local_infile_init)(void **, const char *, + void *), + int (*local_infile_read)(void *, char *, + unsigned int), + void (*local_infile_end)(void *), + int (*local_infile_error)(void *, char*, + unsigned int), + void *); + +void +mysql_set_local_infile_default(MYSQL *mysql); + + +/* + enable/disable parsing of all queries to decide if they go on master or + slave +*/ +void STDCALL mysql_enable_rpl_parse(MYSQL* mysql); +void STDCALL mysql_disable_rpl_parse(MYSQL* mysql); +/* get the value of the parse flag */ +int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql); + +/* enable/disable reads from master */ +void STDCALL mysql_enable_reads_from_master(MYSQL* mysql); +void STDCALL mysql_disable_reads_from_master(MYSQL* mysql); +/* get the value of the master read flag */ +my_bool STDCALL mysql_reads_from_master_enabled(MYSQL* mysql); + +enum mysql_rpl_type STDCALL mysql_rpl_query_type(const char* q, int len); + +/* discover the master and its slaves */ +my_bool STDCALL mysql_rpl_probe(MYSQL* mysql); + +/* set the master, close/free the old one, if it is not a pivot */ +int STDCALL mysql_set_master(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd); +int STDCALL mysql_add_slave(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd); + +int STDCALL mysql_shutdown(MYSQL *mysql, + enum mysql_enum_shutdown_level + shutdown_level); +int STDCALL mysql_dump_debug_info(MYSQL *mysql); +int STDCALL mysql_refresh(MYSQL *mysql, + unsigned int refresh_options); +int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid); +int STDCALL mysql_set_server_option(MYSQL *mysql, + enum enum_mysql_set_option + option); +int STDCALL mysql_ping(MYSQL *mysql); +const char * STDCALL mysql_stat(MYSQL *mysql); +const char * STDCALL mysql_get_server_info(MYSQL *mysql); +const char * STDCALL mysql_get_client_info(void); +unsigned long STDCALL mysql_get_client_version(void); +const char * STDCALL mysql_get_host_info(MYSQL *mysql); +unsigned long STDCALL mysql_get_server_version(MYSQL *mysql); +unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild); +MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild); +MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); +int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, + const char *arg); +void STDCALL mysql_free_result(MYSQL_RES *result); +void STDCALL mysql_data_seek(MYSQL_RES *result, + my_ulonglong offset); +MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, + MYSQL_ROW_OFFSET offset); +MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, + MYSQL_FIELD_OFFSET offset); +MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); +unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); +MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); +MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, + const char *wild); +unsigned long STDCALL mysql_escape_string(char *to,const char *from, + unsigned long from_length); +unsigned long STDCALL mysql_hex_string(char *to,const char *from, + unsigned long from_length); +unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, + char *to,const char *from, + unsigned long length); +void STDCALL mysql_debug(const char *debug); +char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, + char *to, + unsigned long to_length, + const char *from, + unsigned long from_length, + void *param, + char * + (*extend_buffer) + (void *, char *to, + unsigned long *length)); +void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); +unsigned int STDCALL mysql_thread_safe(void); +my_bool STDCALL mysql_embedded(void); +MYSQL_MANAGER* STDCALL mysql_manager_init(MYSQL_MANAGER* con); +MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, + const char* host, + const char* user, + const char* passwd, + unsigned int port); +void STDCALL mysql_manager_close(MYSQL_MANAGER* con); +int STDCALL mysql_manager_command(MYSQL_MANAGER* con, + const char* cmd, int cmd_len); +int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, + char* res_buf, + int res_buf_size); +my_bool STDCALL mysql_read_query_result(MYSQL *mysql); + + +/* + The following definitions are added for the enhanced + client-server protocol +*/ + +/* statement state */ +enum enum_mysql_stmt_state +{ + MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE, + MYSQL_STMT_FETCH_DONE +}; + + +/* + This structure is used to define bind information, and + internally by the client library. + Public members with their descriptions are listed below + (conventionally `On input' refers to the binds given to + mysql_stmt_bind_param, `On output' refers to the binds given + to mysql_stmt_bind_result): + + buffer_type - One of the MYSQL_* types, used to describe + the host language type of buffer. + On output: if column type is different from + buffer_type, column value is automatically converted + to buffer_type before it is stored in the buffer. + buffer - On input: points to the buffer with input data. + On output: points to the buffer capable to store + output data. + The type of memory pointed by buffer must correspond + to buffer_type. See the correspondence table in + the comment to mysql_stmt_bind_param. + + The two above members are mandatory for any kind of bind. + + buffer_length - the length of the buffer. You don't have to set + it for any fixed length buffer: float, double, + int, etc. It must be set however for variable-length + types, such as BLOBs or STRINGs. + + length - On input: in case when lengths of input values + are different for each execute, you can set this to + point at a variable containining value length. This + way the value length can be different in each execute. + If length is not NULL, buffer_length is not used. + Note, length can even point at buffer_length if + you keep bind structures around while fetching: + this way you can change buffer_length before + each execution, everything will work ok. + On output: if length is set, mysql_stmt_fetch will + write column length into it. + + is_null - On input: points to a boolean variable that should + be set to TRUE for NULL values. + This member is useful only if your data may be + NULL in some but not all cases. + If your data is never NULL, is_null should be set to 0. + If your data is always NULL, set buffer_type + to MYSQL_TYPE_NULL, and is_null will not be used. + + is_unsigned - On input: used to signify that values provided for one + of numeric types are unsigned. + On output describes signedness of the output buffer. + If, taking into account is_unsigned flag, column data + is out of range of the output buffer, data for this column + is regarded truncated. Note that this has no correspondence + to the sign of result set column, if you need to find it out + use mysql_stmt_result_metadata. + error - where to write a truncation error if it is present. + possible error value is: + 0 no truncation + 1 value is out of range or buffer is too small + + Please note that MYSQL_BIND also has internals members. +*/ + +typedef struct st_mysql_bind +{ + unsigned long *length; /* output length pointer */ + my_bool *is_null; /* Pointer to null indicator */ + void *buffer; /* buffer to get/put data */ + /* set this if you want to track data truncations happened during fetch */ + my_bool *error; + enum enum_field_types buffer_type; /* buffer type */ + /* output buffer length, must be set when fetching str/binary */ + unsigned long buffer_length; + unsigned char *row_ptr; /* for the current data position */ + unsigned long offset; /* offset position for char/binary fetch */ + unsigned long length_value; /* Used if length is 0 */ + unsigned int param_number; /* For null count and error messages */ + unsigned int pack_length; /* Internal length for packed data */ + my_bool error_value; /* used if error is 0 */ + my_bool is_unsigned; /* set if integer type is unsigned */ + my_bool long_data_used; /* If used with mysql_send_long_data */ + my_bool is_null_value; /* Used if is_null is 0 */ + void (*store_param_func)(NET *net, struct st_mysql_bind *param); + void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); +} MYSQL_BIND; + + +/* statement handler */ +typedef struct st_mysql_stmt +{ + MEM_ROOT mem_root; /* root allocations */ + LIST list; /* list to keep track of all stmts */ + MYSQL *mysql; /* connection handle */ + MYSQL_BIND *params; /* input parameters */ + MYSQL_BIND *bind; /* output parameters */ + MYSQL_FIELD *fields; /* result set metadata */ + MYSQL_DATA result; /* cached result set */ + MYSQL_ROWS *data_cursor; /* current row in cached result */ + /* copy of mysql->affected_rows after statement execution */ + my_ulonglong affected_rows; + my_ulonglong insert_id; /* copy of mysql->insert_id */ + /* + mysql_stmt_fetch() calls this function to fetch one row (it's different + for buffered, unbuffered and cursor fetch). + */ + int (*read_row_func)(struct st_mysql_stmt *stmt, + unsigned char **row); + unsigned long stmt_id; /* Id for prepared statement */ + unsigned long flags; /* i.e. type of cursor to open */ + unsigned long prefetch_rows; /* number of rows per one COM_FETCH */ + /* + Copied from mysql->server_status after execute/fetch to know + server-side cursor status for this statement. + */ + unsigned int server_status; + unsigned int last_errno; /* error code */ + unsigned int param_count; /* input parameter count */ + unsigned int field_count; /* number of columns in result set */ + enum enum_mysql_stmt_state state; /* statement state */ + char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ + char sqlstate[SQLSTATE_LENGTH+1]; + /* Types of input parameters should be sent to server */ + my_bool send_types_to_server; + my_bool bind_param_done; /* input buffers were supplied */ + unsigned char bind_result_done; /* output buffers were supplied */ + /* mysql_stmt_close() had to cancel this result */ + my_bool unbuffered_fetch_cancelled; + /* + Is set to true if we need to calculate field->max_length for + metadata fields when doing mysql_stmt_store_result. + */ + my_bool update_max_length; +} MYSQL_STMT; + +enum enum_stmt_attr_type +{ + /* + When doing mysql_stmt_store_result calculate max_length attribute + of statement metadata. This is to be consistent with the old API, + where this was done automatically. + In the new API we do that only by request because it slows down + mysql_stmt_store_result sufficiently. + */ + STMT_ATTR_UPDATE_MAX_LENGTH, + /* + unsigned long with combination of cursor flags (read only, for update, + etc) + */ + STMT_ATTR_CURSOR_TYPE, + /* + Amount of rows to retrieve from server per one fetch if using cursors. + Accepts unsigned long attribute in the range 1 - ulong_max + */ + STMT_ATTR_PREFETCH_ROWS +}; + + +typedef struct st_mysql_methods +{ + my_bool (*read_query_result)(MYSQL *mysql); + my_bool (*advanced_command)(MYSQL *mysql, + enum enum_server_command command, + const char *header, + unsigned long header_length, + const char *arg, + unsigned long arg_length, + my_bool skip_check, + MYSQL_STMT *stmt); + MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + unsigned int fields); + MYSQL_RES * (*use_result)(MYSQL *mysql); + void (*fetch_lengths)(unsigned long *to, + MYSQL_ROW column, unsigned int field_count); + void (*flush_use_result)(MYSQL *mysql); +#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) + MYSQL_FIELD * (*list_fields)(MYSQL *mysql); + my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt); + int (*stmt_execute)(MYSQL_STMT *stmt); + int (*read_binary_rows)(MYSQL_STMT *stmt); + int (*unbuffered_fetch)(MYSQL *mysql, char **row); + void (*free_embedded_thd)(MYSQL *mysql); + const char *(*read_statistics)(MYSQL *mysql); + my_bool (*next_result)(MYSQL *mysql); + int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd); + int (*read_rows_from_cursor)(MYSQL_STMT *stmt); +#endif +} MYSQL_METHODS; + + +MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql); +int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, + unsigned long length); +int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, + unsigned int column, + unsigned long offset); +int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); +unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + const void *attr); +my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + void *attr); +my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); +my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, + unsigned int param_number, + const char *data, + unsigned long length); +MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt); +MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, + MYSQL_ROW_OFFSET offset); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt); +void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset); +my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt); + +my_bool STDCALL mysql_commit(MYSQL * mysql); +my_bool STDCALL mysql_rollback(MYSQL * mysql); +my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); +my_bool STDCALL mysql_more_results(MYSQL *mysql); +int STDCALL mysql_next_result(MYSQL *mysql); +void STDCALL mysql_close(MYSQL *sock); + + +/* status return codes */ +#define MYSQL_NO_DATA 100 +#define MYSQL_DATA_TRUNCATED 101 + +#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) + +#ifdef USE_OLD_FUNCTIONS +MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, + const char *user, const char *passwd); +int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); +int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); +#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) +#endif +#define HAVE_MYSQL_REAL_CONNECT + +/* + The following functions are mainly exported because of mysqlbinlog; + They are not for general usage +*/ + +#define simple_command(mysql, command, arg, length, skip_check) \ + (*(mysql)->methods->advanced_command)(mysql, command, NullS, \ + 0, arg, length, skip_check, NULL) +#define stmt_command(mysql, command, arg, length, stmt) \ + (*(mysql)->methods->advanced_command)(mysql, command, NullS, \ + 0, arg, length, 1, stmt) + +#ifdef __NETWARE__ +#pragma pack(pop) /* restore alignment */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _mysql_h */ diff --git a/code/meosdb/mysql50/mysql_com.h b/code/meosdb/mysql50/mysql_com.h new file mode 100644 index 0000000..a079a9a --- /dev/null +++ b/code/meosdb/mysql50/mysql_com.h @@ -0,0 +1,463 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* +** Common definition between mysql server & client +*/ + +#ifndef _mysql_com_h +#define _mysql_com_h + +#define NAME_LEN 64 /* Field/table name length */ +#define HOSTNAME_LENGTH 60 +#define USERNAME_LENGTH 16 +#define SERVER_VERSION_LENGTH 60 +#define SQLSTATE_LENGTH 5 + +/* + USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain + username and hostname parts of the user identifier with trailing zero in + MySQL standard format: + user_name_part@host_name_part\0 +*/ +#define USER_HOST_BUFF_SIZE HOSTNAME_LENGTH + USERNAME_LENGTH + 2 + +#define LOCAL_HOST "localhost" +#define LOCAL_HOST_NAMEDPIPE "." + + +#if defined(__WIN__) && !defined( _CUSTOMCONFIG_) +#define MYSQL_NAMEDPIPE "MySQL" +#define MYSQL_SERVICENAME "MySQL" +#endif /* __WIN__ */ + +/* + You should add new commands to the end of this list, otherwise old + servers won't be able to handle them as 'unsupported'. +*/ + +enum enum_server_command +{ + COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, + COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, + COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, + COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, + COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, + COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, + COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, + /* don't forget to update const char *command_name[] in sql_parse.cc */ + + /* Must be last */ + COM_END +}; + + +/* + Length of random string sent by server on handshake; this is also length of + obfuscated password, recieved from client +*/ +#define SCRAMBLE_LENGTH 20 +#define SCRAMBLE_LENGTH_323 8 +/* length of password stored in the db: new passwords are preceeded with '*' */ +#define SCRAMBLED_PASSWORD_CHAR_LENGTH (SCRAMBLE_LENGTH*2+1) +#define SCRAMBLED_PASSWORD_CHAR_LENGTH_323 (SCRAMBLE_LENGTH_323*2) + + +#define NOT_NULL_FLAG 1 /* Field can't be NULL */ +#define PRI_KEY_FLAG 2 /* Field is part of a primary key */ +#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */ +#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */ +#define BLOB_FLAG 16 /* Field is a blob */ +#define UNSIGNED_FLAG 32 /* Field is unsigned */ +#define ZEROFILL_FLAG 64 /* Field is zerofill */ +#define BINARY_FLAG 128 /* Field is binary */ + +/* The following are only sent to new clients */ +#define ENUM_FLAG 256 /* field is an enum */ +#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ +#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */ +#define SET_FLAG 2048 /* field is a set */ +#define NO_DEFAULT_VALUE_FLAG 4096 /* Field doesn't have default value */ +#define NUM_FLAG 32768 /* Field is num (for clients) */ +#define PART_KEY_FLAG 16384 /* Intern; Part of some key */ +#define GROUP_FLAG 32768 /* Intern: Group field */ +#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ +#define BINCMP_FLAG 131072 /* Intern: Used by sql_yacc */ + +#define REFRESH_GRANT 1 /* Refresh grant tables */ +#define REFRESH_LOG 2 /* Start on new log file */ +#define REFRESH_TABLES 4 /* close all tables */ +#define REFRESH_HOSTS 8 /* Flush host cache */ +#define REFRESH_STATUS 16 /* Flush status variables */ +#define REFRESH_THREADS 32 /* Flush thread cache */ +#define REFRESH_SLAVE 64 /* Reset master info and restart slave + thread */ +#define REFRESH_MASTER 128 /* Remove all bin logs in the index + and truncate the index */ + +/* The following can't be set with mysql_refresh() */ +#define REFRESH_READ_LOCK 16384 /* Lock tables for read */ +#define REFRESH_FAST 32768 /* Intern flag */ + +/* RESET (remove all queries) from query cache */ +#define REFRESH_QUERY_CACHE 65536 +#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */ +#define REFRESH_DES_KEY_FILE 0x40000L +#define REFRESH_USER_RESOURCES 0x80000L + +#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ +#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ +#define CLIENT_LONG_FLAG 4 /* Get all column flags */ +#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ +#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ +#define CLIENT_COMPRESS 32 /* Can use compression protocol */ +#define CLIENT_ODBC 64 /* Odbc client */ +#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ +#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ +#define CLIENT_PROTOCOL_41 512 /* New 4.1 protocol */ +#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ +#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ +#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ +#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ +#define CLIENT_RESERVED 16384 /* Old flag for 4.1 protocol */ +#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */ +#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */ +#define CLIENT_MULTI_RESULTS (1UL << 17) /* Enable/disable multi-results */ + +#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) +#define CLIENT_REMEMBER_OPTIONS (1UL << 31) + +#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ +#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ +#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */ +#define SERVER_QUERY_NO_GOOD_INDEX_USED 16 +#define SERVER_QUERY_NO_INDEX_USED 32 +/* + The server was able to fulfill the clients request and opened a + read-only non-scrollable cursor for a query. This flag comes + in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. +*/ +#define SERVER_STATUS_CURSOR_EXISTS 64 +/* + This flag is sent when a read-only cursor is exhausted, in reply to + COM_STMT_FETCH command. +*/ +#define SERVER_STATUS_LAST_ROW_SENT 128 +#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */ +#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 + +#define MYSQL_ERRMSG_SIZE 512 +#define NET_READ_TIMEOUT 30 /* Timeout on read */ +#define NET_WRITE_TIMEOUT 60 /* Timeout on write */ +#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ + +#define ONLY_KILL_QUERY 1 + +struct st_vio; /* Only C */ +typedef struct st_vio Vio; + +#define MAX_TINYINT_WIDTH 3 /* Max width for a TINY w.o. sign */ +#define MAX_SMALLINT_WIDTH 5 /* Max width for a SHORT w.o. sign */ +#define MAX_MEDIUMINT_WIDTH 8 /* Max width for a INT24 w.o. sign */ +#define MAX_INT_WIDTH 10 /* Max width for a LONG w.o. sign */ +#define MAX_BIGINT_WIDTH 20 /* Max width for a LONGLONG */ +#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */ +#define MAX_BLOB_WIDTH 8192 /* Default width for blob */ + +typedef struct st_net { +#if !defined(CHECK_EMBEDDED_DIFFERENCES) || !defined(EMBEDDED_LIBRARY) + Vio* vio; + unsigned char *buff,*buff_end,*write_pos,*read_pos; + my_socket fd; /* For Perl DBI/dbd */ + unsigned long max_packet,max_packet_size; + unsigned int pkt_nr,compress_pkt_nr; + unsigned int write_timeout, read_timeout, retry_count; + int fcntl; + my_bool compress; + /* + The following variable is set if we are doing several queries in one + command ( as in LOAD TABLE ... FROM MASTER ), + and do not want to confuse the client with OK at the wrong time + */ + unsigned long remain_in_buf,length, buf_length, where_b; + unsigned int *return_status; + unsigned char reading_or_writing; + char save_char; + my_bool no_send_ok; /* For SPs and other things that do multiple stmts */ + my_bool no_send_eof; /* For SPs' first version read-only cursors */ + /* + Set if OK packet is already sent, and we do not need to send error + messages + */ + my_bool no_send_error; + /* + Pointer to query object in query cache, do not equal NULL (0) for + queries in cache that have not stored its results yet + */ +#endif + char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1]; + unsigned int last_errno; + unsigned char error; + + /* + 'query_cache_query' should be accessed only via query cache + functions and methods to maintain proper locking. + */ + gptr query_cache_query; + + my_bool report_error; /* We should report error (we have unreported error) */ + my_bool return_errno; +} NET; + +#define packet_error (~(unsigned long) 0) + +enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, + MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, + MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, + MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, + MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, + MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, + MYSQL_TYPE_BIT, + MYSQL_TYPE_NEWDECIMAL=246, + MYSQL_TYPE_ENUM=247, + MYSQL_TYPE_SET=248, + MYSQL_TYPE_TINY_BLOB=249, + MYSQL_TYPE_MEDIUM_BLOB=250, + MYSQL_TYPE_LONG_BLOB=251, + MYSQL_TYPE_BLOB=252, + MYSQL_TYPE_VAR_STRING=253, + MYSQL_TYPE_STRING=254, + MYSQL_TYPE_GEOMETRY=255 + +}; + +/* For backward compatibility */ +#define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS +#define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL +#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL +#define FIELD_TYPE_TINY MYSQL_TYPE_TINY +#define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT +#define FIELD_TYPE_LONG MYSQL_TYPE_LONG +#define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT +#define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE +#define FIELD_TYPE_NULL MYSQL_TYPE_NULL +#define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP +#define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG +#define FIELD_TYPE_INT24 MYSQL_TYPE_INT24 +#define FIELD_TYPE_DATE MYSQL_TYPE_DATE +#define FIELD_TYPE_TIME MYSQL_TYPE_TIME +#define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME +#define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR +#define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE +#define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM +#define FIELD_TYPE_SET MYSQL_TYPE_SET +#define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB +#define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB +#define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB +#define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB +#define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING +#define FIELD_TYPE_STRING MYSQL_TYPE_STRING +#define FIELD_TYPE_CHAR MYSQL_TYPE_TINY +#define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM +#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY +#define FIELD_TYPE_BIT MYSQL_TYPE_BIT + + +/* Shutdown/kill enums and constants */ + +/* Bits for THD::killable. */ +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) + +enum mysql_enum_shutdown_level { + /* + We want levels to be in growing order of hardness (because we use number + comparisons). Note that DEFAULT does not respect the growing property, but + it's ok. + */ + SHUTDOWN_DEFAULT = 0, + /* wait for existing connections to finish */ + SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, + /* wait for existing trans to finish */ + SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, + /* wait for existing updates to finish (=> no partial MyISAM update) */ + SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, + /* flush InnoDB buffers and other storage engines' buffers*/ + SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + /* don't flush InnoDB buffers, flush other storage engines' buffers*/ + SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + /* Now the 2 levels of the KILL command */ +#if MYSQL_VERSION_ID >= 50000 + KILL_QUERY= 254, +#endif + KILL_CONNECTION= 255 +}; + + +enum enum_cursor_type +{ + CURSOR_TYPE_NO_CURSOR= 0, + CURSOR_TYPE_READ_ONLY= 1, + CURSOR_TYPE_FOR_UPDATE= 2, + CURSOR_TYPE_SCROLLABLE= 4 +}; + + +/* options for mysql_set_option */ +enum enum_mysql_set_option +{ + MYSQL_OPTION_MULTI_STATEMENTS_ON, + MYSQL_OPTION_MULTI_STATEMENTS_OFF +}; + +#define net_new_transaction(net) ((net)->pkt_nr=0) + +#ifdef __cplusplus +extern "C" { +#endif + +my_bool my_net_init(NET *net, Vio* vio); +void my_net_local_init(NET *net); +void net_end(NET *net); +void net_clear(NET *net); +my_bool net_realloc(NET *net, unsigned long length); +my_bool net_flush(NET *net); +my_bool my_net_write(NET *net,const char *packet,unsigned long len); +my_bool net_write_command(NET *net,unsigned char command, + const char *header, unsigned long head_len, + const char *packet, unsigned long len); +int net_real_write(NET *net,const char *packet,unsigned long len); +unsigned long my_net_read(NET *net); + +#ifdef _global_h +void my_net_set_write_timeout(NET *net, uint timeout); +void my_net_set_read_timeout(NET *net, uint timeout); +#endif + +/* + The following function is not meant for normal usage + Currently it's used internally by manager.c +*/ +struct sockaddr; +int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen, + unsigned int timeout); + +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + +#ifdef __cplusplus +} +#endif + + /* The following is for user defined functions */ + +enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, + DECIMAL_RESULT}; + +typedef struct st_udf_args +{ + unsigned int arg_count; /* Number of arguments */ + enum Item_result *arg_type; /* Pointer to item_results */ + char **args; /* Pointer to argument */ + unsigned long *lengths; /* Length of string arguments */ + char *maybe_null; /* Set to 1 for all maybe_null args */ + char **attributes; /* Pointer to attribute name */ + unsigned long *attribute_lengths; /* Length of attribute arguments */ +} UDF_ARGS; + + /* This holds information about the result */ + +typedef struct st_udf_init +{ + my_bool maybe_null; /* 1 if function can return NULL */ + unsigned int decimals; /* for real functions */ + unsigned long max_length; /* For string functions */ + char *ptr; /* free pointer for function data */ + my_bool const_item; /* 0 if result is independent of arguments */ +} UDF_INIT; + + /* Constants when using compression */ +#define NET_HEADER_SIZE 4 /* standard header size */ +#define COMP_HEADER_SIZE 3 /* compression header extra size */ + + /* Prototypes to password functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + These functions are used for authentication by client and server and + implemented in sql/password.c +*/ + +void randominit(struct rand_struct *, unsigned long seed1, + unsigned long seed2); +double my_rnd(struct rand_struct *); +void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st); + +void hash_password(unsigned long *to, const char *password, unsigned int password_len); +void make_scrambled_password_323(char *to, const char *password); +void scramble_323(char *to, const char *message, const char *password); +my_bool check_scramble_323(const char *, const char *message, + unsigned long *salt); +void get_salt_from_password_323(unsigned long *res, const char *password); +void make_password_from_salt_323(char *to, const unsigned long *salt); + +void make_scrambled_password(char *to, const char *password); +void scramble(char *to, const char *message, const char *password); +my_bool check_scramble(const char *reply, const char *message, + const unsigned char *hash_stage2); +void get_salt_from_password(unsigned char *res, const char *password); +void make_password_from_salt(char *to, const unsigned char *hash_stage2); +char *octet2hex(char *to, const char *str, unsigned int len); + +/* end of password.c */ + +char *get_tty_password(char *opt_message); +const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); + +/* Some other useful functions */ + +my_bool my_init(void); +extern int modify_defaults_file(const char *file_location, const char *option, + const char *option_value, + const char *section_name, int remove_option); +int load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv); +my_bool my_thread_init(void); +void my_thread_end(void); + +#ifdef _global_h +ulong STDCALL net_field_length(uchar **packet); +my_ulonglong net_field_length_ll(uchar **packet); +char *net_store_length(char *pkg, ulonglong length); +#endif + +#ifdef __cplusplus +} +#endif + +#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */ +#define MYSQL_STMT_HEADER 4 +#define MYSQL_LONG_DATA_HEADER 6 + +#endif diff --git a/code/meosdb/mysql50/mysql_embed.h b/code/meosdb/mysql50/mysql_embed.h new file mode 100644 index 0000000..83ab65b --- /dev/null +++ b/code/meosdb/mysql50/mysql_embed.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Defines that are unique to the embedded version of MySQL */ + +#ifdef EMBEDDED_LIBRARY + +/* Things we don't need in the embedded version of MySQL */ +/* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ + +#undef HAVE_PSTACK /* No stacktrace */ +#undef HAVE_DLOPEN /* No udf functions */ +#undef HAVE_OPENSSL +#undef HAVE_SMEM /* No shared memory */ +#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ + +#define DONT_USE_RAID + +#endif /* EMBEDDED_LIBRARY */ diff --git a/code/meosdb/mysql50/mysql_time.h b/code/meosdb/mysql50/mysql_time.h new file mode 100644 index 0000000..33c3636 --- /dev/null +++ b/code/meosdb/mysql50/mysql_time.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2004 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _mysql_time_h_ +#define _mysql_time_h_ + +/* + Time declarations shared between the server and client API: + you should not add anything to this header unless it's used + (and hence should be visible) in mysql.h. + If you're looking for a place to add new time-related declaration, + it's most likely my_time.h. See also "C API Handling of Date + and Time Values" chapter in documentation. +*/ + +enum enum_mysql_timestamp_type +{ + MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, + MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 +}; + + +/* + Structure which is used to represent datetime values inside MySQL. + + We assume that values in this structure are normalized, i.e. year <= 9999, + month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions + in server such as my_system_gmt_sec() or make_time() family of functions + rely on this (actually now usage of make_*() family relies on a bit weaker + restriction). Also functions that produce MYSQL_TIME as result ensure this. + There is one exception to this rule though if this structure holds time + value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold + bigger values. +*/ +typedef struct st_mysql_time +{ + unsigned int year, month, day, hour, minute, second; + unsigned long second_part; + my_bool neg; + enum enum_mysql_timestamp_type time_type; +} MYSQL_TIME; + +#endif /* _mysql_time_h_ */ diff --git a/code/meosdb/mysql50/mysql_version.h b/code/meosdb/mysql50/mysql_version.h new file mode 100644 index 0000000..8bd873c --- /dev/null +++ b/code/meosdb/mysql50/mysql_version.h @@ -0,0 +1,29 @@ +/* Copyright Abandoned 1996, 1999, 2001 MySQL AB + This file is public domain and comes with NO WARRANTY of any kind */ + +/* Version numbers for protocol & mysqld */ + +#ifndef _mysql_version_h +#define _mysql_version_h +#ifdef _CUSTOMCONFIG_ +#include +#else +#define PROTOCOL_VERSION 10 +#define MYSQL_SERVER_VERSION "5.0.45" +#define MYSQL_BASE_VERSION "mysqld-5.0" +#define MYSQL_SERVER_SUFFIX_DEF "-community-nt" +#define FRM_VER 6 +#define MYSQL_VERSION_ID 50045 +#define MYSQL_PORT 3306 +#define MYSQL_UNIX_ADDR "/tmp/mysql.sock" +#define MYSQL_CONFIG_NAME "my" +#define MYSQL_COMPILATION_COMMENT "MySQL Community Edition (GPL)" + +/* mysqld compile time options */ +#endif /* _CUSTOMCONFIG_ */ + +#ifndef LICENSE +#define LICENSE GPL +#endif /* LICENSE */ + +#endif /* _mysql_version_h */ diff --git a/code/meosdb/mysql50/mysqld_ername.h b/code/meosdb/mysql50/mysqld_ername.h new file mode 100644 index 0000000..ab986ec --- /dev/null +++ b/code/meosdb/mysql50/mysqld_ername.h @@ -0,0 +1,474 @@ +/* Autogenerated file, please don't edit */ + +{ "ER_HASHCHK", 1000 }, +{ "ER_NISAMCHK", 1001 }, +{ "ER_NO", 1002 }, +{ "ER_YES", 1003 }, +{ "ER_CANT_CREATE_FILE", 1004 }, +{ "ER_CANT_CREATE_TABLE", 1005 }, +{ "ER_CANT_CREATE_DB", 1006 }, +{ "ER_DB_CREATE_EXISTS", 1007 }, +{ "ER_DB_DROP_EXISTS", 1008 }, +{ "ER_DB_DROP_DELETE", 1009 }, +{ "ER_DB_DROP_RMDIR", 1010 }, +{ "ER_CANT_DELETE_FILE", 1011 }, +{ "ER_CANT_FIND_SYSTEM_REC", 1012 }, +{ "ER_CANT_GET_STAT", 1013 }, +{ "ER_CANT_GET_WD", 1014 }, +{ "ER_CANT_LOCK", 1015 }, +{ "ER_CANT_OPEN_FILE", 1016 }, +{ "ER_FILE_NOT_FOUND", 1017 }, +{ "ER_CANT_READ_DIR", 1018 }, +{ "ER_CANT_SET_WD", 1019 }, +{ "ER_CHECKREAD", 1020 }, +{ "ER_DISK_FULL", 1021 }, +{ "ER_DUP_KEY", 1022 }, +{ "ER_ERROR_ON_CLOSE", 1023 }, +{ "ER_ERROR_ON_READ", 1024 }, +{ "ER_ERROR_ON_RENAME", 1025 }, +{ "ER_ERROR_ON_WRITE", 1026 }, +{ "ER_FILE_USED", 1027 }, +{ "ER_FILSORT_ABORT", 1028 }, +{ "ER_FORM_NOT_FOUND", 1029 }, +{ "ER_GET_ERRNO", 1030 }, +{ "ER_ILLEGAL_HA", 1031 }, +{ "ER_KEY_NOT_FOUND", 1032 }, +{ "ER_NOT_FORM_FILE", 1033 }, +{ "ER_NOT_KEYFILE", 1034 }, +{ "ER_OLD_KEYFILE", 1035 }, +{ "ER_OPEN_AS_READONLY", 1036 }, +{ "ER_OUTOFMEMORY", 1037 }, +{ "ER_OUT_OF_SORTMEMORY", 1038 }, +{ "ER_UNEXPECTED_EOF", 1039 }, +{ "ER_CON_COUNT_ERROR", 1040 }, +{ "ER_OUT_OF_RESOURCES", 1041 }, +{ "ER_BAD_HOST_ERROR", 1042 }, +{ "ER_HANDSHAKE_ERROR", 1043 }, +{ "ER_DBACCESS_DENIED_ERROR", 1044 }, +{ "ER_ACCESS_DENIED_ERROR", 1045 }, +{ "ER_NO_DB_ERROR", 1046 }, +{ "ER_UNKNOWN_COM_ERROR", 1047 }, +{ "ER_BAD_NULL_ERROR", 1048 }, +{ "ER_BAD_DB_ERROR", 1049 }, +{ "ER_TABLE_EXISTS_ERROR", 1050 }, +{ "ER_BAD_TABLE_ERROR", 1051 }, +{ "ER_NON_UNIQ_ERROR", 1052 }, +{ "ER_SERVER_SHUTDOWN", 1053 }, +{ "ER_BAD_FIELD_ERROR", 1054 }, +{ "ER_WRONG_FIELD_WITH_GROUP", 1055 }, +{ "ER_WRONG_GROUP_FIELD", 1056 }, +{ "ER_WRONG_SUM_SELECT", 1057 }, +{ "ER_WRONG_VALUE_COUNT", 1058 }, +{ "ER_TOO_LONG_IDENT", 1059 }, +{ "ER_DUP_FIELDNAME", 1060 }, +{ "ER_DUP_KEYNAME", 1061 }, +{ "ER_DUP_ENTRY", 1062 }, +{ "ER_WRONG_FIELD_SPEC", 1063 }, +{ "ER_PARSE_ERROR", 1064 }, +{ "ER_EMPTY_QUERY", 1065 }, +{ "ER_NONUNIQ_TABLE", 1066 }, +{ "ER_INVALID_DEFAULT", 1067 }, +{ "ER_MULTIPLE_PRI_KEY", 1068 }, +{ "ER_TOO_MANY_KEYS", 1069 }, +{ "ER_TOO_MANY_KEY_PARTS", 1070 }, +{ "ER_TOO_LONG_KEY", 1071 }, +{ "ER_KEY_COLUMN_DOES_NOT_EXITS", 1072 }, +{ "ER_BLOB_USED_AS_KEY", 1073 }, +{ "ER_TOO_BIG_FIELDLENGTH", 1074 }, +{ "ER_WRONG_AUTO_KEY", 1075 }, +{ "ER_READY", 1076 }, +{ "ER_NORMAL_SHUTDOWN", 1077 }, +{ "ER_GOT_SIGNAL", 1078 }, +{ "ER_SHUTDOWN_COMPLETE", 1079 }, +{ "ER_FORCING_CLOSE", 1080 }, +{ "ER_IPSOCK_ERROR", 1081 }, +{ "ER_NO_SUCH_INDEX", 1082 }, +{ "ER_WRONG_FIELD_TERMINATORS", 1083 }, +{ "ER_BLOBS_AND_NO_TERMINATED", 1084 }, +{ "ER_TEXTFILE_NOT_READABLE", 1085 }, +{ "ER_FILE_EXISTS_ERROR", 1086 }, +{ "ER_LOAD_INFO", 1087 }, +{ "ER_ALTER_INFO", 1088 }, +{ "ER_WRONG_SUB_KEY", 1089 }, +{ "ER_CANT_REMOVE_ALL_FIELDS", 1090 }, +{ "ER_CANT_DROP_FIELD_OR_KEY", 1091 }, +{ "ER_INSERT_INFO", 1092 }, +{ "ER_UPDATE_TABLE_USED", 1093 }, +{ "ER_NO_SUCH_THREAD", 1094 }, +{ "ER_KILL_DENIED_ERROR", 1095 }, +{ "ER_NO_TABLES_USED", 1096 }, +{ "ER_TOO_BIG_SET", 1097 }, +{ "ER_NO_UNIQUE_LOGFILE", 1098 }, +{ "ER_TABLE_NOT_LOCKED_FOR_WRITE", 1099 }, +{ "ER_TABLE_NOT_LOCKED", 1100 }, +{ "ER_BLOB_CANT_HAVE_DEFAULT", 1101 }, +{ "ER_WRONG_DB_NAME", 1102 }, +{ "ER_WRONG_TABLE_NAME", 1103 }, +{ "ER_TOO_BIG_SELECT", 1104 }, +{ "ER_UNKNOWN_ERROR", 1105 }, +{ "ER_UNKNOWN_PROCEDURE", 1106 }, +{ "ER_WRONG_PARAMCOUNT_TO_PROCEDURE", 1107 }, +{ "ER_WRONG_PARAMETERS_TO_PROCEDURE", 1108 }, +{ "ER_UNKNOWN_TABLE", 1109 }, +{ "ER_FIELD_SPECIFIED_TWICE", 1110 }, +{ "ER_INVALID_GROUP_FUNC_USE", 1111 }, +{ "ER_UNSUPPORTED_EXTENSION", 1112 }, +{ "ER_TABLE_MUST_HAVE_COLUMNS", 1113 }, +{ "ER_RECORD_FILE_FULL", 1114 }, +{ "ER_UNKNOWN_CHARACTER_SET", 1115 }, +{ "ER_TOO_MANY_TABLES", 1116 }, +{ "ER_TOO_MANY_FIELDS", 1117 }, +{ "ER_TOO_BIG_ROWSIZE", 1118 }, +{ "ER_STACK_OVERRUN", 1119 }, +{ "ER_WRONG_OUTER_JOIN", 1120 }, +{ "ER_NULL_COLUMN_IN_INDEX", 1121 }, +{ "ER_CANT_FIND_UDF", 1122 }, +{ "ER_CANT_INITIALIZE_UDF", 1123 }, +{ "ER_UDF_NO_PATHS", 1124 }, +{ "ER_UDF_EXISTS", 1125 }, +{ "ER_CANT_OPEN_LIBRARY", 1126 }, +{ "ER_CANT_FIND_DL_ENTRY", 1127 }, +{ "ER_FUNCTION_NOT_DEFINED", 1128 }, +{ "ER_HOST_IS_BLOCKED", 1129 }, +{ "ER_HOST_NOT_PRIVILEGED", 1130 }, +{ "ER_PASSWORD_ANONYMOUS_USER", 1131 }, +{ "ER_PASSWORD_NOT_ALLOWED", 1132 }, +{ "ER_PASSWORD_NO_MATCH", 1133 }, +{ "ER_UPDATE_INFO", 1134 }, +{ "ER_CANT_CREATE_THREAD", 1135 }, +{ "ER_WRONG_VALUE_COUNT_ON_ROW", 1136 }, +{ "ER_CANT_REOPEN_TABLE", 1137 }, +{ "ER_INVALID_USE_OF_NULL", 1138 }, +{ "ER_REGEXP_ERROR", 1139 }, +{ "ER_MIX_OF_GROUP_FUNC_AND_FIELDS", 1140 }, +{ "ER_NONEXISTING_GRANT", 1141 }, +{ "ER_TABLEACCESS_DENIED_ERROR", 1142 }, +{ "ER_COLUMNACCESS_DENIED_ERROR", 1143 }, +{ "ER_ILLEGAL_GRANT_FOR_TABLE", 1144 }, +{ "ER_GRANT_WRONG_HOST_OR_USER", 1145 }, +{ "ER_NO_SUCH_TABLE", 1146 }, +{ "ER_NONEXISTING_TABLE_GRANT", 1147 }, +{ "ER_NOT_ALLOWED_COMMAND", 1148 }, +{ "ER_SYNTAX_ERROR", 1149 }, +{ "ER_DELAYED_CANT_CHANGE_LOCK", 1150 }, +{ "ER_TOO_MANY_DELAYED_THREADS", 1151 }, +{ "ER_ABORTING_CONNECTION", 1152 }, +{ "ER_NET_PACKET_TOO_LARGE", 1153 }, +{ "ER_NET_READ_ERROR_FROM_PIPE", 1154 }, +{ "ER_NET_FCNTL_ERROR", 1155 }, +{ "ER_NET_PACKETS_OUT_OF_ORDER", 1156 }, +{ "ER_NET_UNCOMPRESS_ERROR", 1157 }, +{ "ER_NET_READ_ERROR", 1158 }, +{ "ER_NET_READ_INTERRUPTED", 1159 }, +{ "ER_NET_ERROR_ON_WRITE", 1160 }, +{ "ER_NET_WRITE_INTERRUPTED", 1161 }, +{ "ER_TOO_LONG_STRING", 1162 }, +{ "ER_TABLE_CANT_HANDLE_BLOB", 1163 }, +{ "ER_TABLE_CANT_HANDLE_AUTO_INCREMENT", 1164 }, +{ "ER_DELAYED_INSERT_TABLE_LOCKED", 1165 }, +{ "ER_WRONG_COLUMN_NAME", 1166 }, +{ "ER_WRONG_KEY_COLUMN", 1167 }, +{ "ER_WRONG_MRG_TABLE", 1168 }, +{ "ER_DUP_UNIQUE", 1169 }, +{ "ER_BLOB_KEY_WITHOUT_LENGTH", 1170 }, +{ "ER_PRIMARY_CANT_HAVE_NULL", 1171 }, +{ "ER_TOO_MANY_ROWS", 1172 }, +{ "ER_REQUIRES_PRIMARY_KEY", 1173 }, +{ "ER_NO_RAID_COMPILED", 1174 }, +{ "ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE", 1175 }, +{ "ER_KEY_DOES_NOT_EXITS", 1176 }, +{ "ER_CHECK_NO_SUCH_TABLE", 1177 }, +{ "ER_CHECK_NOT_IMPLEMENTED", 1178 }, +{ "ER_CANT_DO_THIS_DURING_AN_TRANSACTION", 1179 }, +{ "ER_ERROR_DURING_COMMIT", 1180 }, +{ "ER_ERROR_DURING_ROLLBACK", 1181 }, +{ "ER_ERROR_DURING_FLUSH_LOGS", 1182 }, +{ "ER_ERROR_DURING_CHECKPOINT", 1183 }, +{ "ER_NEW_ABORTING_CONNECTION", 1184 }, +{ "ER_DUMP_NOT_IMPLEMENTED", 1185 }, +{ "ER_FLUSH_MASTER_BINLOG_CLOSED", 1186 }, +{ "ER_INDEX_REBUILD", 1187 }, +{ "ER_MASTER", 1188 }, +{ "ER_MASTER_NET_READ", 1189 }, +{ "ER_MASTER_NET_WRITE", 1190 }, +{ "ER_FT_MATCHING_KEY_NOT_FOUND", 1191 }, +{ "ER_LOCK_OR_ACTIVE_TRANSACTION", 1192 }, +{ "ER_UNKNOWN_SYSTEM_VARIABLE", 1193 }, +{ "ER_CRASHED_ON_USAGE", 1194 }, +{ "ER_CRASHED_ON_REPAIR", 1195 }, +{ "ER_WARNING_NOT_COMPLETE_ROLLBACK", 1196 }, +{ "ER_TRANS_CACHE_FULL", 1197 }, +{ "ER_SLAVE_MUST_STOP", 1198 }, +{ "ER_SLAVE_NOT_RUNNING", 1199 }, +{ "ER_BAD_SLAVE", 1200 }, +{ "ER_MASTER_INFO", 1201 }, +{ "ER_SLAVE_THREAD", 1202 }, +{ "ER_TOO_MANY_USER_CONNECTIONS", 1203 }, +{ "ER_SET_CONSTANTS_ONLY", 1204 }, +{ "ER_LOCK_WAIT_TIMEOUT", 1205 }, +{ "ER_LOCK_TABLE_FULL", 1206 }, +{ "ER_READ_ONLY_TRANSACTION", 1207 }, +{ "ER_DROP_DB_WITH_READ_LOCK", 1208 }, +{ "ER_CREATE_DB_WITH_READ_LOCK", 1209 }, +{ "ER_WRONG_ARGUMENTS", 1210 }, +{ "ER_NO_PERMISSION_TO_CREATE_USER", 1211 }, +{ "ER_UNION_TABLES_IN_DIFFERENT_DIR", 1212 }, +{ "ER_LOCK_DEADLOCK", 1213 }, +{ "ER_TABLE_CANT_HANDLE_FT", 1214 }, +{ "ER_CANNOT_ADD_FOREIGN", 1215 }, +{ "ER_NO_REFERENCED_ROW", 1216 }, +{ "ER_ROW_IS_REFERENCED", 1217 }, +{ "ER_CONNECT_TO_MASTER", 1218 }, +{ "ER_QUERY_ON_MASTER", 1219 }, +{ "ER_ERROR_WHEN_EXECUTING_COMMAND", 1220 }, +{ "ER_WRONG_USAGE", 1221 }, +{ "ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT", 1222 }, +{ "ER_CANT_UPDATE_WITH_READLOCK", 1223 }, +{ "ER_MIXING_NOT_ALLOWED", 1224 }, +{ "ER_DUP_ARGUMENT", 1225 }, +{ "ER_USER_LIMIT_REACHED", 1226 }, +{ "ER_SPECIFIC_ACCESS_DENIED_ERROR", 1227 }, +{ "ER_LOCAL_VARIABLE", 1228 }, +{ "ER_GLOBAL_VARIABLE", 1229 }, +{ "ER_NO_DEFAULT", 1230 }, +{ "ER_WRONG_VALUE_FOR_VAR", 1231 }, +{ "ER_WRONG_TYPE_FOR_VAR", 1232 }, +{ "ER_VAR_CANT_BE_READ", 1233 }, +{ "ER_CANT_USE_OPTION_HERE", 1234 }, +{ "ER_NOT_SUPPORTED_YET", 1235 }, +{ "ER_MASTER_FATAL_ERROR_READING_BINLOG", 1236 }, +{ "ER_SLAVE_IGNORED_TABLE", 1237 }, +{ "ER_INCORRECT_GLOBAL_LOCAL_VAR", 1238 }, +{ "ER_WRONG_FK_DEF", 1239 }, +{ "ER_KEY_REF_DO_NOT_MATCH_TABLE_REF", 1240 }, +{ "ER_OPERAND_COLUMNS", 1241 }, +{ "ER_SUBQUERY_NO_1_ROW", 1242 }, +{ "ER_UNKNOWN_STMT_HANDLER", 1243 }, +{ "ER_CORRUPT_HELP_DB", 1244 }, +{ "ER_CYCLIC_REFERENCE", 1245 }, +{ "ER_AUTO_CONVERT", 1246 }, +{ "ER_ILLEGAL_REFERENCE", 1247 }, +{ "ER_DERIVED_MUST_HAVE_ALIAS", 1248 }, +{ "ER_SELECT_REDUCED", 1249 }, +{ "ER_TABLENAME_NOT_ALLOWED_HERE", 1250 }, +{ "ER_NOT_SUPPORTED_AUTH_MODE", 1251 }, +{ "ER_SPATIAL_CANT_HAVE_NULL", 1252 }, +{ "ER_COLLATION_CHARSET_MISMATCH", 1253 }, +{ "ER_SLAVE_WAS_RUNNING", 1254 }, +{ "ER_SLAVE_WAS_NOT_RUNNING", 1255 }, +{ "ER_TOO_BIG_FOR_UNCOMPRESS", 1256 }, +{ "ER_ZLIB_Z_MEM_ERROR", 1257 }, +{ "ER_ZLIB_Z_BUF_ERROR", 1258 }, +{ "ER_ZLIB_Z_DATA_ERROR", 1259 }, +{ "ER_CUT_VALUE_GROUP_CONCAT", 1260 }, +{ "ER_WARN_TOO_FEW_RECORDS", 1261 }, +{ "ER_WARN_TOO_MANY_RECORDS", 1262 }, +{ "ER_WARN_NULL_TO_NOTNULL", 1263 }, +{ "ER_WARN_DATA_OUT_OF_RANGE", 1264 }, +{ "WARN_DATA_TRUNCATED", 1265 }, +{ "ER_WARN_USING_OTHER_HANDLER", 1266 }, +{ "ER_CANT_AGGREGATE_2COLLATIONS", 1267 }, +{ "ER_DROP_USER", 1268 }, +{ "ER_REVOKE_GRANTS", 1269 }, +{ "ER_CANT_AGGREGATE_3COLLATIONS", 1270 }, +{ "ER_CANT_AGGREGATE_NCOLLATIONS", 1271 }, +{ "ER_VARIABLE_IS_NOT_STRUCT", 1272 }, +{ "ER_UNKNOWN_COLLATION", 1273 }, +{ "ER_SLAVE_IGNORED_SSL_PARAMS", 1274 }, +{ "ER_SERVER_IS_IN_SECURE_AUTH_MODE", 1275 }, +{ "ER_WARN_FIELD_RESOLVED", 1276 }, +{ "ER_BAD_SLAVE_UNTIL_COND", 1277 }, +{ "ER_MISSING_SKIP_SLAVE", 1278 }, +{ "ER_UNTIL_COND_IGNORED", 1279 }, +{ "ER_WRONG_NAME_FOR_INDEX", 1280 }, +{ "ER_WRONG_NAME_FOR_CATALOG", 1281 }, +{ "ER_WARN_QC_RESIZE", 1282 }, +{ "ER_BAD_FT_COLUMN", 1283 }, +{ "ER_UNKNOWN_KEY_CACHE", 1284 }, +{ "ER_WARN_HOSTNAME_WONT_WORK", 1285 }, +{ "ER_UNKNOWN_STORAGE_ENGINE", 1286 }, +{ "ER_WARN_DEPRECATED_SYNTAX", 1287 }, +{ "ER_NON_UPDATABLE_TABLE", 1288 }, +{ "ER_FEATURE_DISABLED", 1289 }, +{ "ER_OPTION_PREVENTS_STATEMENT", 1290 }, +{ "ER_DUPLICATED_VALUE_IN_TYPE", 1291 }, +{ "ER_TRUNCATED_WRONG_VALUE", 1292 }, +{ "ER_TOO_MUCH_AUTO_TIMESTAMP_COLS", 1293 }, +{ "ER_INVALID_ON_UPDATE", 1294 }, +{ "ER_UNSUPPORTED_PS", 1295 }, +{ "ER_GET_ERRMSG", 1296 }, +{ "ER_GET_TEMPORARY_ERRMSG", 1297 }, +{ "ER_UNKNOWN_TIME_ZONE", 1298 }, +{ "ER_WARN_INVALID_TIMESTAMP", 1299 }, +{ "ER_INVALID_CHARACTER_STRING", 1300 }, +{ "ER_WARN_ALLOWED_PACKET_OVERFLOWED", 1301 }, +{ "ER_CONFLICTING_DECLARATIONS", 1302 }, +{ "ER_SP_NO_RECURSIVE_CREATE", 1303 }, +{ "ER_SP_ALREADY_EXISTS", 1304 }, +{ "ER_SP_DOES_NOT_EXIST", 1305 }, +{ "ER_SP_DROP_FAILED", 1306 }, +{ "ER_SP_STORE_FAILED", 1307 }, +{ "ER_SP_LILABEL_MISMATCH", 1308 }, +{ "ER_SP_LABEL_REDEFINE", 1309 }, +{ "ER_SP_LABEL_MISMATCH", 1310 }, +{ "ER_SP_UNINIT_VAR", 1311 }, +{ "ER_SP_BADSELECT", 1312 }, +{ "ER_SP_BADRETURN", 1313 }, +{ "ER_SP_BADSTATEMENT", 1314 }, +{ "ER_UPDATE_LOG_DEPRECATED_IGNORED", 1315 }, +{ "ER_UPDATE_LOG_DEPRECATED_TRANSLATED", 1316 }, +{ "ER_QUERY_INTERRUPTED", 1317 }, +{ "ER_SP_WRONG_NO_OF_ARGS", 1318 }, +{ "ER_SP_COND_MISMATCH", 1319 }, +{ "ER_SP_NORETURN", 1320 }, +{ "ER_SP_NORETURNEND", 1321 }, +{ "ER_SP_BAD_CURSOR_QUERY", 1322 }, +{ "ER_SP_BAD_CURSOR_SELECT", 1323 }, +{ "ER_SP_CURSOR_MISMATCH", 1324 }, +{ "ER_SP_CURSOR_ALREADY_OPEN", 1325 }, +{ "ER_SP_CURSOR_NOT_OPEN", 1326 }, +{ "ER_SP_UNDECLARED_VAR", 1327 }, +{ "ER_SP_WRONG_NO_OF_FETCH_ARGS", 1328 }, +{ "ER_SP_FETCH_NO_DATA", 1329 }, +{ "ER_SP_DUP_PARAM", 1330 }, +{ "ER_SP_DUP_VAR", 1331 }, +{ "ER_SP_DUP_COND", 1332 }, +{ "ER_SP_DUP_CURS", 1333 }, +{ "ER_SP_CANT_ALTER", 1334 }, +{ "ER_SP_SUBSELECT_NYI", 1335 }, +{ "ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG", 1336 }, +{ "ER_SP_VARCOND_AFTER_CURSHNDLR", 1337 }, +{ "ER_SP_CURSOR_AFTER_HANDLER", 1338 }, +{ "ER_SP_CASE_NOT_FOUND", 1339 }, +{ "ER_FPARSER_TOO_BIG_FILE", 1340 }, +{ "ER_FPARSER_BAD_HEADER", 1341 }, +{ "ER_FPARSER_EOF_IN_COMMENT", 1342 }, +{ "ER_FPARSER_ERROR_IN_PARAMETER", 1343 }, +{ "ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER", 1344 }, +{ "ER_VIEW_NO_EXPLAIN", 1345 }, +{ "ER_FRM_UNKNOWN_TYPE", 1346 }, +{ "ER_WRONG_OBJECT", 1347 }, +{ "ER_NONUPDATEABLE_COLUMN", 1348 }, +{ "ER_VIEW_SELECT_DERIVED", 1349 }, +{ "ER_VIEW_SELECT_CLAUSE", 1350 }, +{ "ER_VIEW_SELECT_VARIABLE", 1351 }, +{ "ER_VIEW_SELECT_TMPTABLE", 1352 }, +{ "ER_VIEW_WRONG_LIST", 1353 }, +{ "ER_WARN_VIEW_MERGE", 1354 }, +{ "ER_WARN_VIEW_WITHOUT_KEY", 1355 }, +{ "ER_VIEW_INVALID", 1356 }, +{ "ER_SP_NO_DROP_SP", 1357 }, +{ "ER_SP_GOTO_IN_HNDLR", 1358 }, +{ "ER_TRG_ALREADY_EXISTS", 1359 }, +{ "ER_TRG_DOES_NOT_EXIST", 1360 }, +{ "ER_TRG_ON_VIEW_OR_TEMP_TABLE", 1361 }, +{ "ER_TRG_CANT_CHANGE_ROW", 1362 }, +{ "ER_TRG_NO_SUCH_ROW_IN_TRG", 1363 }, +{ "ER_NO_DEFAULT_FOR_FIELD", 1364 }, +{ "ER_DIVISION_BY_ZERO", 1365 }, +{ "ER_TRUNCATED_WRONG_VALUE_FOR_FIELD", 1366 }, +{ "ER_ILLEGAL_VALUE_FOR_TYPE", 1367 }, +{ "ER_VIEW_NONUPD_CHECK", 1368 }, +{ "ER_VIEW_CHECK_FAILED", 1369 }, +{ "ER_PROCACCESS_DENIED_ERROR", 1370 }, +{ "ER_RELAY_LOG_FAIL", 1371 }, +{ "ER_PASSWD_LENGTH", 1372 }, +{ "ER_UNKNOWN_TARGET_BINLOG", 1373 }, +{ "ER_IO_ERR_LOG_INDEX_READ", 1374 }, +{ "ER_BINLOG_PURGE_PROHIBITED", 1375 }, +{ "ER_FSEEK_FAIL", 1376 }, +{ "ER_BINLOG_PURGE_FATAL_ERR", 1377 }, +{ "ER_LOG_IN_USE", 1378 }, +{ "ER_LOG_PURGE_UNKNOWN_ERR", 1379 }, +{ "ER_RELAY_LOG_INIT", 1380 }, +{ "ER_NO_BINARY_LOGGING", 1381 }, +{ "ER_RESERVED_SYNTAX", 1382 }, +{ "ER_WSAS_FAILED", 1383 }, +{ "ER_DIFF_GROUPS_PROC", 1384 }, +{ "ER_NO_GROUP_FOR_PROC", 1385 }, +{ "ER_ORDER_WITH_PROC", 1386 }, +{ "ER_LOGGING_PROHIBIT_CHANGING_OF", 1387 }, +{ "ER_NO_FILE_MAPPING", 1388 }, +{ "ER_WRONG_MAGIC", 1389 }, +{ "ER_PS_MANY_PARAM", 1390 }, +{ "ER_KEY_PART_0", 1391 }, +{ "ER_VIEW_CHECKSUM", 1392 }, +{ "ER_VIEW_MULTIUPDATE", 1393 }, +{ "ER_VIEW_NO_INSERT_FIELD_LIST", 1394 }, +{ "ER_VIEW_DELETE_MERGE_VIEW", 1395 }, +{ "ER_CANNOT_USER", 1396 }, +{ "ER_XAER_NOTA", 1397 }, +{ "ER_XAER_INVAL", 1398 }, +{ "ER_XAER_RMFAIL", 1399 }, +{ "ER_XAER_OUTSIDE", 1400 }, +{ "ER_XAER_RMERR", 1401 }, +{ "ER_XA_RBROLLBACK", 1402 }, +{ "ER_NONEXISTING_PROC_GRANT", 1403 }, +{ "ER_PROC_AUTO_GRANT_FAIL", 1404 }, +{ "ER_PROC_AUTO_REVOKE_FAIL", 1405 }, +{ "ER_DATA_TOO_LONG", 1406 }, +{ "ER_SP_BAD_SQLSTATE", 1407 }, +{ "ER_STARTUP", 1408 }, +{ "ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR", 1409 }, +{ "ER_CANT_CREATE_USER_WITH_GRANT", 1410 }, +{ "ER_WRONG_VALUE_FOR_TYPE", 1411 }, +{ "ER_TABLE_DEF_CHANGED", 1412 }, +{ "ER_SP_DUP_HANDLER", 1413 }, +{ "ER_SP_NOT_VAR_ARG", 1414 }, +{ "ER_SP_NO_RETSET", 1415 }, +{ "ER_CANT_CREATE_GEOMETRY_OBJECT", 1416 }, +{ "ER_FAILED_ROUTINE_BREAK_BINLOG", 1417 }, +{ "ER_BINLOG_UNSAFE_ROUTINE", 1418 }, +{ "ER_BINLOG_CREATE_ROUTINE_NEED_SUPER", 1419 }, +{ "ER_EXEC_STMT_WITH_OPEN_CURSOR", 1420 }, +{ "ER_STMT_HAS_NO_OPEN_CURSOR", 1421 }, +{ "ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG", 1422 }, +{ "ER_NO_DEFAULT_FOR_VIEW_FIELD", 1423 }, +{ "ER_SP_NO_RECURSION", 1424 }, +{ "ER_TOO_BIG_SCALE", 1425 }, +{ "ER_TOO_BIG_PRECISION", 1426 }, +{ "ER_M_BIGGER_THAN_D", 1427 }, +{ "ER_WRONG_LOCK_OF_SYSTEM_TABLE", 1428 }, +{ "ER_CONNECT_TO_FOREIGN_DATA_SOURCE", 1429 }, +{ "ER_QUERY_ON_FOREIGN_DATA_SOURCE", 1430 }, +{ "ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST", 1431 }, +{ "ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE", 1432 }, +{ "ER_FOREIGN_DATA_STRING_INVALID", 1433 }, +{ "ER_CANT_CREATE_FEDERATED_TABLE", 1434 }, +{ "ER_TRG_IN_WRONG_SCHEMA", 1435 }, +{ "ER_STACK_OVERRUN_NEED_MORE", 1436 }, +{ "ER_TOO_LONG_BODY", 1437 }, +{ "ER_WARN_CANT_DROP_DEFAULT_KEYCACHE", 1438 }, +{ "ER_TOO_BIG_DISPLAYWIDTH", 1439 }, +{ "ER_XAER_DUPID", 1440 }, +{ "ER_DATETIME_FUNCTION_OVERFLOW", 1441 }, +{ "ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG", 1442 }, +{ "ER_VIEW_PREVENT_UPDATE", 1443 }, +{ "ER_PS_NO_RECURSION", 1444 }, +{ "ER_SP_CANT_SET_AUTOCOMMIT", 1445 }, +{ "ER_MALFORMED_DEFINER", 1446 }, +{ "ER_VIEW_FRM_NO_USER", 1447 }, +{ "ER_VIEW_OTHER_USER", 1448 }, +{ "ER_NO_SUCH_USER", 1449 }, +{ "ER_FORBID_SCHEMA_CHANGE", 1450 }, +{ "ER_ROW_IS_REFERENCED_2", 1451 }, +{ "ER_NO_REFERENCED_ROW_2", 1452 }, +{ "ER_SP_BAD_VAR_SHADOW", 1453 }, +{ "ER_TRG_NO_DEFINER", 1454 }, +{ "ER_OLD_FILE_FORMAT", 1455 }, +{ "ER_SP_RECURSION_LIMIT", 1456 }, +{ "ER_SP_PROC_TABLE_CORRUPT", 1457 }, +{ "ER_SP_WRONG_NAME", 1458 }, +{ "ER_TABLE_NEEDS_UPGRADE", 1459 }, +{ "ER_SP_NO_AGGREGATE", 1460 }, +{ "ER_MAX_PREPARED_STMT_COUNT_REACHED", 1461 }, +{ "ER_VIEW_RECURSIVE", 1462 }, +{ "ER_NON_GROUPING_FIELD_USED", 1463 }, +{ "ER_TABLE_CANT_HANDLE_SPKEYS", 1464 }, +{ "ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA", 1465 }, +{ "ER_REMOVED_SPACES", 1466 }, +{ "ER_AUTOINC_READ_FAILED", 1467 }, +{ "ER_USERNAME", 1468 }, +{ "ER_HOSTNAME", 1469 }, +{ "ER_WRONG_STRING_LENGTH", 1470 }, +{ "ER_NON_INSERTABLE_TABLE", 1471 }, diff --git a/code/meosdb/mysql50/mysqld_error.h b/code/meosdb/mysql50/mysqld_error.h new file mode 100644 index 0000000..1448697 --- /dev/null +++ b/code/meosdb/mysql50/mysqld_error.h @@ -0,0 +1,476 @@ +/* Autogenerated file, please don't edit */ + +#define ER_ERROR_FIRST 1000 +#define ER_HASHCHK 1000 +#define ER_NISAMCHK 1001 +#define ER_NO 1002 +#define ER_YES 1003 +#define ER_CANT_CREATE_FILE 1004 +#define ER_CANT_CREATE_TABLE 1005 +#define ER_CANT_CREATE_DB 1006 +#define ER_DB_CREATE_EXISTS 1007 +#define ER_DB_DROP_EXISTS 1008 +#define ER_DB_DROP_DELETE 1009 +#define ER_DB_DROP_RMDIR 1010 +#define ER_CANT_DELETE_FILE 1011 +#define ER_CANT_FIND_SYSTEM_REC 1012 +#define ER_CANT_GET_STAT 1013 +#define ER_CANT_GET_WD 1014 +#define ER_CANT_LOCK 1015 +#define ER_CANT_OPEN_FILE 1016 +#define ER_FILE_NOT_FOUND 1017 +#define ER_CANT_READ_DIR 1018 +#define ER_CANT_SET_WD 1019 +#define ER_CHECKREAD 1020 +#define ER_DISK_FULL 1021 +#define ER_DUP_KEY 1022 +#define ER_ERROR_ON_CLOSE 1023 +#define ER_ERROR_ON_READ 1024 +#define ER_ERROR_ON_RENAME 1025 +#define ER_ERROR_ON_WRITE 1026 +#define ER_FILE_USED 1027 +#define ER_FILSORT_ABORT 1028 +#define ER_FORM_NOT_FOUND 1029 +#define ER_GET_ERRNO 1030 +#define ER_ILLEGAL_HA 1031 +#define ER_KEY_NOT_FOUND 1032 +#define ER_NOT_FORM_FILE 1033 +#define ER_NOT_KEYFILE 1034 +#define ER_OLD_KEYFILE 1035 +#define ER_OPEN_AS_READONLY 1036 +#define ER_OUTOFMEMORY 1037 +#define ER_OUT_OF_SORTMEMORY 1038 +#define ER_UNEXPECTED_EOF 1039 +#define ER_CON_COUNT_ERROR 1040 +#define ER_OUT_OF_RESOURCES 1041 +#define ER_BAD_HOST_ERROR 1042 +#define ER_HANDSHAKE_ERROR 1043 +#define ER_DBACCESS_DENIED_ERROR 1044 +#define ER_ACCESS_DENIED_ERROR 1045 +#define ER_NO_DB_ERROR 1046 +#define ER_UNKNOWN_COM_ERROR 1047 +#define ER_BAD_NULL_ERROR 1048 +#define ER_BAD_DB_ERROR 1049 +#define ER_TABLE_EXISTS_ERROR 1050 +#define ER_BAD_TABLE_ERROR 1051 +#define ER_NON_UNIQ_ERROR 1052 +#define ER_SERVER_SHUTDOWN 1053 +#define ER_BAD_FIELD_ERROR 1054 +#define ER_WRONG_FIELD_WITH_GROUP 1055 +#define ER_WRONG_GROUP_FIELD 1056 +#define ER_WRONG_SUM_SELECT 1057 +#define ER_WRONG_VALUE_COUNT 1058 +#define ER_TOO_LONG_IDENT 1059 +#define ER_DUP_FIELDNAME 1060 +#define ER_DUP_KEYNAME 1061 +#define ER_DUP_ENTRY 1062 +#define ER_WRONG_FIELD_SPEC 1063 +#define ER_PARSE_ERROR 1064 +#define ER_EMPTY_QUERY 1065 +#define ER_NONUNIQ_TABLE 1066 +#define ER_INVALID_DEFAULT 1067 +#define ER_MULTIPLE_PRI_KEY 1068 +#define ER_TOO_MANY_KEYS 1069 +#define ER_TOO_MANY_KEY_PARTS 1070 +#define ER_TOO_LONG_KEY 1071 +#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072 +#define ER_BLOB_USED_AS_KEY 1073 +#define ER_TOO_BIG_FIELDLENGTH 1074 +#define ER_WRONG_AUTO_KEY 1075 +#define ER_READY 1076 +#define ER_NORMAL_SHUTDOWN 1077 +#define ER_GOT_SIGNAL 1078 +#define ER_SHUTDOWN_COMPLETE 1079 +#define ER_FORCING_CLOSE 1080 +#define ER_IPSOCK_ERROR 1081 +#define ER_NO_SUCH_INDEX 1082 +#define ER_WRONG_FIELD_TERMINATORS 1083 +#define ER_BLOBS_AND_NO_TERMINATED 1084 +#define ER_TEXTFILE_NOT_READABLE 1085 +#define ER_FILE_EXISTS_ERROR 1086 +#define ER_LOAD_INFO 1087 +#define ER_ALTER_INFO 1088 +#define ER_WRONG_SUB_KEY 1089 +#define ER_CANT_REMOVE_ALL_FIELDS 1090 +#define ER_CANT_DROP_FIELD_OR_KEY 1091 +#define ER_INSERT_INFO 1092 +#define ER_UPDATE_TABLE_USED 1093 +#define ER_NO_SUCH_THREAD 1094 +#define ER_KILL_DENIED_ERROR 1095 +#define ER_NO_TABLES_USED 1096 +#define ER_TOO_BIG_SET 1097 +#define ER_NO_UNIQUE_LOGFILE 1098 +#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 +#define ER_TABLE_NOT_LOCKED 1100 +#define ER_BLOB_CANT_HAVE_DEFAULT 1101 +#define ER_WRONG_DB_NAME 1102 +#define ER_WRONG_TABLE_NAME 1103 +#define ER_TOO_BIG_SELECT 1104 +#define ER_UNKNOWN_ERROR 1105 +#define ER_UNKNOWN_PROCEDURE 1106 +#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 +#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 +#define ER_UNKNOWN_TABLE 1109 +#define ER_FIELD_SPECIFIED_TWICE 1110 +#define ER_INVALID_GROUP_FUNC_USE 1111 +#define ER_UNSUPPORTED_EXTENSION 1112 +#define ER_TABLE_MUST_HAVE_COLUMNS 1113 +#define ER_RECORD_FILE_FULL 1114 +#define ER_UNKNOWN_CHARACTER_SET 1115 +#define ER_TOO_MANY_TABLES 1116 +#define ER_TOO_MANY_FIELDS 1117 +#define ER_TOO_BIG_ROWSIZE 1118 +#define ER_STACK_OVERRUN 1119 +#define ER_WRONG_OUTER_JOIN 1120 +#define ER_NULL_COLUMN_IN_INDEX 1121 +#define ER_CANT_FIND_UDF 1122 +#define ER_CANT_INITIALIZE_UDF 1123 +#define ER_UDF_NO_PATHS 1124 +#define ER_UDF_EXISTS 1125 +#define ER_CANT_OPEN_LIBRARY 1126 +#define ER_CANT_FIND_DL_ENTRY 1127 +#define ER_FUNCTION_NOT_DEFINED 1128 +#define ER_HOST_IS_BLOCKED 1129 +#define ER_HOST_NOT_PRIVILEGED 1130 +#define ER_PASSWORD_ANONYMOUS_USER 1131 +#define ER_PASSWORD_NOT_ALLOWED 1132 +#define ER_PASSWORD_NO_MATCH 1133 +#define ER_UPDATE_INFO 1134 +#define ER_CANT_CREATE_THREAD 1135 +#define ER_WRONG_VALUE_COUNT_ON_ROW 1136 +#define ER_CANT_REOPEN_TABLE 1137 +#define ER_INVALID_USE_OF_NULL 1138 +#define ER_REGEXP_ERROR 1139 +#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 +#define ER_NONEXISTING_GRANT 1141 +#define ER_TABLEACCESS_DENIED_ERROR 1142 +#define ER_COLUMNACCESS_DENIED_ERROR 1143 +#define ER_ILLEGAL_GRANT_FOR_TABLE 1144 +#define ER_GRANT_WRONG_HOST_OR_USER 1145 +#define ER_NO_SUCH_TABLE 1146 +#define ER_NONEXISTING_TABLE_GRANT 1147 +#define ER_NOT_ALLOWED_COMMAND 1148 +#define ER_SYNTAX_ERROR 1149 +#define ER_DELAYED_CANT_CHANGE_LOCK 1150 +#define ER_TOO_MANY_DELAYED_THREADS 1151 +#define ER_ABORTING_CONNECTION 1152 +#define ER_NET_PACKET_TOO_LARGE 1153 +#define ER_NET_READ_ERROR_FROM_PIPE 1154 +#define ER_NET_FCNTL_ERROR 1155 +#define ER_NET_PACKETS_OUT_OF_ORDER 1156 +#define ER_NET_UNCOMPRESS_ERROR 1157 +#define ER_NET_READ_ERROR 1158 +#define ER_NET_READ_INTERRUPTED 1159 +#define ER_NET_ERROR_ON_WRITE 1160 +#define ER_NET_WRITE_INTERRUPTED 1161 +#define ER_TOO_LONG_STRING 1162 +#define ER_TABLE_CANT_HANDLE_BLOB 1163 +#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 +#define ER_DELAYED_INSERT_TABLE_LOCKED 1165 +#define ER_WRONG_COLUMN_NAME 1166 +#define ER_WRONG_KEY_COLUMN 1167 +#define ER_WRONG_MRG_TABLE 1168 +#define ER_DUP_UNIQUE 1169 +#define ER_BLOB_KEY_WITHOUT_LENGTH 1170 +#define ER_PRIMARY_CANT_HAVE_NULL 1171 +#define ER_TOO_MANY_ROWS 1172 +#define ER_REQUIRES_PRIMARY_KEY 1173 +#define ER_NO_RAID_COMPILED 1174 +#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 +#define ER_KEY_DOES_NOT_EXITS 1176 +#define ER_CHECK_NO_SUCH_TABLE 1177 +#define ER_CHECK_NOT_IMPLEMENTED 1178 +#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 +#define ER_ERROR_DURING_COMMIT 1180 +#define ER_ERROR_DURING_ROLLBACK 1181 +#define ER_ERROR_DURING_FLUSH_LOGS 1182 +#define ER_ERROR_DURING_CHECKPOINT 1183 +#define ER_NEW_ABORTING_CONNECTION 1184 +#define ER_DUMP_NOT_IMPLEMENTED 1185 +#define ER_FLUSH_MASTER_BINLOG_CLOSED 1186 +#define ER_INDEX_REBUILD 1187 +#define ER_MASTER 1188 +#define ER_MASTER_NET_READ 1189 +#define ER_MASTER_NET_WRITE 1190 +#define ER_FT_MATCHING_KEY_NOT_FOUND 1191 +#define ER_LOCK_OR_ACTIVE_TRANSACTION 1192 +#define ER_UNKNOWN_SYSTEM_VARIABLE 1193 +#define ER_CRASHED_ON_USAGE 1194 +#define ER_CRASHED_ON_REPAIR 1195 +#define ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 +#define ER_TRANS_CACHE_FULL 1197 +#define ER_SLAVE_MUST_STOP 1198 +#define ER_SLAVE_NOT_RUNNING 1199 +#define ER_BAD_SLAVE 1200 +#define ER_MASTER_INFO 1201 +#define ER_SLAVE_THREAD 1202 +#define ER_TOO_MANY_USER_CONNECTIONS 1203 +#define ER_SET_CONSTANTS_ONLY 1204 +#define ER_LOCK_WAIT_TIMEOUT 1205 +#define ER_LOCK_TABLE_FULL 1206 +#define ER_READ_ONLY_TRANSACTION 1207 +#define ER_DROP_DB_WITH_READ_LOCK 1208 +#define ER_CREATE_DB_WITH_READ_LOCK 1209 +#define ER_WRONG_ARGUMENTS 1210 +#define ER_NO_PERMISSION_TO_CREATE_USER 1211 +#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 +#define ER_LOCK_DEADLOCK 1213 +#define ER_TABLE_CANT_HANDLE_FT 1214 +#define ER_CANNOT_ADD_FOREIGN 1215 +#define ER_NO_REFERENCED_ROW 1216 +#define ER_ROW_IS_REFERENCED 1217 +#define ER_CONNECT_TO_MASTER 1218 +#define ER_QUERY_ON_MASTER 1219 +#define ER_ERROR_WHEN_EXECUTING_COMMAND 1220 +#define ER_WRONG_USAGE 1221 +#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 +#define ER_CANT_UPDATE_WITH_READLOCK 1223 +#define ER_MIXING_NOT_ALLOWED 1224 +#define ER_DUP_ARGUMENT 1225 +#define ER_USER_LIMIT_REACHED 1226 +#define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 +#define ER_LOCAL_VARIABLE 1228 +#define ER_GLOBAL_VARIABLE 1229 +#define ER_NO_DEFAULT 1230 +#define ER_WRONG_VALUE_FOR_VAR 1231 +#define ER_WRONG_TYPE_FOR_VAR 1232 +#define ER_VAR_CANT_BE_READ 1233 +#define ER_CANT_USE_OPTION_HERE 1234 +#define ER_NOT_SUPPORTED_YET 1235 +#define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 +#define ER_SLAVE_IGNORED_TABLE 1237 +#define ER_INCORRECT_GLOBAL_LOCAL_VAR 1238 +#define ER_WRONG_FK_DEF 1239 +#define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240 +#define ER_OPERAND_COLUMNS 1241 +#define ER_SUBQUERY_NO_1_ROW 1242 +#define ER_UNKNOWN_STMT_HANDLER 1243 +#define ER_CORRUPT_HELP_DB 1244 +#define ER_CYCLIC_REFERENCE 1245 +#define ER_AUTO_CONVERT 1246 +#define ER_ILLEGAL_REFERENCE 1247 +#define ER_DERIVED_MUST_HAVE_ALIAS 1248 +#define ER_SELECT_REDUCED 1249 +#define ER_TABLENAME_NOT_ALLOWED_HERE 1250 +#define ER_NOT_SUPPORTED_AUTH_MODE 1251 +#define ER_SPATIAL_CANT_HAVE_NULL 1252 +#define ER_COLLATION_CHARSET_MISMATCH 1253 +#define ER_SLAVE_WAS_RUNNING 1254 +#define ER_SLAVE_WAS_NOT_RUNNING 1255 +#define ER_TOO_BIG_FOR_UNCOMPRESS 1256 +#define ER_ZLIB_Z_MEM_ERROR 1257 +#define ER_ZLIB_Z_BUF_ERROR 1258 +#define ER_ZLIB_Z_DATA_ERROR 1259 +#define ER_CUT_VALUE_GROUP_CONCAT 1260 +#define ER_WARN_TOO_FEW_RECORDS 1261 +#define ER_WARN_TOO_MANY_RECORDS 1262 +#define ER_WARN_NULL_TO_NOTNULL 1263 +#define ER_WARN_DATA_OUT_OF_RANGE 1264 +#define WARN_DATA_TRUNCATED 1265 +#define ER_WARN_USING_OTHER_HANDLER 1266 +#define ER_CANT_AGGREGATE_2COLLATIONS 1267 +#define ER_DROP_USER 1268 +#define ER_REVOKE_GRANTS 1269 +#define ER_CANT_AGGREGATE_3COLLATIONS 1270 +#define ER_CANT_AGGREGATE_NCOLLATIONS 1271 +#define ER_VARIABLE_IS_NOT_STRUCT 1272 +#define ER_UNKNOWN_COLLATION 1273 +#define ER_SLAVE_IGNORED_SSL_PARAMS 1274 +#define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275 +#define ER_WARN_FIELD_RESOLVED 1276 +#define ER_BAD_SLAVE_UNTIL_COND 1277 +#define ER_MISSING_SKIP_SLAVE 1278 +#define ER_UNTIL_COND_IGNORED 1279 +#define ER_WRONG_NAME_FOR_INDEX 1280 +#define ER_WRONG_NAME_FOR_CATALOG 1281 +#define ER_WARN_QC_RESIZE 1282 +#define ER_BAD_FT_COLUMN 1283 +#define ER_UNKNOWN_KEY_CACHE 1284 +#define ER_WARN_HOSTNAME_WONT_WORK 1285 +#define ER_UNKNOWN_STORAGE_ENGINE 1286 +#define ER_WARN_DEPRECATED_SYNTAX 1287 +#define ER_NON_UPDATABLE_TABLE 1288 +#define ER_FEATURE_DISABLED 1289 +#define ER_OPTION_PREVENTS_STATEMENT 1290 +#define ER_DUPLICATED_VALUE_IN_TYPE 1291 +#define ER_TRUNCATED_WRONG_VALUE 1292 +#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 +#define ER_INVALID_ON_UPDATE 1294 +#define ER_UNSUPPORTED_PS 1295 +#define ER_GET_ERRMSG 1296 +#define ER_GET_TEMPORARY_ERRMSG 1297 +#define ER_UNKNOWN_TIME_ZONE 1298 +#define ER_WARN_INVALID_TIMESTAMP 1299 +#define ER_INVALID_CHARACTER_STRING 1300 +#define ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301 +#define ER_CONFLICTING_DECLARATIONS 1302 +#define ER_SP_NO_RECURSIVE_CREATE 1303 +#define ER_SP_ALREADY_EXISTS 1304 +#define ER_SP_DOES_NOT_EXIST 1305 +#define ER_SP_DROP_FAILED 1306 +#define ER_SP_STORE_FAILED 1307 +#define ER_SP_LILABEL_MISMATCH 1308 +#define ER_SP_LABEL_REDEFINE 1309 +#define ER_SP_LABEL_MISMATCH 1310 +#define ER_SP_UNINIT_VAR 1311 +#define ER_SP_BADSELECT 1312 +#define ER_SP_BADRETURN 1313 +#define ER_SP_BADSTATEMENT 1314 +#define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 +#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 +#define ER_QUERY_INTERRUPTED 1317 +#define ER_SP_WRONG_NO_OF_ARGS 1318 +#define ER_SP_COND_MISMATCH 1319 +#define ER_SP_NORETURN 1320 +#define ER_SP_NORETURNEND 1321 +#define ER_SP_BAD_CURSOR_QUERY 1322 +#define ER_SP_BAD_CURSOR_SELECT 1323 +#define ER_SP_CURSOR_MISMATCH 1324 +#define ER_SP_CURSOR_ALREADY_OPEN 1325 +#define ER_SP_CURSOR_NOT_OPEN 1326 +#define ER_SP_UNDECLARED_VAR 1327 +#define ER_SP_WRONG_NO_OF_FETCH_ARGS 1328 +#define ER_SP_FETCH_NO_DATA 1329 +#define ER_SP_DUP_PARAM 1330 +#define ER_SP_DUP_VAR 1331 +#define ER_SP_DUP_COND 1332 +#define ER_SP_DUP_CURS 1333 +#define ER_SP_CANT_ALTER 1334 +#define ER_SP_SUBSELECT_NYI 1335 +#define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 +#define ER_SP_VARCOND_AFTER_CURSHNDLR 1337 +#define ER_SP_CURSOR_AFTER_HANDLER 1338 +#define ER_SP_CASE_NOT_FOUND 1339 +#define ER_FPARSER_TOO_BIG_FILE 1340 +#define ER_FPARSER_BAD_HEADER 1341 +#define ER_FPARSER_EOF_IN_COMMENT 1342 +#define ER_FPARSER_ERROR_IN_PARAMETER 1343 +#define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1344 +#define ER_VIEW_NO_EXPLAIN 1345 +#define ER_FRM_UNKNOWN_TYPE 1346 +#define ER_WRONG_OBJECT 1347 +#define ER_NONUPDATEABLE_COLUMN 1348 +#define ER_VIEW_SELECT_DERIVED 1349 +#define ER_VIEW_SELECT_CLAUSE 1350 +#define ER_VIEW_SELECT_VARIABLE 1351 +#define ER_VIEW_SELECT_TMPTABLE 1352 +#define ER_VIEW_WRONG_LIST 1353 +#define ER_WARN_VIEW_MERGE 1354 +#define ER_WARN_VIEW_WITHOUT_KEY 1355 +#define ER_VIEW_INVALID 1356 +#define ER_SP_NO_DROP_SP 1357 +#define ER_SP_GOTO_IN_HNDLR 1358 +#define ER_TRG_ALREADY_EXISTS 1359 +#define ER_TRG_DOES_NOT_EXIST 1360 +#define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 +#define ER_TRG_CANT_CHANGE_ROW 1362 +#define ER_TRG_NO_SUCH_ROW_IN_TRG 1363 +#define ER_NO_DEFAULT_FOR_FIELD 1364 +#define ER_DIVISION_BY_ZERO 1365 +#define ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 1366 +#define ER_ILLEGAL_VALUE_FOR_TYPE 1367 +#define ER_VIEW_NONUPD_CHECK 1368 +#define ER_VIEW_CHECK_FAILED 1369 +#define ER_PROCACCESS_DENIED_ERROR 1370 +#define ER_RELAY_LOG_FAIL 1371 +#define ER_PASSWD_LENGTH 1372 +#define ER_UNKNOWN_TARGET_BINLOG 1373 +#define ER_IO_ERR_LOG_INDEX_READ 1374 +#define ER_BINLOG_PURGE_PROHIBITED 1375 +#define ER_FSEEK_FAIL 1376 +#define ER_BINLOG_PURGE_FATAL_ERR 1377 +#define ER_LOG_IN_USE 1378 +#define ER_LOG_PURGE_UNKNOWN_ERR 1379 +#define ER_RELAY_LOG_INIT 1380 +#define ER_NO_BINARY_LOGGING 1381 +#define ER_RESERVED_SYNTAX 1382 +#define ER_WSAS_FAILED 1383 +#define ER_DIFF_GROUPS_PROC 1384 +#define ER_NO_GROUP_FOR_PROC 1385 +#define ER_ORDER_WITH_PROC 1386 +#define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 +#define ER_NO_FILE_MAPPING 1388 +#define ER_WRONG_MAGIC 1389 +#define ER_PS_MANY_PARAM 1390 +#define ER_KEY_PART_0 1391 +#define ER_VIEW_CHECKSUM 1392 +#define ER_VIEW_MULTIUPDATE 1393 +#define ER_VIEW_NO_INSERT_FIELD_LIST 1394 +#define ER_VIEW_DELETE_MERGE_VIEW 1395 +#define ER_CANNOT_USER 1396 +#define ER_XAER_NOTA 1397 +#define ER_XAER_INVAL 1398 +#define ER_XAER_RMFAIL 1399 +#define ER_XAER_OUTSIDE 1400 +#define ER_XAER_RMERR 1401 +#define ER_XA_RBROLLBACK 1402 +#define ER_NONEXISTING_PROC_GRANT 1403 +#define ER_PROC_AUTO_GRANT_FAIL 1404 +#define ER_PROC_AUTO_REVOKE_FAIL 1405 +#define ER_DATA_TOO_LONG 1406 +#define ER_SP_BAD_SQLSTATE 1407 +#define ER_STARTUP 1408 +#define ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR 1409 +#define ER_CANT_CREATE_USER_WITH_GRANT 1410 +#define ER_WRONG_VALUE_FOR_TYPE 1411 +#define ER_TABLE_DEF_CHANGED 1412 +#define ER_SP_DUP_HANDLER 1413 +#define ER_SP_NOT_VAR_ARG 1414 +#define ER_SP_NO_RETSET 1415 +#define ER_CANT_CREATE_GEOMETRY_OBJECT 1416 +#define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 +#define ER_BINLOG_UNSAFE_ROUTINE 1418 +#define ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 +#define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 +#define ER_STMT_HAS_NO_OPEN_CURSOR 1421 +#define ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 +#define ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 +#define ER_SP_NO_RECURSION 1424 +#define ER_TOO_BIG_SCALE 1425 +#define ER_TOO_BIG_PRECISION 1426 +#define ER_M_BIGGER_THAN_D 1427 +#define ER_WRONG_LOCK_OF_SYSTEM_TABLE 1428 +#define ER_CONNECT_TO_FOREIGN_DATA_SOURCE 1429 +#define ER_QUERY_ON_FOREIGN_DATA_SOURCE 1430 +#define ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST 1431 +#define ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE 1432 +#define ER_FOREIGN_DATA_STRING_INVALID 1433 +#define ER_CANT_CREATE_FEDERATED_TABLE 1434 +#define ER_TRG_IN_WRONG_SCHEMA 1435 +#define ER_STACK_OVERRUN_NEED_MORE 1436 +#define ER_TOO_LONG_BODY 1437 +#define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 +#define ER_TOO_BIG_DISPLAYWIDTH 1439 +#define ER_XAER_DUPID 1440 +#define ER_DATETIME_FUNCTION_OVERFLOW 1441 +#define ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 +#define ER_VIEW_PREVENT_UPDATE 1443 +#define ER_PS_NO_RECURSION 1444 +#define ER_SP_CANT_SET_AUTOCOMMIT 1445 +#define ER_MALFORMED_DEFINER 1446 +#define ER_VIEW_FRM_NO_USER 1447 +#define ER_VIEW_OTHER_USER 1448 +#define ER_NO_SUCH_USER 1449 +#define ER_FORBID_SCHEMA_CHANGE 1450 +#define ER_ROW_IS_REFERENCED_2 1451 +#define ER_NO_REFERENCED_ROW_2 1452 +#define ER_SP_BAD_VAR_SHADOW 1453 +#define ER_TRG_NO_DEFINER 1454 +#define ER_OLD_FILE_FORMAT 1455 +#define ER_SP_RECURSION_LIMIT 1456 +#define ER_SP_PROC_TABLE_CORRUPT 1457 +#define ER_SP_WRONG_NAME 1458 +#define ER_TABLE_NEEDS_UPGRADE 1459 +#define ER_SP_NO_AGGREGATE 1460 +#define ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 +#define ER_VIEW_RECURSIVE 1462 +#define ER_NON_GROUPING_FIELD_USED 1463 +#define ER_TABLE_CANT_HANDLE_SPKEYS 1464 +#define ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA 1465 +#define ER_REMOVED_SPACES 1466 +#define ER_AUTOINC_READ_FAILED 1467 +#define ER_USERNAME 1468 +#define ER_HOSTNAME 1469 +#define ER_WRONG_STRING_LENGTH 1470 +#define ER_NON_INSERTABLE_TABLE 1471 +#define ER_ERROR_LAST 1471 diff --git a/code/meosdb/mysql50/raid.h b/code/meosdb/mysql50/raid.h new file mode 100644 index 0000000..740f045 --- /dev/null +++ b/code/meosdb/mysql50/raid.h @@ -0,0 +1,158 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Parser needs these defines always, even if USE_RAID is not defined */ +#define RAID_TYPE_0 1 /* Striping */ +#define RAID_TYPE_x 2 /* Some new modes */ +#define RAID_TYPE_y 3 + +#define RAID_DEFAULT_CHUNKS 4 +#define RAID_DEFAULT_CHUNKSIZE 256*1024 /* 256kB */ + +C_MODE_START +#define my_raid_type(raid_type) raid_type_string[(int)(raid_type)] +extern const char *raid_type_string[]; +C_MODE_END + +#ifdef DONT_USE_RAID +#undef USE_RAID +#endif +#if defined(USE_RAID) + +#include "my_dir.h" + +/* Trap all occurences of my_...() in source and use our wrapper around this function */ + +#ifdef MAP_TO_USE_RAID +#define my_read(A,B,C,D) my_raid_read(A,B,C,D) +#define my_write(A,B,C,D) my_raid_write(A,B,C,D) +#define my_pwrite(A,B,C,D,E) my_raid_pwrite(A,B,C,D,E) +#define my_pread(A,B,C,D,E) my_raid_pread(A,B,C,D,E) +#define my_chsize(A,B,C,D) my_raid_chsize(A,B,C,D) +#define my_close(A,B) my_raid_close(A,B) +#define my_tell(A,B) my_raid_tell(A,B) +#define my_seek(A,B,C,D) my_raid_seek(A,B,C,D) +#define my_lock(A,B,C,D,E) my_raid_lock(A,B,C,D,E) +#define my_fstat(A,B,C) my_raid_fstat(A,B,C) +#endif /* MAP_TO_USE_RAID */ + +#ifdef __cplusplus +extern "C" { +#endif + + void init_raid(void); + void end_raid(void); + + bool is_raid(File fd); + File my_raid_create(const char *FileName, int CreateFlags, int access_flags, + uint raid_type, uint raid_chunks, ulong raid_chunksize, + myf MyFlags); + File my_raid_open(const char *FileName, int Flags, + uint raid_type, uint raid_chunks, ulong raid_chunksize, + myf MyFlags); + int my_raid_rename(const char *from, const char *to, uint raid_chunks, + myf MyFlags); + int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags); + int my_raid_redel(const char *old_name, const char *new_name, + uint raid_chunks, myf MyFlags); + + my_off_t my_raid_seek(File fd, my_off_t pos, int whence, myf MyFlags); + my_off_t my_raid_tell(File fd, myf MyFlags); + + uint my_raid_write(File,const byte *Buffer, uint Count, myf MyFlags); + uint my_raid_read(File Filedes, byte *Buffer, uint Count, myf MyFlags); + + uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, + myf MyFlags); + uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count, + my_off_t offset, myf MyFlags); + + int my_raid_lock(File,int locktype, my_off_t start, my_off_t length, + myf MyFlags); + int my_raid_chsize(File fd, my_off_t newlength, int filler, myf MyFlags); + int my_raid_close(File, myf MyFlags); + int my_raid_fstat(int Filedes, struct stat *buf, myf MyFlags); + +#ifdef __cplusplus +} + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +class RaidName { + public: + RaidName(const char *FileName); + ~RaidName(); + bool IsRaid(); + int Rename(const char * from, const char * to, myf MyFlags); + private: + uint _raid_type; /* RAID_TYPE_0 or RAID_TYPE_1 or RAID_TYPE_5 */ + uint _raid_chunks; /* 1..n */ + ulong _raid_chunksize; /* 1..n in bytes */ +}; + +class RaidFd { + public: + RaidFd(uint raid_type, uint raid_chunks , ulong raid_chunksize); + ~RaidFd(); + File Create(const char *FileName, int CreateFlags, int access_flags, + myf MyFlags); + File Open(const char *FileName, int Flags, myf MyFlags); + my_off_t Seek(my_off_t pos,int whence,myf MyFlags); + my_off_t Tell(myf MyFlags); + int Write(const byte *Buffer, uint Count, myf MyFlags); + int Read(const byte *Buffer, uint Count, myf MyFlags); + int Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags); + int Chsize(File fd, my_off_t newlength, int filler, myf MyFlags); + int Fstat(int fd, MY_STAT *stat_area, myf MyFlags ); + int Close(myf MyFlags); + static bool IsRaid(File fd); + static DYNAMIC_ARRAY _raid_map; /* Map of RaidFD* */ + private: + + uint _raid_type; /* RAID_TYPE_0 or RAID_TYPE_1 or RAID_TYPE_5 */ + uint _raid_chunks; /* 1..n */ + ulong _raid_chunksize; /* 1..n in bytes */ + + ulong _total_block; /* We are operating with block no x (can be 0..many). */ + uint _this_block; /* can be 0.._raid_chunks */ + uint _remaining_bytes; /* Maximum bytes that can be written in this block */ + + my_off_t _position; + my_off_t _size; /* Cached file size for faster seek(SEEK_END) */ + File _fd; + File *_fd_vector; /* Array of File */ + off_t *_seek_vector; /* Array of cached seek positions */ + + inline void Calculate() + { + DBUG_ENTER("RaidFd::_Calculate"); + DBUG_PRINT("info",("_position: %lu _raid_chunksize: %lu _size: %lu", + (ulong) _position, _raid_chunksize, (ulong) _size)); + + _total_block = (ulong) (_position / _raid_chunksize); + _this_block = _total_block % _raid_chunks; /* can be 0.._raid_chunks */ + _remaining_bytes = (uint) (_raid_chunksize - + (_position - _total_block * _raid_chunksize)); + DBUG_PRINT("info", + ("_total_block: %lu this_block: %d _remaining_bytes: %d", + _total_block, _this_block, _remaining_bytes)); + DBUG_VOID_RETURN; + } +}; + +#endif /* __cplusplus */ +#endif /* USE_RAID */ diff --git a/code/meosdb/mysql50/sql_common.h b/code/meosdb/mysql50/sql_common.h new file mode 100644 index 0000000..df00c1b --- /dev/null +++ b/code/meosdb/mysql50/sql_common.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2003-2004, 2006 MySQL AB + + 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; version 2 of the License. + + 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 */ + + +extern const char *unknown_sqlstate; +extern const char *not_error_sqlstate; + +#ifdef __cplusplus +extern "C" { +#endif + +extern CHARSET_INFO *default_client_charset_info; +MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, + my_bool default_value, uint server_capabilities); +void free_rows(MYSQL_DATA *cur); +void free_old_query(MYSQL *mysql); +void end_server(MYSQL *mysql); +my_bool mysql_reconnect(MYSQL *mysql); +void mysql_read_default_options(struct st_mysql_options *options, + const char *filename,const char *group); +my_bool +cli_advanced_command(MYSQL *mysql, enum enum_server_command command, + const char *header, ulong header_length, + const char *arg, ulong arg_length, my_bool skip_check, + MYSQL_STMT *stmt); +unsigned long cli_safe_read(MYSQL *mysql); +void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode, + const char *sqlstate); +void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); +#ifdef __cplusplus +} +#endif + +#define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41) + diff --git a/code/meosdb/mysql50/sql_state.h b/code/meosdb/mysql50/sql_state.h new file mode 100644 index 0000000..ff3304c --- /dev/null +++ b/code/meosdb/mysql50/sql_state.h @@ -0,0 +1,201 @@ +/* Autogenerated file, please don't edit */ + +ER_DUP_KEY ,"23000", "", +ER_OUTOFMEMORY ,"HY001", "S1001", +ER_OUT_OF_SORTMEMORY ,"HY001", "S1001", +ER_CON_COUNT_ERROR ,"08004", "", +ER_BAD_HOST_ERROR ,"08S01", "", +ER_HANDSHAKE_ERROR ,"08S01", "", +ER_DBACCESS_DENIED_ERROR ,"42000", "", +ER_ACCESS_DENIED_ERROR ,"28000", "", +ER_NO_DB_ERROR ,"3D000", "", +ER_UNKNOWN_COM_ERROR ,"08S01", "", +ER_BAD_NULL_ERROR ,"23000", "", +ER_BAD_DB_ERROR ,"42000", "", +ER_TABLE_EXISTS_ERROR ,"42S01", "", +ER_BAD_TABLE_ERROR ,"42S02", "", +ER_NON_UNIQ_ERROR ,"23000", "", +ER_SERVER_SHUTDOWN ,"08S01", "", +ER_BAD_FIELD_ERROR ,"42S22", "S0022", +ER_WRONG_FIELD_WITH_GROUP ,"42000", "S1009", +ER_WRONG_GROUP_FIELD ,"42000", "S1009", +ER_WRONG_SUM_SELECT ,"42000", "S1009", +ER_WRONG_VALUE_COUNT ,"21S01", "", +ER_TOO_LONG_IDENT ,"42000", "S1009", +ER_DUP_FIELDNAME ,"42S21", "S1009", +ER_DUP_KEYNAME ,"42000", "S1009", +ER_DUP_ENTRY ,"23000", "S1009", +ER_WRONG_FIELD_SPEC ,"42000", "S1009", +ER_PARSE_ERROR ,"42000", "", +ER_EMPTY_QUERY ,"42000", "", +ER_NONUNIQ_TABLE ,"42000", "S1009", +ER_INVALID_DEFAULT ,"42000", "S1009", +ER_MULTIPLE_PRI_KEY ,"42000", "S1009", +ER_TOO_MANY_KEYS ,"42000", "S1009", +ER_TOO_MANY_KEY_PARTS ,"42000", "S1009", +ER_TOO_LONG_KEY ,"42000", "S1009", +ER_KEY_COLUMN_DOES_NOT_EXITS ,"42000", "S1009", +ER_BLOB_USED_AS_KEY ,"42000", "S1009", +ER_TOO_BIG_FIELDLENGTH ,"42000", "S1009", +ER_WRONG_AUTO_KEY ,"42000", "S1009", +ER_FORCING_CLOSE ,"08S01", "", +ER_IPSOCK_ERROR ,"08S01", "", +ER_NO_SUCH_INDEX ,"42S12", "S1009", +ER_WRONG_FIELD_TERMINATORS ,"42000", "S1009", +ER_BLOBS_AND_NO_TERMINATED ,"42000", "S1009", +ER_CANT_REMOVE_ALL_FIELDS ,"42000", "", +ER_CANT_DROP_FIELD_OR_KEY ,"42000", "", +ER_BLOB_CANT_HAVE_DEFAULT ,"42000", "", +ER_WRONG_DB_NAME ,"42000", "", +ER_WRONG_TABLE_NAME ,"42000", "", +ER_TOO_BIG_SELECT ,"42000", "", +ER_UNKNOWN_PROCEDURE ,"42000", "", +ER_WRONG_PARAMCOUNT_TO_PROCEDURE ,"42000", "", +ER_UNKNOWN_TABLE ,"42S02", "", +ER_FIELD_SPECIFIED_TWICE ,"42000", "", +ER_UNSUPPORTED_EXTENSION ,"42000", "", +ER_TABLE_MUST_HAVE_COLUMNS ,"42000", "", +ER_UNKNOWN_CHARACTER_SET ,"42000", "", +ER_TOO_BIG_ROWSIZE ,"42000", "", +ER_WRONG_OUTER_JOIN ,"42000", "", +ER_NULL_COLUMN_IN_INDEX ,"42000", "", +ER_PASSWORD_ANONYMOUS_USER ,"42000", "", +ER_PASSWORD_NOT_ALLOWED ,"42000", "", +ER_PASSWORD_NO_MATCH ,"42000", "", +ER_WRONG_VALUE_COUNT_ON_ROW ,"21S01", "", +ER_INVALID_USE_OF_NULL ,"22004", "", +ER_REGEXP_ERROR ,"42000", "", +ER_MIX_OF_GROUP_FUNC_AND_FIELDS ,"42000", "", +ER_NONEXISTING_GRANT ,"42000", "", +ER_TABLEACCESS_DENIED_ERROR ,"42000", "", +ER_COLUMNACCESS_DENIED_ERROR ,"42000", "", +ER_ILLEGAL_GRANT_FOR_TABLE ,"42000", "", +ER_GRANT_WRONG_HOST_OR_USER ,"42000", "", +ER_NO_SUCH_TABLE ,"42S02", "", +ER_NONEXISTING_TABLE_GRANT ,"42000", "", +ER_NOT_ALLOWED_COMMAND ,"42000", "", +ER_SYNTAX_ERROR ,"42000", "", +ER_ABORTING_CONNECTION ,"08S01", "", +ER_NET_PACKET_TOO_LARGE ,"08S01", "", +ER_NET_READ_ERROR_FROM_PIPE ,"08S01", "", +ER_NET_FCNTL_ERROR ,"08S01", "", +ER_NET_PACKETS_OUT_OF_ORDER ,"08S01", "", +ER_NET_UNCOMPRESS_ERROR ,"08S01", "", +ER_NET_READ_ERROR ,"08S01", "", +ER_NET_READ_INTERRUPTED ,"08S01", "", +ER_NET_ERROR_ON_WRITE ,"08S01", "", +ER_NET_WRITE_INTERRUPTED ,"08S01", "", +ER_TOO_LONG_STRING ,"42000", "", +ER_TABLE_CANT_HANDLE_BLOB ,"42000", "", +ER_TABLE_CANT_HANDLE_AUTO_INCREMENT ,"42000", "", +ER_WRONG_COLUMN_NAME ,"42000", "", +ER_WRONG_KEY_COLUMN ,"42000", "", +ER_DUP_UNIQUE ,"23000", "", +ER_BLOB_KEY_WITHOUT_LENGTH ,"42000", "", +ER_PRIMARY_CANT_HAVE_NULL ,"42000", "", +ER_TOO_MANY_ROWS ,"42000", "", +ER_REQUIRES_PRIMARY_KEY ,"42000", "", +ER_CHECK_NO_SUCH_TABLE ,"42000", "", +ER_CHECK_NOT_IMPLEMENTED ,"42000", "", +ER_CANT_DO_THIS_DURING_AN_TRANSACTION ,"25000", "", +ER_NEW_ABORTING_CONNECTION ,"08S01", "", +ER_MASTER_NET_READ ,"08S01", "", +ER_MASTER_NET_WRITE ,"08S01", "", +ER_TOO_MANY_USER_CONNECTIONS ,"42000", "", +ER_READ_ONLY_TRANSACTION ,"25000", "", +ER_NO_PERMISSION_TO_CREATE_USER ,"42000", "", +ER_LOCK_DEADLOCK ,"40001", "", +ER_NO_REFERENCED_ROW ,"23000", "", +ER_ROW_IS_REFERENCED ,"23000", "", +ER_CONNECT_TO_MASTER ,"08S01", "", +ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT ,"21000", "", +ER_USER_LIMIT_REACHED ,"42000", "", +ER_SPECIFIC_ACCESS_DENIED_ERROR ,"42000", "", +ER_NO_DEFAULT ,"42000", "", +ER_WRONG_VALUE_FOR_VAR ,"42000", "", +ER_WRONG_TYPE_FOR_VAR ,"42000", "", +ER_CANT_USE_OPTION_HERE ,"42000", "", +ER_NOT_SUPPORTED_YET ,"42000", "", +ER_WRONG_FK_DEF ,"42000", "", +ER_OPERAND_COLUMNS ,"21000", "", +ER_SUBQUERY_NO_1_ROW ,"21000", "", +ER_ILLEGAL_REFERENCE ,"42S22", "", +ER_DERIVED_MUST_HAVE_ALIAS ,"42000", "", +ER_SELECT_REDUCED ,"01000", "", +ER_TABLENAME_NOT_ALLOWED_HERE ,"42000", "", +ER_NOT_SUPPORTED_AUTH_MODE ,"08004", "", +ER_SPATIAL_CANT_HAVE_NULL ,"42000", "", +ER_COLLATION_CHARSET_MISMATCH ,"42000", "", +ER_WARN_TOO_FEW_RECORDS ,"01000", "", +ER_WARN_TOO_MANY_RECORDS ,"01000", "", +ER_WARN_NULL_TO_NOTNULL ,"22004", "", +ER_WARN_DATA_OUT_OF_RANGE ,"22003", "", +WARN_DATA_TRUNCATED ,"01000", "", +ER_WRONG_NAME_FOR_INDEX ,"42000", "", +ER_WRONG_NAME_FOR_CATALOG ,"42000", "", +ER_UNKNOWN_STORAGE_ENGINE ,"42000", "", +ER_TRUNCATED_WRONG_VALUE ,"22007", "", +ER_SP_NO_RECURSIVE_CREATE ,"2F003", "", +ER_SP_ALREADY_EXISTS ,"42000", "", +ER_SP_DOES_NOT_EXIST ,"42000", "", +ER_SP_LILABEL_MISMATCH ,"42000", "", +ER_SP_LABEL_REDEFINE ,"42000", "", +ER_SP_LABEL_MISMATCH ,"42000", "", +ER_SP_UNINIT_VAR ,"01000", "", +ER_SP_BADSELECT ,"0A000", "", +ER_SP_BADRETURN ,"42000", "", +ER_SP_BADSTATEMENT ,"0A000", "", +ER_UPDATE_LOG_DEPRECATED_IGNORED ,"42000", "", +ER_UPDATE_LOG_DEPRECATED_TRANSLATED ,"42000", "", +ER_QUERY_INTERRUPTED ,"70100", "", +ER_SP_WRONG_NO_OF_ARGS ,"42000", "", +ER_SP_COND_MISMATCH ,"42000", "", +ER_SP_NORETURN ,"42000", "", +ER_SP_NORETURNEND ,"2F005", "", +ER_SP_BAD_CURSOR_QUERY ,"42000", "", +ER_SP_BAD_CURSOR_SELECT ,"42000", "", +ER_SP_CURSOR_MISMATCH ,"42000", "", +ER_SP_CURSOR_ALREADY_OPEN ,"24000", "", +ER_SP_CURSOR_NOT_OPEN ,"24000", "", +ER_SP_UNDECLARED_VAR ,"42000", "", +ER_SP_FETCH_NO_DATA ,"02000", "", +ER_SP_DUP_PARAM ,"42000", "", +ER_SP_DUP_VAR ,"42000", "", +ER_SP_DUP_COND ,"42000", "", +ER_SP_DUP_CURS ,"42000", "", +ER_SP_SUBSELECT_NYI ,"0A000", "", +ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG ,"0A000", "", +ER_SP_VARCOND_AFTER_CURSHNDLR ,"42000", "", +ER_SP_CURSOR_AFTER_HANDLER ,"42000", "", +ER_SP_CASE_NOT_FOUND ,"20000", "", +ER_DIVISION_BY_ZERO ,"22012", "", +ER_ILLEGAL_VALUE_FOR_TYPE ,"22007", "", +ER_PROCACCESS_DENIED_ERROR ,"42000", "", +ER_XAER_NOTA ,"XAE04", "", +ER_XAER_INVAL ,"XAE05", "", +ER_XAER_RMFAIL ,"XAE07", "", +ER_XAER_OUTSIDE ,"XAE09", "", +ER_XAER_RMERR ,"XAE03", "", +ER_XA_RBROLLBACK ,"XA100", "", +ER_NONEXISTING_PROC_GRANT ,"42000", "", +ER_DATA_TOO_LONG ,"22001", "", +ER_SP_BAD_SQLSTATE ,"42000", "", +ER_CANT_CREATE_USER_WITH_GRANT ,"42000", "", +ER_SP_DUP_HANDLER ,"42000", "", +ER_SP_NOT_VAR_ARG ,"42000", "", +ER_SP_NO_RETSET ,"0A000", "", +ER_CANT_CREATE_GEOMETRY_OBJECT ,"22003", "", +ER_TOO_BIG_SCALE ,"42000", "S1009", +ER_TOO_BIG_PRECISION ,"42000", "S1009", +ER_M_BIGGER_THAN_D ,"42000", "S1009", +ER_TOO_LONG_BODY ,"42000", "S1009", +ER_TOO_BIG_DISPLAYWIDTH ,"42000", "S1009", +ER_XAER_DUPID ,"XAE08", "", +ER_DATETIME_FUNCTION_OVERFLOW ,"22008", "", +ER_ROW_IS_REFERENCED_2 ,"23000", "", +ER_NO_REFERENCED_ROW_2 ,"23000", "", +ER_SP_BAD_VAR_SHADOW ,"42000", "", +ER_SP_WRONG_NAME ,"42000", "", +ER_SP_NO_AGGREGATE ,"42000", "", +ER_MAX_PREPARED_STMT_COUNT_REACHED ,"42000", "", +ER_NON_GROUPING_FIELD_USED ,"42000", "", diff --git a/code/meosdb/mysql50/sslopt-case.h b/code/meosdb/mysql50/sslopt-case.h new file mode 100644 index 0000000..ac7d775 --- /dev/null +++ b/code/meosdb/mysql50/sslopt-case.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifdef HAVE_OPENSSL + case OPT_SSL_KEY: + case OPT_SSL_CERT: + case OPT_SSL_CA: + case OPT_SSL_CAPATH: + case OPT_SSL_CIPHER: + /* + Enable use of SSL if we are using any ssl option + One can disable SSL later by using --skip-ssl or --ssl=0 + */ + opt_use_ssl= 1; + break; +#endif diff --git a/code/meosdb/mysql50/sslopt-longopts.h b/code/meosdb/mysql50/sslopt-longopts.h new file mode 100644 index 0000000..1bad6a5 --- /dev/null +++ b/code/meosdb/mysql50/sslopt-longopts.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifdef HAVE_OPENSSL + + {"ssl", OPT_SSL_SSL, + "Enable SSL for connection (automatically enabled with other flags). Disable with --skip-ssl.", + (gptr*) &opt_use_ssl, (gptr*) &opt_use_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"ssl-ca", OPT_SSL_CA, + "CA file in PEM format (check OpenSSL docs, implies --ssl).", + (gptr*) &opt_ssl_ca, (gptr*) &opt_ssl_ca, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-capath", OPT_SSL_CAPATH, + "CA directory (check OpenSSL docs, implies --ssl).", + (gptr*) &opt_ssl_capath, (gptr*) &opt_ssl_capath, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).", + (gptr*) &opt_ssl_cert, (gptr*) &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).", + (gptr*) &opt_ssl_cipher, (gptr*) &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).", + (gptr*) &opt_ssl_key, (gptr*) &opt_ssl_key, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, +#ifdef MYSQL_CLIENT + {"ssl-verify-server-cert", OPT_SSL_VERIFY_SERVER_CERT, + "Verify server's \"Common Name\" in its cert against hostname used when connecting. This option is disabled by default.", + (gptr*) &opt_ssl_verify_server_cert, (gptr*) &opt_ssl_verify_server_cert, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif +#endif /* HAVE_OPENSSL */ diff --git a/code/meosdb/mysql50/sslopt-vars.h b/code/meosdb/mysql50/sslopt-vars.h new file mode 100644 index 0000000..ca5d466 --- /dev/null +++ b/code/meosdb/mysql50/sslopt-vars.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifdef HAVE_OPENSSL +#ifdef SSL_VARS_NOT_STATIC +#define SSL_STATIC +#else +#define SSL_STATIC static +#endif +SSL_STATIC my_bool opt_use_ssl = 0; +SSL_STATIC char *opt_ssl_ca = 0; +SSL_STATIC char *opt_ssl_capath = 0; +SSL_STATIC char *opt_ssl_cert = 0; +SSL_STATIC char *opt_ssl_cipher = 0; +SSL_STATIC char *opt_ssl_key = 0; +#ifdef MYSQL_CLIENT +SSL_STATIC my_bool opt_ssl_verify_server_cert= 0; +#endif +#endif diff --git a/code/meosdb/mysql50/typelib.h b/code/meosdb/mysql50/typelib.h new file mode 100644 index 0000000..0a8b9b4 --- /dev/null +++ b/code/meosdb/mysql50/typelib.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + + +#ifndef _typelib_h +#define _typelib_h + +#include "my_alloc.h" + +typedef struct st_typelib { /* Different types saved here */ + unsigned int count; /* How many types */ + const char *name; /* Name of typelib */ + const char **type_names; + unsigned int *type_lengths; +} TYPELIB; + +extern int find_type(char *x,TYPELIB *typelib,unsigned int full_name); +extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); +extern const char *get_type(TYPELIB *typelib,unsigned int nr); +extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from); + +extern TYPELIB sql_protocol_typelib; + +#endif /* _typelib_h */ diff --git a/code/meosdb/mysql55/decimal.h b/code/meosdb/mysql55/decimal.h new file mode 100644 index 0000000..48d3e89 --- /dev/null +++ b/code/meosdb/mysql55/decimal.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _decimal_h +#define _decimal_h + +typedef enum +{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} + decimal_round_mode; +typedef int32 decimal_digit_t; + +typedef struct st_decimal_t { + int intg, frac, len; + my_bool sign; + decimal_digit_t *buf; +} decimal_t; + +int internal_str2dec(const char *from, decimal_t *to, char **end, + my_bool fixed); +int decimal2string(decimal_t *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler); +int decimal2ulonglong(decimal_t *from, ulonglong *to); +int ulonglong2decimal(ulonglong from, decimal_t *to); +int decimal2longlong(decimal_t *from, longlong *to); +int longlong2decimal(longlong from, decimal_t *to); +int decimal2double(decimal_t *from, double *to); +int double2decimal(double from, decimal_t *to); +int decimal_actual_fraction(decimal_t *from); +int decimal2bin(decimal_t *from, uchar *to, int precision, int scale); +int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale); + +int decimal_size(int precision, int scale); +int decimal_bin_size(int precision, int scale); +int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, + int param); + +int decimal_intg(decimal_t *from); +int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_cmp(decimal_t *from1, decimal_t *from2); +int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, + int scale_incr); +int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_round(decimal_t *from, decimal_t *to, int new_scale, + decimal_round_mode mode); +int decimal_is_zero(decimal_t *from); +void max_decimal(int precision, int frac, decimal_t *to); + +#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) +#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1) + +/* set a decimal_t to zero */ + +#define decimal_make_zero(dec) do { \ + (dec)->buf[0]=0; \ + (dec)->intg=1; \ + (dec)->frac=0; \ + (dec)->sign=0; \ + } while(0) + +/* + returns the length of the buffer to hold string representation + of the decimal (including decimal dot, possible sign and \0) +*/ + +#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \ + (dec)->frac + ((dec)->frac > 0) + 2) + +/* negate a decimal */ +#define decimal_neg(dec) do { (dec)->sign^=1; } while(0) + +/* + conventions: + + decimal_smth() == 0 -- everything's ok + decimal_smth() <= 1 -- result is usable, but precision loss is possible + decimal_smth() <= 2 -- result can be unusable, most significant digits + could've been lost + decimal_smth() > 2 -- no result was generated +*/ + +#define E_DEC_OK 0 +#define E_DEC_TRUNCATED 1 +#define E_DEC_OVERFLOW 2 +#define E_DEC_DIV_ZERO 4 +#define E_DEC_BAD_NUM 8 +#define E_DEC_OOM 16 + +#define E_DEC_ERROR 31 +#define E_DEC_FATAL_ERROR 30 + +#endif + diff --git a/code/meosdb/mysql55/errmsg.h b/code/meosdb/mysql55/errmsg.h new file mode 100644 index 0000000..fabd422 --- /dev/null +++ b/code/meosdb/mysql55/errmsg.h @@ -0,0 +1,108 @@ +#ifndef ERRMSG_INCLUDED +#define ERRMSG_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Error messages for MySQL clients */ +/* (Error messages for the daemon are in sql/share/errmsg.txt) */ + +#ifdef __cplusplus +extern "C" { +#endif +void init_client_errs(void); +void finish_client_errs(void); +extern const char *client_errors[]; /* Error messages */ +#ifdef __cplusplus +} +#endif + +#define CR_MIN_ERROR 2000 /* For easier client code */ +#define CR_MAX_ERROR 2999 +#if !defined(ER) +#define ER(X) client_errors[(X)-CR_MIN_ERROR] +#endif +#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */ + +/* Do not add error numbers before CR_ERROR_FIRST. */ +/* If necessary to add lower numbers, change CR_ERROR_FIRST accordingly. */ +#define CR_ERROR_FIRST 2000 /*Copy first error nr.*/ +#define CR_UNKNOWN_ERROR 2000 +#define CR_SOCKET_CREATE_ERROR 2001 +#define CR_CONNECTION_ERROR 2002 +#define CR_CONN_HOST_ERROR 2003 +#define CR_IPSOCK_ERROR 2004 +#define CR_UNKNOWN_HOST 2005 +#define CR_SERVER_GONE_ERROR 2006 +#define CR_VERSION_ERROR 2007 +#define CR_OUT_OF_MEMORY 2008 +#define CR_WRONG_HOST_INFO 2009 +#define CR_LOCALHOST_CONNECTION 2010 +#define CR_TCP_CONNECTION 2011 +#define CR_SERVER_HANDSHAKE_ERR 2012 +#define CR_SERVER_LOST 2013 +#define CR_COMMANDS_OUT_OF_SYNC 2014 +#define CR_NAMEDPIPE_CONNECTION 2015 +#define CR_NAMEDPIPEWAIT_ERROR 2016 +#define CR_NAMEDPIPEOPEN_ERROR 2017 +#define CR_NAMEDPIPESETSTATE_ERROR 2018 +#define CR_CANT_READ_CHARSET 2019 +#define CR_NET_PACKET_TOO_LARGE 2020 +#define CR_EMBEDDED_CONNECTION 2021 +#define CR_PROBE_SLAVE_STATUS 2022 +#define CR_PROBE_SLAVE_HOSTS 2023 +#define CR_PROBE_SLAVE_CONNECT 2024 +#define CR_PROBE_MASTER_CONNECT 2025 +#define CR_SSL_CONNECTION_ERROR 2026 +#define CR_MALFORMED_PACKET 2027 +#define CR_WRONG_LICENSE 2028 + +/* new 4.1 error codes */ +#define CR_NULL_POINTER 2029 +#define CR_NO_PREPARE_STMT 2030 +#define CR_PARAMS_NOT_BOUND 2031 +#define CR_DATA_TRUNCATED 2032 +#define CR_NO_PARAMETERS_EXISTS 2033 +#define CR_INVALID_PARAMETER_NO 2034 +#define CR_INVALID_BUFFER_USE 2035 +#define CR_UNSUPPORTED_PARAM_TYPE 2036 + +#define CR_SHARED_MEMORY_CONNECTION 2037 +#define CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR 2038 +#define CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR 2039 +#define CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR 2040 +#define CR_SHARED_MEMORY_CONNECT_MAP_ERROR 2041 +#define CR_SHARED_MEMORY_FILE_MAP_ERROR 2042 +#define CR_SHARED_MEMORY_MAP_ERROR 2043 +#define CR_SHARED_MEMORY_EVENT_ERROR 2044 +#define CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR 2045 +#define CR_SHARED_MEMORY_CONNECT_SET_ERROR 2046 +#define CR_CONN_UNKNOW_PROTOCOL 2047 +#define CR_INVALID_CONN_HANDLE 2048 +#define CR_SECURE_AUTH 2049 +#define CR_FETCH_CANCELED 2050 +#define CR_NO_DATA 2051 +#define CR_NO_STMT_METADATA 2052 +#define CR_NO_RESULT_SET 2053 +#define CR_NOT_IMPLEMENTED 2054 +#define CR_SERVER_LOST_EXTENDED 2055 +#define CR_STMT_CLOSED 2056 +#define CR_NEW_STMT_METADATA 2057 +#define CR_ALREADY_CONNECTED 2058 +#define CR_AUTH_PLUGIN_CANNOT_LOAD 2059 +#define CR_ERROR_LAST /*Copy last error nr:*/ 2059 +/* Add error numbers before CR_ERROR_LAST and change it accordingly. */ + +#endif /* ERRMSG_INCLUDED */ diff --git a/code/meosdb/mysql55/keycache.h b/code/meosdb/mysql55/keycache.h new file mode 100644 index 0000000..4ffd1fd --- /dev/null +++ b/code/meosdb/mysql55/keycache.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2003 MySQL AB, 2009 Sun Microsystems, Inc + + 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; version 2 of the License. + + 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 */ + +/* Key cache variable structures */ + +#ifndef _keycache_h +#define _keycache_h + +#include "my_sys.h" /* flush_type */ + +C_MODE_START + +/* declare structures that is used by st_key_cache */ + +struct st_block_link; +typedef struct st_block_link BLOCK_LINK; +struct st_keycache_page; +typedef struct st_keycache_page KEYCACHE_PAGE; +struct st_hash_link; +typedef struct st_hash_link HASH_LINK; + +/* info about requests in a waiting queue */ +typedef struct st_keycache_wqueue +{ + struct st_my_thread_var *last_thread; /* circular list of waiting threads */ +} KEYCACHE_WQUEUE; + +#define CHANGED_BLOCKS_HASH 128 /* must be power of 2 */ + +/* + The key cache structure + It also contains read-only statistics parameters. +*/ + +typedef struct st_key_cache +{ + my_bool key_cache_inited; + my_bool in_resize; /* true during resize operation */ + my_bool resize_in_flush; /* true during flush of resize operation */ + my_bool can_be_used; /* usage of cache for read/write is allowed */ + size_t key_cache_mem_size; /* specified size of the cache memory */ + uint key_cache_block_size; /* size of the page buffer of a cache block */ + ulong min_warm_blocks; /* min number of warm blocks; */ + ulong age_threshold; /* age threshold for hot blocks */ + ulonglong keycache_time; /* total number of block link operations */ + uint hash_entries; /* max number of entries in the hash table */ + int hash_links; /* max number of hash links */ + int hash_links_used; /* number of hash links currently used */ + int disk_blocks; /* max number of blocks in the cache */ + ulong blocks_used; /* maximum number of concurrently used blocks */ + ulong blocks_unused; /* number of currently unused blocks */ + ulong blocks_changed; /* number of currently dirty blocks */ + ulong warm_blocks; /* number of blocks in warm sub-chain */ + ulong cnt_for_resize_op; /* counter to block resize operation */ + long blocks_available; /* number of blocks available in the LRU chain */ + HASH_LINK **hash_root; /* arr. of entries into hash table buckets */ + HASH_LINK *hash_link_root; /* memory for hash table links */ + HASH_LINK *free_hash_list; /* list of free hash links */ + BLOCK_LINK *free_block_list; /* list of free blocks */ + BLOCK_LINK *block_root; /* memory for block links */ + uchar *block_mem; /* memory for block buffers */ + BLOCK_LINK *used_last; /* ptr to the last block of the LRU chain */ + BLOCK_LINK *used_ins; /* ptr to the insertion block in LRU chain */ + mysql_mutex_t cache_lock; /* to lock access to the cache structure */ + KEYCACHE_WQUEUE resize_queue; /* threads waiting during resize operation */ + /* + Waiting for a zero resize count. Using a queue for symmetry though + only one thread can wait here. + */ + KEYCACHE_WQUEUE waiting_for_resize_cnt; + KEYCACHE_WQUEUE waiting_for_hash_link; /* waiting for a free hash link */ + KEYCACHE_WQUEUE waiting_for_block; /* requests waiting for a free block */ + BLOCK_LINK *changed_blocks[CHANGED_BLOCKS_HASH]; /* hash for dirty file bl.*/ + BLOCK_LINK *file_blocks[CHANGED_BLOCKS_HASH]; /* hash for other file bl.*/ + + /* + The following variables are and variables used to hold parameters for + initializing the key cache. + */ + + ulonglong param_buff_size; /* size the memory allocated for the cache */ + ulonglong param_block_size; /* size of the blocks in the key cache */ + ulonglong param_division_limit; /* min. percentage of warm blocks */ + ulonglong param_age_threshold; /* determines when hot block is downgraded */ + + /* Statistics variables. These are reset in reset_key_cache_counters(). */ + ulong global_blocks_changed; /* number of currently dirty blocks */ + ulonglong global_cache_w_requests;/* number of write requests (write hits) */ + ulonglong global_cache_write; /* number of writes from cache to files */ + ulonglong global_cache_r_requests;/* number of read requests (read hits) */ + ulonglong global_cache_read; /* number of reads from files to cache */ + + int blocks; /* max number of blocks in the cache */ + my_bool in_init; /* Set to 1 in MySQL during init/resize */ +} KEY_CACHE; + +/* The default key cache */ +extern KEY_CACHE dflt_key_cache_var, *dflt_key_cache; + +extern int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold); +extern int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold); +extern void change_key_cache_param(KEY_CACHE *keycache, uint division_limit, + uint age_threshold); +extern uchar *key_cache_read(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length, + uint block_length,int return_buffer); +extern int key_cache_insert(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length); +extern int key_cache_write(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length, + uint block_length,int force_write); +extern int flush_key_blocks(KEY_CACHE *keycache, + int file, enum flush_type type); +extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup); + +/* Functions to handle multiple key caches */ +extern my_bool multi_keycache_init(void); +extern void multi_keycache_free(void); +extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length); +extern my_bool multi_key_cache_set(const uchar *key, uint length, + KEY_CACHE *key_cache); +extern void multi_key_cache_change(KEY_CACHE *old_data, + KEY_CACHE *new_data); +extern int reset_key_cache_counters(const char *name, + KEY_CACHE *key_cache); +C_MODE_END +#endif /* _keycache_h */ diff --git a/code/meosdb/mysql55/m_ctype.h b/code/meosdb/mysql55/m_ctype.h new file mode 100644 index 0000000..40f0627 --- /dev/null +++ b/code/meosdb/mysql55/m_ctype.h @@ -0,0 +1,660 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + A better inplementation of the UNIX ctype(3) library. +*/ + +#ifndef _m_ctype_h +#define _m_ctype_h + +#include +#include "my_global.h" /* uint16, uchar */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define MY_CS_NAME_SIZE 32 +#define MY_CS_CTYPE_TABLE_SIZE 257 +#define MY_CS_TO_LOWER_TABLE_SIZE 256 +#define MY_CS_TO_UPPER_TABLE_SIZE 256 +#define MY_CS_SORT_ORDER_TABLE_SIZE 256 +#define MY_CS_TO_UNI_TABLE_SIZE 256 + +#define CHARSET_DIR "charsets/" + +#define my_wc_t ulong + +#define MY_CS_REPLACEMENT_CHARACTER 0xFFFD + +/* + On i386 we store Unicode->CS conversion tables for + some character sets using Big-endian order, + to copy two bytes at onces. + This gives some performance improvement. +*/ +#ifdef __i386__ +#define MB2(x) (((x) >> 8) + (((x) & 0xFF) << 8)) +#define MY_PUT_MB2(s, code) { *((uint16*)(s))= (code); } +#else +#define MB2(x) (x) +#define MY_PUT_MB2(s, code) { (s)[0]= code >> 8; (s)[1]= code & 0xFF; } +#endif + + + +typedef struct unicase_info_st +{ + uint32 toupper; + uint32 tolower; + uint32 sort; +} MY_UNICASE_INFO; + + +extern MY_UNICASE_INFO *my_unicase_default[256]; +extern MY_UNICASE_INFO *my_unicase_turkish[256]; + +typedef struct uni_ctype_st +{ + uchar pctype; + uchar *ctype; +} MY_UNI_CTYPE; + +extern MY_UNI_CTYPE my_uni_ctype[256]; + +/* wm_wc and wc_mb return codes */ +#define MY_CS_ILSEQ 0 /* Wrong by sequence: wb_wc */ +#define MY_CS_ILUNI 0 /* Cannot encode Unicode to charset: wc_mb */ +#define MY_CS_TOOSMALL -101 /* Need at least one byte: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL2 -102 /* Need at least two bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL3 -103 /* Need at least three bytes: wc_mb and mb_wc */ +/* These following three are currently not really used */ +#define MY_CS_TOOSMALL4 -104 /* Need at least 4 bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL5 -105 /* Need at least 5 bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL6 -106 /* Need at least 6 bytes: wc_mb and mb_wc */ +/* A helper macros for "need at least n bytes" */ +#define MY_CS_TOOSMALLN(n) (-100-(n)) + +#define MY_SEQ_INTTAIL 1 +#define MY_SEQ_SPACES 2 + + /* My charsets_list flags */ +#define MY_CS_COMPILED 1 /* compiled-in sets */ +#define MY_CS_CONFIG 2 /* sets that have a *.conf file */ +#define MY_CS_INDEX 4 /* sets listed in the Index file */ +#define MY_CS_LOADED 8 /* sets that are currently loaded */ +#define MY_CS_BINSORT 16 /* if binary sort order */ +#define MY_CS_PRIMARY 32 /* if primary collation */ +#define MY_CS_STRNXFRM 64 /* if strnxfrm is used for sort */ +#define MY_CS_UNICODE 128 /* is a charset is BMP Unicode */ +#define MY_CS_READY 256 /* if a charset is initialized */ +#define MY_CS_AVAILABLE 512 /* If either compiled-in or loaded*/ +#define MY_CS_CSSORT 1024 /* if case sensitive sort order */ +#define MY_CS_HIDDEN 2048 /* don't display in SHOW */ +#define MY_CS_PUREASCII 4096 /* if a charset is pure ascii */ +#define MY_CS_NONASCII 8192 /* if not ASCII-compatible */ +#define MY_CS_UNICODE_SUPPLEMENT 16384 /* Non-BMP Unicode characters */ +#define MY_CHARSET_UNDEFINED 0 + +/* Character repertoire flags */ +#define MY_REPERTOIRE_ASCII 1 /* Pure ASCII U+0000..U+007F */ +#define MY_REPERTOIRE_EXTENDED 2 /* Extended characters: U+0080..U+FFFF */ +#define MY_REPERTOIRE_UNICODE30 3 /* ASCII | EXTENDED: U+0000..U+FFFF */ + +typedef struct my_uni_idx_st +{ + uint16 from; + uint16 to; + uchar *tab; +} MY_UNI_IDX; + +typedef struct +{ + uint beg; + uint end; + uint mb_len; +} my_match_t; + +enum my_lex_states +{ + MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT, + MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, + MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER, + MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, + MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, + MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, + MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON, + MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP, + MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR, + MY_LEX_IDENT_OR_KEYWORD, + MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_NCHAR, + MY_LEX_STRING_OR_DELIMITER +}; + +struct charset_info_st; + + +/* See strings/CHARSET_INFO.txt for information about this structure */ +typedef struct my_collation_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t)); + /* Collation routines */ + int (*strnncoll)(struct charset_info_st *, + const uchar *, size_t, const uchar *, size_t, my_bool); + int (*strnncollsp)(struct charset_info_st *, + const uchar *, size_t, const uchar *, size_t, + my_bool diff_if_only_endspace_difference); + size_t (*strnxfrm)(struct charset_info_st *, + uchar *, size_t, const uchar *, size_t); + size_t (*strnxfrmlen)(struct charset_info_st *, size_t); + my_bool (*like_range)(struct charset_info_st *, + const char *s, size_t s_length, + pchar w_prefix, pchar w_one, pchar w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_len, size_t *max_len); + int (*wildcmp)(struct charset_info_st *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape,int w_one, int w_many); + + int (*strcasecmp)(struct charset_info_st *, const char *, const char *); + + uint (*instr)(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + + /* Hash calculation */ + void (*hash_sort)(struct charset_info_st *cs, const uchar *key, size_t len, + ulong *nr1, ulong *nr2); + my_bool (*propagate)(struct charset_info_st *cs, const uchar *str, size_t len); +} MY_COLLATION_HANDLER; + +extern MY_COLLATION_HANDLER my_collation_mb_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler; +extern MY_COLLATION_HANDLER my_collation_ucs2_uca_handler; + +/* Some typedef to make it easy for C++ to make function pointers */ +typedef int (*my_charset_conv_mb_wc)(struct charset_info_st *, my_wc_t *, + const uchar *, const uchar *); +typedef int (*my_charset_conv_wc_mb)(struct charset_info_st *, my_wc_t, + uchar *, uchar *); +typedef size_t (*my_charset_conv_case)(struct charset_info_st *, + char *, size_t, char *, size_t); + + +/* See strings/CHARSET_INFO.txt about information on this structure */ +typedef struct my_charset_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t)); + /* Multibyte routines */ + uint (*ismbchar)(struct charset_info_st *, const char *, const char *); + uint (*mbcharlen)(struct charset_info_st *, uint c); + size_t (*numchars)(struct charset_info_st *, const char *b, const char *e); + size_t (*charpos)(struct charset_info_st *, const char *b, const char *e, + size_t pos); + size_t (*well_formed_len)(struct charset_info_st *, + const char *b,const char *e, + size_t nchars, int *error); + size_t (*lengthsp)(struct charset_info_st *, const char *ptr, size_t length); + size_t (*numcells)(struct charset_info_st *, const char *b, const char *e); + + /* Unicode conversion */ + my_charset_conv_mb_wc mb_wc; + my_charset_conv_wc_mb wc_mb; + + /* CTYPE scanner */ + int (*ctype)(struct charset_info_st *cs, int *ctype, + const uchar *s, const uchar *e); + + /* Functions for case and sort conversion */ + size_t (*caseup_str)(struct charset_info_st *, char *); + size_t (*casedn_str)(struct charset_info_st *, char *); + + my_charset_conv_case caseup; + my_charset_conv_case casedn; + + /* Charset dependant snprintf() */ + size_t (*snprintf)(struct charset_info_st *, char *to, size_t n, + const char *fmt, + ...) ATTRIBUTE_FORMAT_FPTR(printf, 4, 5); + size_t (*long10_to_str)(struct charset_info_st *, char *to, size_t n, + int radix, long int val); + size_t (*longlong10_to_str)(struct charset_info_st *, char *to, size_t n, + int radix, longlong val); + + void (*fill)(struct charset_info_st *, char *to, size_t len, int fill); + + /* String-to-number conversion routines */ + long (*strntol)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + ulong (*strntoul)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + longlong (*strntoll)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + ulonglong (*strntoull)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + double (*strntod)(struct charset_info_st *, char *s, size_t l, char **e, + int *err); + longlong (*strtoll10)(struct charset_info_st *cs, + const char *nptr, char **endptr, int *error); + ulonglong (*strntoull10rnd)(struct charset_info_st *cs, + const char *str, size_t length, + int unsigned_fl, + char **endptr, int *error); + size_t (*scan)(struct charset_info_st *, const char *b, const char *e, + int sq); +} MY_CHARSET_HANDLER; + +extern MY_CHARSET_HANDLER my_charset_8bit_handler; +extern MY_CHARSET_HANDLER my_charset_ucs2_handler; + + +/* + We define this CHARSET_INFO_DEFINED here to prevent a repeat of the + typedef in hash.c, which will cause a compiler error. +*/ +#define CHARSET_INFO_DEFINED + +/* See strings/CHARSET_INFO.txt about information on this structure */ +typedef struct charset_info_st +{ + uint number; + uint primary_number; + uint binary_number; + uint state; + const char *csname; + const char *name; + const char *comment; + const char *tailoring; + uchar *ctype; + uchar *to_lower; + uchar *to_upper; + uchar *sort_order; + uint16 *contractions; + uint16 **sort_order_big; + uint16 *tab_to_uni; + MY_UNI_IDX *tab_from_uni; + MY_UNICASE_INFO **caseinfo; + uchar *state_map; + uchar *ident_map; + uint strxfrm_multiply; + uchar caseup_multiply; + uchar casedn_multiply; + uint mbminlen; + uint mbmaxlen; + uint16 min_sort_char; + uint16 max_sort_char; /* For LIKE optimization */ + uchar pad_char; + my_bool escape_with_backslash_is_dangerous; + + MY_CHARSET_HANDLER *cset; + MY_COLLATION_HANDLER *coll; + +} CHARSET_INFO; +#define ILLEGAL_CHARSET_INFO_NUMBER (~0U) + + +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_bin; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_latin1; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_filename; + +extern CHARSET_INFO my_charset_big5_chinese_ci; +extern CHARSET_INFO my_charset_big5_bin; +extern CHARSET_INFO my_charset_cp932_japanese_ci; +extern CHARSET_INFO my_charset_cp932_bin; +extern CHARSET_INFO my_charset_cp1250_czech_ci; +extern CHARSET_INFO my_charset_eucjpms_japanese_ci; +extern CHARSET_INFO my_charset_eucjpms_bin; +extern CHARSET_INFO my_charset_euckr_korean_ci; +extern CHARSET_INFO my_charset_euckr_bin; +extern CHARSET_INFO my_charset_gb2312_chinese_ci; +extern CHARSET_INFO my_charset_gb2312_bin; +extern CHARSET_INFO my_charset_gbk_chinese_ci; +extern CHARSET_INFO my_charset_gbk_bin; +extern CHARSET_INFO my_charset_latin1_german2_ci; +extern CHARSET_INFO my_charset_latin1_bin; +extern CHARSET_INFO my_charset_latin2_czech_ci; +extern CHARSET_INFO my_charset_sjis_japanese_ci; +extern CHARSET_INFO my_charset_sjis_bin; +extern CHARSET_INFO my_charset_tis620_thai_ci; +extern CHARSET_INFO my_charset_tis620_bin; +extern CHARSET_INFO my_charset_ucs2_general_ci; +extern CHARSET_INFO my_charset_ucs2_bin; +extern CHARSET_INFO my_charset_ucs2_unicode_ci; +extern CHARSET_INFO my_charset_ujis_japanese_ci; +extern CHARSET_INFO my_charset_ujis_bin; +extern CHARSET_INFO my_charset_utf16_bin; +extern CHARSET_INFO my_charset_utf16_general_ci; +extern CHARSET_INFO my_charset_utf16_unicode_ci; +extern CHARSET_INFO my_charset_utf32_bin; +extern CHARSET_INFO my_charset_utf32_general_ci; +extern CHARSET_INFO my_charset_utf32_unicode_ci; + +extern CHARSET_INFO my_charset_utf8_general_ci; +extern CHARSET_INFO my_charset_utf8_unicode_ci; +extern CHARSET_INFO my_charset_utf8_bin; +extern CHARSET_INFO my_charset_utf8mb4_bin; +extern CHARSET_INFO my_charset_utf8mb4_general_ci; +extern CHARSET_INFO my_charset_utf8mb4_unicode_ci; +#define MY_UTF8MB3 "utf8" +#define MY_UTF8MB4 "utf8mb4" + + +/* Helper functions to handle contraction */ +static inline my_bool +my_cs_have_contractions(CHARSET_INFO *cs) +{ + return cs->contractions != NULL; +} + +static inline my_bool +my_cs_can_be_contraction_head(CHARSET_INFO *cs, my_wc_t wc) +{ + return ((const char *)cs->contractions)[0x40*0x40 + (wc & 0xFF)]; +} + +static inline my_bool +my_cs_can_be_contraction_tail(CHARSET_INFO *cs, my_wc_t wc) +{ + return ((const char *)cs->contractions)[0x40*0x40 + (wc & 0xFF)]; +} + +static inline uint16* +my_cs_contraction2_weight(CHARSET_INFO *cs, my_wc_t wc1, my_wc_t wc2) +{ + return &cs->contractions[(wc1 - 0x40) * 0x40 + wc2 - 0x40]; +} + + +/* declarations for simple charsets */ +extern size_t my_strnxfrm_simple(CHARSET_INFO *, uchar *, size_t, + const uchar *, size_t); +size_t my_strnxfrmlen_simple(CHARSET_INFO *, size_t); +extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, size_t, + const uchar *, size_t, my_bool); + +extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, size_t, + const uchar *, size_t, + my_bool diff_if_only_endspace_difference); + +extern void my_hash_sort_simple(CHARSET_INFO *cs, + const uchar *key, size_t len, + ulong *nr1, ulong *nr2); + +extern size_t my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, size_t length); + +extern uint my_instr_simple(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + + +/* Functions for 8bit */ +extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *); +extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *); +extern size_t my_caseup_8bit(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_8bit(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); + +extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *); + +int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e); +int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); + +int my_mb_ctype_8bit(CHARSET_INFO *,int *, const uchar *,const uchar *); +int my_mb_ctype_mb(CHARSET_INFO *,int *, const uchar *,const uchar *); + +size_t my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq); + +size_t my_snprintf_8bit(struct charset_info_st *, char *to, size_t n, + const char *fmt, ...) + ATTRIBUTE_FORMAT(printf, 4, 5); + +long my_strntol_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +double my_strntod_8bit(CHARSET_INFO *, char *s, size_t l,char **e, + int *err); +size_t my_long10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, + long int val); +size_t my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, + longlong val); + +longlong my_strtoll10_8bit(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); +longlong my_strtoll10_ucs2(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); + +ulonglong my_strntoull10rnd_8bit(CHARSET_INFO *cs, + const char *str, size_t length, int + unsigned_fl, char **endptr, int *error); +ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs, + const char *str, size_t length, + int unsigned_fl, char **endptr, int *error); + +void my_fill_8bit(CHARSET_INFO *cs, char* to, size_t l, int fill); + +/* For 8-bit character set */ +my_bool my_like_range_simple(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +/* For ASCII-based multi-byte character sets with mbminlen=1 */ +my_bool my_like_range_mb(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +/* For other character sets, with arbitrary mbminlen and mbmaxlen numbers */ +my_bool my_like_range_generic(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +int my_wildcmp_8bit(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +int my_wildcmp_bin(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +size_t my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); +size_t my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e); +size_t my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, size_t pos); +size_t my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e, + size_t pos, int *error); +uint my_mbcharlen_8bit(CHARSET_INFO *, uint c); + + +/* Functions for multibyte charsets */ +extern size_t my_caseup_str_mb(CHARSET_INFO *, char *); +extern size_t my_casedn_str_mb(CHARSET_INFO *, char *); +extern size_t my_caseup_mb(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_mb(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_caseup_mb_varlen(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_mb_varlen(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_caseup_ujis(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_ujis(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *); + +int my_wildcmp_mb(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); +size_t my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); +size_t my_numcells_mb(CHARSET_INFO *, const char *b, const char *e); +size_t my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, size_t pos); +size_t my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e, + size_t pos, int *error); +uint my_instr_mb(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + +int my_strnncoll_mb_bin(CHARSET_INFO * cs, + const uchar *s, size_t slen, + const uchar *t, size_t tlen, + my_bool t_is_prefix); + +int my_strnncollsp_mb_bin(CHARSET_INFO *cs, + const uchar *a, size_t a_length, + const uchar *b, size_t b_length, + my_bool diff_if_only_endspace_difference); + +int my_wildcmp_mb_bin(CHARSET_INFO *cs, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +int my_strcasecmp_mb_bin(CHARSET_INFO * cs __attribute__((unused)), + const char *s, const char *t); + +void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), + const uchar *key, size_t len,ulong *nr1, ulong *nr2); + +size_t my_strnxfrm_unicode(CHARSET_INFO *, + uchar *dst, size_t dstlen, + const uchar *src, size_t srclen); + +size_t my_strnxfrm_unicode_full_bin(CHARSET_INFO *, + uchar *dst, size_t dstlen, + const uchar *src, size_t srclen); +size_t my_strnxfrmlen_unicode_full_bin(CHARSET_INFO *, size_t); + +int my_wildcmp_unicode(CHARSET_INFO *cs, + const char *str, const char *str_end, + const char *wildstr, const char *wildend, + int escape, int w_one, int w_many, + MY_UNICASE_INFO **weights); + +extern my_bool my_parse_charset_xml(const char *bug, size_t len, + int (*add)(CHARSET_INFO *cs)); +extern char *my_strchr(CHARSET_INFO *cs, const char *str, const char *end, + pchar c); +extern size_t my_strcspn(CHARSET_INFO *cs, const char *str, const char *end, + const char *accept); + +my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, size_t len); +my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, size_t len); + + +uint my_string_repertoire(CHARSET_INFO *cs, const char *str, ulong len); +my_bool my_charset_is_ascii_based(CHARSET_INFO *cs); +my_bool my_charset_is_8bit_pure_ascii(CHARSET_INFO *cs); +uint my_charset_repertoire(CHARSET_INFO *cs); + +my_bool my_charset_is_ascii_compatible(CHARSET_INFO *cs); + +extern size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n, + const char* fmt, va_list ap); + +#define _MY_U 01 /* Upper case */ +#define _MY_L 02 /* Lower case */ +#define _MY_NMR 04 /* Numeral (digit) */ +#define _MY_SPC 010 /* Spacing character */ +#define _MY_PNT 020 /* Punctuation */ +#define _MY_CTR 040 /* Control character */ +#define _MY_B 0100 /* Blank */ +#define _MY_X 0200 /* heXadecimal digit */ + + +#define my_isascii(c) (!((c) & ~0177)) +#define my_toascii(c) ((c) & 0177) +#define my_tocntrl(c) ((c) & 31) +#define my_toprint(c) ((c) | 64) +#define my_toupper(s,c) (char) ((s)->to_upper[(uchar) (c)]) +#define my_tolower(s,c) (char) ((s)->to_lower[(uchar) (c)]) +#define my_isalpha(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_U | _MY_L)) +#define my_isupper(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_U) +#define my_islower(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_L) +#define my_isdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_NMR) +#define my_isxdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_X) +#define my_isalnum(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_U | _MY_L | _MY_NMR)) +#define my_isspace(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_SPC) +#define my_ispunct(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_PNT) +#define my_isprint(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR | _MY_B)) +#define my_isgraph(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR)) +#define my_iscntrl(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_CTR) + +/* Some macros that should be cleaned up a little */ +#define my_isvar(s,c) (my_isalnum(s,c) || (c) == '_') +#define my_isvar_start(s,c) (my_isalpha(s,c) || (c) == '_') + +#define my_binary_compare(s) ((s)->state & MY_CS_BINSORT) +#define use_strnxfrm(s) ((s)->state & MY_CS_STRNXFRM) +#define my_strnxfrm(s, a, b, c, d) ((s)->coll->strnxfrm((s), (a), (b), (c), (d))) +#define my_strnncoll(s, a, b, c, d) ((s)->coll->strnncoll((s), (a), (b), (c), (d), 0)) +#define my_like_range(s, a, b, c, d, e, f, g, h, i, j) \ + ((s)->coll->like_range((s), (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))) +#define my_wildcmp(cs,s,se,w,we,e,o,m) ((cs)->coll->wildcmp((cs),(s),(se),(w),(we),(e),(o),(m))) +#define my_strcasecmp(s, a, b) ((s)->coll->strcasecmp((s), (a), (b))) +#define my_charpos(cs, b, e, num) (cs)->cset->charpos((cs), (const char*) (b), (const char *)(e), (num)) + + +#define use_mb(s) ((s)->cset->ismbchar != NULL) +#define my_ismbchar(s, a, b) ((s)->cset->ismbchar((s), (a), (b))) +#ifdef USE_MB +#define my_mbcharlen(s, a) ((s)->cset->mbcharlen((s),(a))) +#else +#define my_mbcharlen(s, a) 1 +#endif + +#define my_caseup_str(s, a) ((s)->cset->caseup_str((s), (a))) +#define my_casedn_str(s, a) ((s)->cset->casedn_str((s), (a))) +#define my_strntol(s, a, b, c, d, e) ((s)->cset->strntol((s),(a),(b),(c),(d),(e))) +#define my_strntoul(s, a, b, c, d, e) ((s)->cset->strntoul((s),(a),(b),(c),(d),(e))) +#define my_strntoll(s, a, b, c, d, e) ((s)->cset->strntoll((s),(a),(b),(c),(d),(e))) +#define my_strntoull(s, a, b, c,d, e) ((s)->cset->strntoull((s),(a),(b),(c),(d),(e))) +#define my_strntod(s, a, b, c, d) ((s)->cset->strntod((s),(a),(b),(c),(d))) + + +/* XXX: still need to take care of this one */ +#ifdef MY_CHARSET_TIS620 +#error The TIS620 charset is broken at the moment. Tell tim to fix it. +#define USE_TIS620 +#include "t_ctype.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _m_ctype_h */ diff --git a/code/meosdb/mysql55/m_string.h b/code/meosdb/mysql55/m_string.h new file mode 100644 index 0000000..2cfc0c5 --- /dev/null +++ b/code/meosdb/mysql55/m_string.h @@ -0,0 +1,295 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* There may be prolems include all of theese. Try to test in + configure with ones are needed? */ + +/* This is needed for the definitions of strchr... on solaris */ + +#ifndef _m_string_h +#define _m_string_h + +#include "my_global.h" /* HAVE_* */ + +#ifndef __USE_GNU +#define __USE_GNU /* We want to use stpcpy */ +#endif +#if defined(HAVE_STRINGS_H) +#include +#endif +#if defined(HAVE_STRING_H) +#include +#endif + +/* need by my_vsnprintf */ +#include + +/* This is needed for the definitions of bzero... on solaris */ +#if defined(HAVE_STRINGS_H) +#include +#endif + +/* This is needed for the definitions of memcpy... on solaris */ +#if defined(HAVE_MEMORY_H) && !defined(__cplusplus) +#include +#endif + +#if !defined(HAVE_MEMCPY) && !defined(HAVE_MEMMOVE) +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define memset(A,C,B) bfill((A),(B),(C)) +# define memmove(d, s, n) bmove ((d), (s), (n)) +#elif defined(HAVE_MEMMOVE) +# define bmove(d, s, n) memmove((d), (s), (n)) +#endif + +/* Unixware 7 */ +#if !defined(HAVE_BFILL) +# define bfill(A,B,C) memset((A),(C),(B)) +#endif + +#if !defined(bzero) && !defined(HAVE_BZERO) +# define bzero(A,B) memset((A),0,(B)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + my_str_malloc() and my_str_free() are assigned to implementations in + strings/alloc.c, but can be overridden in the calling program. + */ +extern void *(*my_str_malloc)(size_t); +extern void (*my_str_free)(void *); + +#if defined(HAVE_STPCPY) && MY_GNUC_PREREQ(3, 4) && !defined(__INTEL_COMPILER) +#define strmov(A,B) __builtin_stpcpy((A),(B)) +#elif defined(HAVE_STPCPY) +#define strmov(A,B) stpcpy((A),(B)) +#ifndef stpcpy +extern char *stpcpy(char *, const char *); /* For AIX with gcc 2.95.3 */ +#endif +#endif + +/* Declared in int2str() */ +extern char _dig_vec_upper[]; +extern char _dig_vec_lower[]; + +#ifndef strmov +#define strmov_overlapp(A,B) strmov(A,B) +#define strmake_overlapp(A,B,C) strmake(A,B,C) +#endif + + /* Prototypes for string functions */ + +extern void bmove_upp(uchar *dst,const uchar *src,size_t len); +extern void bchange(uchar *dst,size_t old_len,const uchar *src, + size_t new_len,size_t tot_len); +extern void strappend(char *s,size_t len,pchar fill); +extern char *strend(const char *s); +extern char *strcend(const char *, pchar); +extern char *strfill(char * s,size_t len,pchar fill); +extern char *strmake(char *dst,const char *src,size_t length); + +#ifndef strmov +extern char *strmov(char *dst,const char *src); +#else +extern char *strmov_overlapp(char *dst,const char *src); +#endif +extern char *strnmov(char *dst, const char *src, size_t n); +extern char *strcont(const char *src, const char *set); +extern char *strxmov(char *dst, const char *src, ...); +extern char *strxnmov(char *dst, size_t len, const char *src, ...); + +/* Prototypes of normal stringfunctions (with may ours) */ +#ifndef HAVE_STRNLEN +extern size_t strnlen(const char *s, size_t n); +#endif + +extern int is_prefix(const char *, const char *); + +/* Conversion routines */ +typedef enum { + MY_GCVT_ARG_FLOAT, + MY_GCVT_ARG_DOUBLE +} my_gcvt_arg_type; + +double my_strtod(const char *str, char **end, int *error); +double my_atof(const char *nptr); +size_t my_fcvt(double x, int precision, char *to, my_bool *error); +size_t my_gcvt(double x, my_gcvt_arg_type type, int width, char *to, + my_bool *error); + +#define NOT_FIXED_DEC 31 + +/* + The longest string my_fcvt can return is 311 + "precision" bytes. + Here we assume that we never cal my_fcvt() with precision >= NOT_FIXED_DEC + (+ 1 byte for the terminating '\0'). +*/ +#define FLOATING_POINT_BUFFER (311 + NOT_FIXED_DEC) + +/* + We want to use the 'e' format in some cases even if we have enough space + for the 'f' one just to mimic sprintf("%.15g") behavior for large integers, + and to improve it for numbers < 10^(-4). + That is, for |x| < 1 we require |x| >= 10^(-15), and for |x| > 1 we require + it to be integer and be <= 10^DBL_DIG for the 'f' format to be used. + We don't lose precision, but make cases like "1e200" or "0.00001" look nicer. +*/ +#define MAX_DECPT_FOR_F_FORMAT DBL_DIG + +/* + The maximum possible field width for my_gcvt() conversion. + (DBL_DIG + 2) significant digits + sign + "." + ("e-NNN" or + MAX_DECPT_FOR_F_FORMAT zeros for cases when |x|<1 and the 'f' format is used). +*/ +#define MY_GCVT_MAX_FIELD_WIDTH (DBL_DIG + 4 + max(5, MAX_DECPT_FOR_F_FORMAT)) \ + +extern char *llstr(longlong value,char *buff); +extern char *ullstr(longlong value,char *buff); +#ifndef HAVE_STRTOUL +extern long strtol(const char *str, char **ptr, int base); +extern ulong strtoul(const char *str, char **ptr, int base); +#endif + +extern char *int2str(long val, char *dst, int radix, int upcase); +extern char *int10_to_str(long val,char *dst,int radix); +extern char *str2int(const char *src,int radix,long lower,long upper, + long *val); +longlong my_strtoll10(const char *nptr, char **endptr, int *error); +#if SIZEOF_LONG == SIZEOF_LONG_LONG +#define ll2str(A,B,C,D) int2str((A),(B),(C),(D)) +#define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C)) +#undef strtoll +#define strtoll(A,B,C) strtol((A),(B),(C)) +#define strtoull(A,B,C) strtoul((A),(B),(C)) +#ifndef HAVE_STRTOULL +#define HAVE_STRTOULL +#endif +#ifndef HAVE_STRTOLL +#define HAVE_STRTOLL +#endif +#else +#ifdef HAVE_LONG_LONG +extern char *ll2str(longlong val,char *dst,int radix, int upcase); +extern char *longlong10_to_str(longlong val,char *dst,int radix); +#if (!defined(HAVE_STRTOULL) || defined(NO_STRTOLL_PROTO)) +extern longlong strtoll(const char *str, char **ptr, int base); +extern ulonglong strtoull(const char *str, char **ptr, int base); +#endif +#endif +#endif +#define longlong2str(A,B,C) ll2str((A),(B),(C),1) + +#if defined(__cplusplus) +} +#endif + +/* + LEX_STRING -- a pair of a C-string and its length. + (it's part of the plugin API as a MYSQL_LEX_STRING) +*/ + +#include +typedef struct st_mysql_lex_string LEX_STRING; + +#define STRING_WITH_LEN(X) (X), ((size_t) (sizeof(X) - 1)) +#define USTRING_WITH_LEN(X) ((uchar*) X), ((size_t) (sizeof(X) - 1)) +#define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1)) + +struct st_mysql_const_lex_string +{ + const char *str; + size_t length; +}; +typedef struct st_mysql_const_lex_string LEX_CSTRING; + +/* SPACE_INT is a word that contains only spaces */ +#if SIZEOF_INT == 4 +#define SPACE_INT 0x20202020 +#elif SIZEOF_INT == 8 +#define SPACE_INT 0x2020202020202020 +#else +#error define the appropriate constant for a word full of spaces +#endif + +/** + Skip trailing space. + + On most systems reading memory in larger chunks (ideally equal to the size of + the chinks that the machine physically reads from memory) causes fewer memory + access loops and hence increased performance. + This is why the 'int' type is used : it's closest to that (according to how + it's defined in C). + So when we determine the amount of whitespace at the end of a string we do + the following : + 1. We divide the string into 3 zones : + a) from the start of the string (__start) to the first multiple + of sizeof(int) (__start_words) + b) from the end of the string (__end) to the last multiple of sizeof(int) + (__end_words) + c) a zone that is aligned to sizeof(int) and can be safely accessed + through an int * + 2. We start comparing backwards from (c) char-by-char. If all we find is + space then we continue + 3. If there are elements in zone (b) we compare them as unsigned ints to a + int mask (SPACE_INT) consisting of all spaces + 4. Finally we compare the remaining part (a) of the string char by char. + This covers for the last non-space unsigned int from 3. (if any) + + This algorithm works well for relatively larger strings, but it will slow + the things down for smaller strings (because of the additional calculations + and checks compared to the naive method). Thus the barrier of length 20 + is added. + + @param ptr pointer to the input string + @param len the length of the string + @return the last non-space character +*/ + +static inline const uchar *skip_trailing_space(const uchar *ptr,size_t len) +{ + const uchar *end= ptr + len; + + if (len > 20) + { + const uchar *end_words= (const uchar *)(intptr) + (((ulonglong)(intptr)end) / SIZEOF_INT * SIZEOF_INT); + const uchar *start_words= (const uchar *)(intptr) + ((((ulonglong)(intptr)ptr) + SIZEOF_INT - 1) / SIZEOF_INT * SIZEOF_INT); + + DBUG_ASSERT(((ulonglong)(intptr)ptr) >= SIZEOF_INT); + if (end_words > ptr) + { + while (end > end_words && end[-1] == 0x20) + end--; + if (end[-1] == 0x20 && start_words < end_words) + while (end > start_words && ((unsigned *)end)[-1] == SPACE_INT) + end -= SIZEOF_INT; + } + } + while (end > ptr && end[-1] == 0x20) + end--; + return (end); +} + +static inline void lex_string_set(LEX_STRING *lex_str, const char *c_str) +{ + lex_str->str= (char *) c_str; + lex_str->length= strlen(c_str); +} + +#endif diff --git a/code/meosdb/mysql55/my_alloc.h b/code/meosdb/mysql55/my_alloc.h new file mode 100644 index 0000000..866a5cf --- /dev/null +++ b/code/meosdb/mysql55/my_alloc.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + Data structures for mysys/my_alloc.c (root memory allocator) +*/ + +#ifndef _my_alloc_h +#define _my_alloc_h + +#define ALLOC_MAX_BLOCK_TO_DROP 4096 +#define ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP 10 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_used_mem +{ /* struct for once_alloc (block) */ + struct st_used_mem *next; /* Next block in use */ + unsigned int left; /* memory left in block */ + unsigned int size; /* size of block */ +} USED_MEM; + + +typedef struct st_mem_root +{ + USED_MEM *free; /* blocks with free memory in it */ + USED_MEM *used; /* blocks almost without free memory */ + USED_MEM *pre_alloc; /* preallocated block */ + /* if block have less memory it will be put in 'used' list */ + size_t min_malloc; + size_t block_size; /* initial block size */ + unsigned int block_num; /* allocated blocks counter */ + /* + first free block in queue test counter (if it exceed + MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) + */ + unsigned int first_block_usage; + + void (*error_handler)(void); +} MEM_ROOT; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/meosdb/mysql55/my_attribute.h b/code/meosdb/mysql55/my_attribute.h new file mode 100644 index 0000000..ebd236e --- /dev/null +++ b/code/meosdb/mysql55/my_attribute.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + Helper macros used for setting different __attributes__ + on functions in a portable fashion +*/ + +#ifndef _my_attribute_h +#define _my_attribute_h + +#if defined(__GNUC__) +# ifndef GCC_VERSION +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +# endif +#endif + +/* + Disable __attribute__() on gcc < 2.7, g++ < 3.4, and non-gcc compilers. + Some forms of __attribute__ are actually supported in earlier versions of + g++, but we just disable them all because we only use them to generate + compilation warnings. +*/ +#ifndef __attribute__ +# if !defined(__GNUC__) +# define __attribute__(A) +# elif GCC_VERSION < 2008 +# define __attribute__(A) +# elif defined(__cplusplus) && GCC_VERSION < 3004 +# define __attribute__(A) +# endif +#endif + +/* + __attribute__((format(...))) is only supported in gcc >= 2.8 and g++ >= 3.4 + But that's already covered by the __attribute__ tests above, so this is + just a convenience macro. +*/ +#ifndef ATTRIBUTE_FORMAT +# define ATTRIBUTE_FORMAT(style, m, n) __attribute__((format(style, m, n))) +#endif + +/* + + __attribute__((format(...))) on a function pointer is not supported + until gcc 3.1 +*/ +#ifndef ATTRIBUTE_FORMAT_FPTR +# if (GCC_VERSION >= 3001) +# define ATTRIBUTE_FORMAT_FPTR(style, m, n) ATTRIBUTE_FORMAT(style, m, n) +# else +# define ATTRIBUTE_FORMAT_FPTR(style, m, n) +# endif /* GNUC >= 3.1 */ +#endif + + +#endif diff --git a/code/meosdb/mysql55/my_compiler.h b/code/meosdb/mysql55/my_compiler.h new file mode 100644 index 0000000..918b4fc --- /dev/null +++ b/code/meosdb/mysql55/my_compiler.h @@ -0,0 +1,145 @@ +#ifndef MY_COMPILER_INCLUDED +#define MY_COMPILER_INCLUDED + +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + Header for compiler-dependent features. + + Intended to contain a set of reusable wrappers for preprocessor + macros, attributes, pragmas, and any other features that are + specific to a target compiler. +*/ + +#include /* stddef.h offsetof */ + +/** + Compiler-dependent internal convenience macros. +*/ + +/* GNU C/C++ */ +#if defined __GNUC__ +/* Convenience macro to test the minimum required GCC version. */ +# define MY_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +/* Any after 2.95... */ +# define MY_ALIGN_EXT +/* Comunicate to the compiler the unreachability of the code. */ +# if MY_GNUC_PREREQ(4,5) +# define MY_ASSERT_UNREACHABLE() __builtin_unreachable() +# endif + +/* Microsoft Visual C++ */ +#elif defined _MSC_VER +# define MY_ALIGNOF(type) __alignof(type) +# define MY_ALIGNED(n) __declspec(align(n)) + +/* Oracle Solaris Studio */ +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# if __SUNPRO_C >= 0x590 +# define MY_ALIGN_EXT +# endif + +/* IBM XL C/C++ */ +#elif defined __xlC__ +# if __xlC__ >= 0x0600 +# define MY_ALIGN_EXT +# endif + +/* HP aCC */ +#elif defined(__HP_aCC) || defined(__HP_cc) +# if (__HP_aCC >= 60000) || (__HP_cc >= 60000) +# define MY_ALIGN_EXT +# endif +#endif + +#ifdef MY_ALIGN_EXT +/** Specifies the minimum alignment of a type. */ +# define MY_ALIGNOF(type) __alignof__(type) +/** Determine the alignment requirement of a type. */ +# define MY_ALIGNED(n) __attribute__((__aligned__((n)))) +#endif + +/** + Generic (compiler-independent) features. +*/ + +#ifndef MY_GNUC_PREREQ +# define MY_GNUC_PREREQ(maj, min) (0) +#endif + +#ifndef MY_ALIGNOF +# ifdef __cplusplus + template struct my_alignof_helper { char m1; type m2; }; + /* Invalid for non-POD types, but most compilers give the right answer. */ +# define MY_ALIGNOF(type) offsetof(my_alignof_helper, m2) +# else +# define MY_ALIGNOF(type) offsetof(struct { char m1; type m2; }, m2) +# endif +#endif + +#ifndef MY_ASSERT_UNREACHABLE +# define MY_ASSERT_UNREACHABLE() do { assert(0); } while (0) +#endif + +/** + C++ Type Traits +*/ + +#ifdef __cplusplus + +/** + Opaque storage with a particular alignment. +*/ +# if defined(MY_ALIGNED) +/* Partial specialization used due to MSVC++. */ +template struct my_alignment_imp; +template<> struct MY_ALIGNED(1) my_alignment_imp<1> {}; +template<> struct MY_ALIGNED(2) my_alignment_imp<2> {}; +template<> struct MY_ALIGNED(4) my_alignment_imp<4> {}; +template<> struct MY_ALIGNED(8) my_alignment_imp<8> {}; +template<> struct MY_ALIGNED(16) my_alignment_imp<16> {}; +/* ... expand as necessary. */ +# else +template +struct my_alignment_imp { double m1; }; +# endif + +/** + A POD type with a given size and alignment. + + @remark If the compiler does not support a alignment attribute + (MY_ALIGN macro), the default alignment of a double is + used instead. + + @tparam size The minimum size. + @tparam alignment The desired alignment: 1, 2, 4, 8 or 16. +*/ +template +struct my_aligned_storage +{ + union + { + char data[size]; + my_alignment_imp align; + }; +}; + +#endif /* __cplusplus */ + +#include + +#endif /* MY_COMPILER_INCLUDED */ diff --git a/code/meosdb/mysql55/my_config.h b/code/meosdb/mysql55/my_config.h new file mode 100644 index 0000000..55e01d9 --- /dev/null +++ b/code/meosdb/mysql55/my_config.h @@ -0,0 +1,618 @@ +/* Copyright (C) 2009, 2011, Oracle and/or its affiliates. All rights + reserved + + 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; version 2 of the License. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MY_CONFIG_H +#define MY_CONFIG_H +#define DOT_FRM_VERSION 6 +/* Headers we may want to use. */ +#define STDC_HEADERS 1 +/* #undef _GNU_SOURCE */ +/* #undef HAVE_ALLOCA_H */ +/* #undef HAVE_AIO_H */ +/* #undef HAVE_ARPA_INET_H */ +/* #undef HAVE_ASM_MSR_H */ +/* #undef HAVE_ASM_TERMBITS_H */ +#define HAVE_BSEARCH 1 +/* #undef HAVE_CRYPT_H */ +/* #undef HAVE_CURSES_H */ +/* #undef HAVE_CXXABI_H */ +/* #undef HAVE_NCURSES_H */ +/* #undef HAVE_NDIR_H */ +/* #undef HAVE_DIRENT_H */ +/* #undef HAVE_DLFCN_H */ +/* #undef HAVE_EXECINFO_H */ +#define HAVE_FCNTL_H 1 +/* #undef HAVE_FENV_H */ +#define HAVE_FLOAT_H 1 +/* #undef HAVE_FLOATINGPOINT_H */ +/* #undef HAVE_FNMATCH_H */ +/* #undef HAVE_FPU_CONTROL_H */ +/* #undef HAVE_GRP_H */ +/* #undef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */ +/* #undef HAVE_IA64INTRIN_H */ +/* #undef HAVE_IEEEFP_H */ +/* #undef HAVE_INTTYPES_H */ +#define HAVE_LIMITS_H 1 +#define HAVE_LOCALE_H 1 +#define HAVE_MALLOC_H 1 +#define HAVE_MEMORY_H 1 +/* #undef HAVE_NETINET_IN_H */ +/* #undef HAVE_PATHS_H */ +/* #undef HAVE_POLL_H */ +/* #undef HAVE_PORT_H */ +/* #undef HAVE_PWD_H */ +/* #undef HAVE_SCHED_H */ +/* #undef HAVE_SELECT_H */ +/* #undef HAVE_SOLARIS_LARGE_PAGES */ +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STDARG_H 1 +/* #undef HAVE_STRINGS_H */ +#define HAVE_STRING_H 1 +/* #undef HAVE_STDINT_H */ +/* #undef HAVE_SEMAPHORE_H */ +/* #undef HAVE_SYNCH_H */ +/* #undef HAVE_SYSENT_H */ +/* #undef HAVE_SYS_DIR_H */ +/* #undef HAVE_SYS_CDEFS_H */ +/* #undef HAVE_SYS_FILE_H */ +/* #undef HAVE_SYS_FPU_H */ +/* #undef HAVE_SYS_IOCTL_H */ +/* #undef HAVE_SYS_IPC_H */ +/* #undef HAVE_SYS_MALLOC_H */ +/* #undef HAVE_SYS_MMAN_H */ +/* #undef HAVE_SYS_NDIR_H */ +/* #undef HAVE_SYS_PTE_H */ +/* #undef HAVE_SYS_PTEM_H */ +/* #undef HAVE_SYS_PRCTL_H */ +/* #undef HAVE_SYS_RESOURCE_H */ +/* #undef HAVE_SYS_SELECT_H */ +/* #undef HAVE_SYS_SHM_H */ +/* #undef HAVE_SYS_SOCKET_H */ +#define HAVE_SYS_STAT_H 1 +/* #undef HAVE_SYS_STREAM_H */ +/* #undef HAVE_SYS_TERMCAP_H */ +#define HAVE_SYS_TIMEB_H 1 +/* #undef HAVE_SYS_TIMES_H */ +/* #undef HAVE_SYS_TIME_H */ +#define HAVE_SYS_TYPES_H 1 +/* #undef HAVE_SYS_UN_H */ +/* #undef HAVE_SYS_VADVISE_H */ +/* #undef HAVE_TERM_H */ +/* #undef HAVE_TERMBITS_H */ +/* #undef HAVE_TERMIOS_H */ +/* #undef HAVE_TERMIO_H */ +/* #undef HAVE_TERMCAP_H */ +#define HAVE_TIME_H 1 +/* #undef HAVE_UNISTD_H */ +/* #undef HAVE_UTIME_H */ +#define HAVE_VARARGS_H 1 +/* #undef HAVE_VIS_H */ +#define HAVE_SYS_UTIME_H 1 +/* #undef HAVE_SYS_WAIT_H */ +/* #undef HAVE_SYS_PARAM_H */ + +/* Libraries */ +/* #undef HAVE_LIBPTHREAD */ +/* #undef HAVE_LIBM */ +/* #undef HAVE_LIBDL */ +/* #undef HAVE_LIBRT */ +/* #undef HAVE_LIBSOCKET */ +/* #undef HAVE_LIBNSL */ +/* #undef HAVE_LIBCRYPT */ +/* #undef HAVE_LIBMTMALLOC */ +/* #undef HAVE_LIBWRAP */ +/* Does "struct timespec" have a "sec" and "nsec" field? */ +/* #undef HAVE_TIMESPEC_TS_SEC */ + +/* Readline */ +/* #undef HAVE_HIST_ENTRY */ +/* #undef USE_LIBEDIT_INTERFACE */ +/* #undef USE_NEW_READLINE_INTERFACE */ + +/* #undef FIONREAD_IN_SYS_IOCTL */ +/* #undef GWINSZ_IN_SYS_IOCTL */ +/* #undef TIOCSTAT_IN_SYS_IOCTL */ + +/* Functions we may want to use. */ +/* #undef HAVE_AIOWAIT */ +/* #undef HAVE_ALARM */ +#define HAVE_ALLOCA 1 +/* #undef HAVE_BFILL */ +/* #undef HAVE_BMOVE */ +/* #undef HAVE_BZERO */ +/* #undef HAVE_INDEX */ +/* #undef HAVE_CHOWN */ +/* #undef HAVE_CLOCK_GETTIME */ +/* #undef HAVE_CRYPT */ +/* #undef HAVE_CUSERID */ +#define HAVE_CXX_NEW 1 +/* #undef HAVE_DIRECTIO */ +/* #undef HAVE_DLERROR */ +/* #undef HAVE_DLOPEN */ +/* #undef HAVE_DOPRNT */ +/* #undef HAVE_FCHMOD */ +/* #undef HAVE_FCNTL */ +/* #undef HAVE_FCONVERT */ +/* #undef HAVE_FDATASYNC */ +/* #undef HAVE_FESETROUND */ +#define HAVE_FINITE 1 +/* #undef HAVE_FP_EXCEPT */ +/* #undef HAVE_FPSETMASK */ +/* #undef HAVE_FSEEKO */ +/* #undef HAVE_FSYNC */ +#define HAVE_FTIME 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETCWD 1 +/* #undef HAVE_GETHOSTBYADDR_R */ +/* #undef HAVE_GETHOSTBYNAME_R */ +/* #undef HAVE_GETHRTIME */ +/* #undef HAVE_GETLINE */ +/* #undef HAVE_GETNAMEINFO */ +/* #undef HAVE_GETPAGESIZE */ +/* #undef HAVE_GETPASS */ +/* #undef HAVE_GETPASSPHRASE */ +/* #undef HAVE_GETPWNAM */ +/* #undef HAVE_GETPWUID */ +/* #undef HAVE_GETRLIMIT */ +/* #undef HAVE_GETRUSAGE */ +/* #undef HAVE_GETTIMEOFDAY */ +/* #undef HAVE_GETWD */ +/* #undef HAVE_GMTIME_R */ +/* #undef gmtime_r */ +/* #undef HAVE_INITGROUPS */ +/* #undef HAVE_ISSETUGID */ +#define HAVE_ISNAN 1 +/* #undef HAVE_ISINF */ +/* #undef HAVE_LARGE_PAGE_OPTION */ +#define HAVE_LDIV 1 +/* #undef HAVE_LRAND48 */ +/* #undef HAVE_LOCALTIME_R */ +/* #undef HAVE_LOG2 */ +#define HAVE_LONGJMP 1 +/* #undef HAVE_LSTAT */ +/* #undef HAVE_MEMALIGN */ +/* #undef HAVE_MLOCK */ +/* #undef HAVE_NPTL */ +/* #undef HAVE_NL_LANGINFO */ +/* #undef HAVE_MADVISE */ +/* #undef HAVE_DECL_MADVISE */ +/* #undef HAVE_DECL_TGOTO */ +/* #undef HAVE_DECL_MHA_MAPSIZE_VA */ +/* #undef HAVE_MALLINFO */ +#define HAVE_MEMCPY 1 +#define HAVE_MEMMOVE 1 +/* #undef HAVE_MKSTEMP */ +/* #undef HAVE_MLOCKALL */ +/* #undef HAVE_MMAP */ +/* #undef HAVE_MMAP64 */ +#define HAVE_PERROR 1 +/* #undef HAVE_POLL */ +/* #undef HAVE_PORT_CREATE */ +/* #undef HAVE_POSIX_FALLOCATE */ +/* #undef HAVE_PREAD */ +/* #undef HAVE_PAUSE_INSTRUCTION */ +/* #undef HAVE_FAKE_PAUSE_INSTRUCTION */ +/* #undef HAVE_RDTSCLL */ +/* #undef HAVE_READ_REAL_TIME */ +/* #undef HAVE_PTHREAD_ATTR_CREATE */ +/* #undef HAVE_PTHREAD_ATTR_GETSTACKSIZE */ +/* #undef HAVE_PTHREAD_ATTR_SETPRIO */ +/* #undef HAVE_PTHREAD_ATTR_SETSCHEDPARAM */ +/* #undef HAVE_PTHREAD_ATTR_SETSCOPE */ +/* #undef HAVE_PTHREAD_ATTR_SETSTACKSIZE */ +/* #undef HAVE_PTHREAD_CONDATTR_CREATE */ +/* #undef HAVE_PTHREAD_CONDATTR_SETCLOCK */ +/* #undef HAVE_PTHREAD_INIT */ +/* #undef HAVE_PTHREAD_KEY_DELETE */ +/* #undef HAVE_PTHREAD_KEY_DELETE */ +/* #undef HAVE_PTHREAD_KILL */ +/* #undef HAVE_PTHREAD_RWLOCK_RDLOCK */ +/* #undef HAVE_PTHREAD_SETPRIO_NP */ +/* #undef HAVE_PTHREAD_SETSCHEDPARAM */ +/* #undef HAVE_PTHREAD_SIGMASK */ +/* #undef HAVE_PTHREAD_THREADMASK */ +/* #undef HAVE_PTHREAD_YIELD_NP */ +/* #undef HAVE_PTHREAD_YIELD_ZERO_ARG */ +/* #undef PTHREAD_ONCE_INITIALIZER */ +#define HAVE_PUTENV 1 +/* #undef HAVE_RE_COMP */ +/* #undef HAVE_REGCOMP */ +/* #undef HAVE_READDIR_R */ +/* #undef HAVE_READLINK */ +/* #undef HAVE_REALPATH */ +#define HAVE_RENAME 1 +/* #undef HAVE_RINT */ +/* #undef HAVE_RWLOCK_INIT */ +/* #undef HAVE_SCHED_YIELD */ +#define HAVE_SELECT 1 +/* #undef HAVE_SETFD */ +/* #undef HAVE_SETENV */ +#define HAVE_SETLOCALE 1 +/* #undef HAVE_SIGADDSET */ +/* #undef HAVE_SIGEMPTYSET */ +/* #undef HAVE_SIGHOLD */ +/* #undef HAVE_SIGSET */ +/* #undef HAVE_SIGSET_T */ +/* #undef HAVE_SIGACTION */ +/* #undef HAVE_SIGTHREADMASK */ +/* #undef HAVE_SIGWAIT */ +/* #undef HAVE_SLEEP */ +#define HAVE_SNPRINTF 1 +/* #undef HAVE_STPCPY */ +#define HAVE_STRERROR 1 +#define HAVE_STRCOLL 1 +/* #undef HAVE_STRSIGNAL */ +/* #undef HAVE_STRLCPY */ +/* #undef HAVE_STRLCAT */ +/* #undef HAVE_FGETLN */ +#define HAVE_STRNLEN 1 +#define HAVE_STRPBRK 1 +/* #undef HAVE_STRSEP */ +#define HAVE_STRSTR 1 +#define HAVE_STRTOK_R 1 +#define HAVE_STRTOL 1 +#define HAVE_STRTOLL 1 +#define HAVE_STRTOUL 1 +#define HAVE_STRTOULL 1 +/* #undef HAVE_SHMAT */ +/* #undef HAVE_SHMCTL */ +/* #undef HAVE_SHMDT */ +/* #undef HAVE_SHMGET */ +#define HAVE_TELL 1 +#define HAVE_TEMPNAM 1 +/* #undef HAVE_THR_SETCONCURRENCY */ +/* #undef HAVE_THR_YIELD */ +#define HAVE_TIME 1 +/* #undef HAVE_TIMES */ +/* #undef HAVE_VALLOC */ +#define HAVE_VIO_READ_BUFF 1 +/* #undef HAVE_VASPRINTF */ +#define HAVE_VPRINTF 1 +#define HAVE_VSNPRINTF 1 +/* #undef HAVE_FTRUNCATE */ +#define HAVE_TZNAME 1 +/* #undef HAVE_AIO_READ */ +/* Symbols we may use */ +/* #undef HAVE_SYS_ERRLIST */ +/* used by stacktrace functions */ +/* #undef HAVE_BSS_START */ +/* #undef HAVE_BACKTRACE */ +/* #undef HAVE_BACKTRACE_SYMBOLS */ +/* #undef HAVE_BACKTRACE_SYMBOLS_FD */ +/* #undef HAVE_PRINTSTACK */ +/* #undef HAVE_STRUCT_SOCKADDR_IN6 */ +/* #undef HAVE_STRUCT_IN6_ADDR */ +/* #undef HAVE_NETINET_IN6_H */ +#define HAVE_IPV6 1 +/* #undef ss_family */ +/* #undef HAVE_SOCKADDR_IN_SIN_LEN */ +/* #undef HAVE_SOCKADDR_IN6_SIN6_LEN */ +/* #undef HAVE_TIMESPEC_TS_SEC */ +/* #undef STRUCT_DIRENT_HAS_D_INO */ +/* #undef STRUCT_DIRENT_HAS_D_NAMLEN */ +#define SPRINTF_RETURNS_INT 1 + +#define USE_MB 1 +#define USE_MB_IDENT 1 + +/* #undef HAVE_VALGRIND */ + +/* Types we may use */ +#ifdef __APPLE__ + /* + Special handling required for OSX to support universal binaries that + mix 32 and 64 bit architectures. + */ + #if(__LP64__) + #define SIZEOF_LONG 8 + #else + #define SIZEOF_LONG 4 + #endif + #define SIZEOF_VOIDP SIZEOF_LONG + #define SIZEOF_CHARP SIZEOF_LONG + #define SIZEOF_SIZE_T SIZEOF_LONG +#else +/* No indentation, to fetch the lines from verification scripts */ +#define SIZEOF_LONG 4 +#define SIZEOF_VOIDP 8 +#define SIZEOF_CHARP 8 +#define SIZEOF_SIZE_T 8 +#endif + +#define SIZEOF_CHAR 1 +#define HAVE_CHAR 1 +#define HAVE_LONG 1 +#define HAVE_CHARP 1 +#define SIZEOF_SHORT 2 +#define HAVE_SHORT 1 +#define SIZEOF_INT 4 +#define HAVE_INT 1 +#define SIZEOF_LONG_LONG 8 +#define HAVE_LONG_LONG 1 +#define SIZEOF_OFF_T 4 +#define HAVE_OFF_T 1 +/* #undef SIZEOF_SIGSET_T */ +/* #undef HAVE_SIGSET_T */ +#define HAVE_SIZE_T 1 +/* #undef SIZEOF_UCHAR */ +/* #undef HAVE_UCHAR */ +/* #undef SIZEOF_UINT */ +/* #undef HAVE_UINT */ +/* #undef SIZEOF_ULONG */ +/* #undef HAVE_ULONG */ +/* #undef SIZEOF_INT8 */ +/* #undef HAVE_INT8 */ +/* #undef SIZEOF_UINT8 */ +/* #undef HAVE_UINT8 */ +/* #undef SIZEOF_INT16 */ +/* #undef HAVE_INT16 */ +/* #undef SIZEOF_UINT16 */ +/* #undef HAVE_UINT16 */ +/* #undef SIZEOF_INT32 */ +/* #undef HAVE_INT32 */ +/* #undef SIZEOF_UINT32 */ +/* #undef HAVE_UINT32 */ +/* #undef SIZEOF_U_INT32_T */ +/* #undef HAVE_U_INT32_T */ +/* #undef SIZEOF_INT64 */ +/* #undef HAVE_INT64 */ +/* #undef SIZEOF_UINT64 */ +/* #undef HAVE_UINT64 */ +/* #undef SIZEOF_BOOL */ +/* #undef HAVE_BOOL */ + +#define SOCKET_SIZE_TYPE int + +/* #undef HAVE_MBSTATE_T */ + +#define MAX_INDEXES 64 + +#define QSORT_TYPE_IS_VOID 1 +#define RETQSORTTYPE void + +#define SIGNAL_RETURN_TYPE_IS_VOID 1 +#define RETSIGTYPE void +#define VOID_SIGHANDLER 1 +#define STRUCT_RLIMIT struct rlimit + +#ifdef __APPLE__ + #if __BIG_ENDIAN + #define WORDS_BIGENDIAN 1 + #endif +#else +/* #undef WORDS_BIGENDIAN */ +#endif + +/* Define to `__inline__' or `__inline' if that's what the C compiler calls + it, or to nothing if 'inline' is not supported under any name. */ +/* #undef C_HAS_inline */ +#if !(C_HAS_inline) +#ifndef __cplusplus +# define inline __inline +#endif +#endif + + +/* #undef TARGET_OS_LINUX */ + +#define HAVE_WCTYPE_H 1 +#define HAVE_WCHAR_H 1 +/* #undef HAVE_LANGINFO_H */ +/* #undef HAVE_MBRLEN */ +/* #undef HAVE_MBSCMP */ +/* #undef HAVE_MBSRTOWCS */ +/* #undef HAVE_WCRTOMB */ +/* #undef HAVE_MBRTOWC */ +/* #undef HAVE_WCSCOLL */ +/* #undef HAVE_WCSDUP */ +/* #undef HAVE_WCWIDTH */ +/* #undef HAVE_WCTYPE */ +/* #undef HAVE_ISWLOWER */ +/* #undef HAVE_ISWUPPER */ +/* #undef HAVE_TOWLOWER */ +/* #undef HAVE_TOWUPPER */ +/* #undef HAVE_ISWCTYPE */ +/* #undef HAVE_WCHAR_T */ +/* #undef HAVE_WCTYPE_T */ +/* #undef HAVE_WINT_T */ + + +#define HAVE_STRCASECMP 1 +#define HAVE_STRNCASECMP 1 +#define HAVE_STRDUP 1 +/* #undef HAVE_LANGINFO_CODESET */ +/* #undef HAVE_TCGETATTR */ +/* #undef HAVE_FLOCKFILE */ + +/* #undef HAVE_WEAK_SYMBOL */ +/* #undef HAVE_ABI_CXA_DEMANGLE */ + + +/* #undef HAVE_POSIX_SIGNALS */ +/* #undef HAVE_BSD_SIGNALS */ +/* #undef HAVE_SVR3_SIGNALS */ +#define HAVE_V7_SIGNALS 1 + + +/* #undef HAVE_SOLARIS_STYLE_GETHOST */ +/* #undef HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE */ +/* #undef HAVE_GETHOSTBYNAME_R_RETURN_INT */ + +/* #undef MY_ATOMIC_MODE_DUMMY */ +/* #undef MY_ATOMIC_MODE_RWLOCKS */ +/* #undef HAVE_GCC_ATOMIC_BUILTINS */ +/* #undef HAVE_SOLARIS_ATOMIC */ +/* #undef HAVE_DECL_SHM_HUGETLB */ +/* #undef HAVE_LARGE_PAGES */ +/* #undef HUGETLB_USE_PROC_MEMINFO */ +#define NO_FCNTL_NONBLOCK 1 +#define NO_ALARM 1 + +/* #undef _LARGE_FILES */ +#define _LARGEFILE_SOURCE 1 +/* #undef _LARGEFILE64_SOURCE */ +/* #undef _FILE_OFFSET_BITS */ + +/* #undef TIME_WITH_SYS_TIME */ + +#define STACK_DIRECTION -1 + +#define SYSTEM_TYPE "Win64" +#define MACHINE_TYPE "x86" +/* #undef HAVE_DTRACE */ + +#define SIGNAL_WITH_VIO_CLOSE 1 + +/* Windows stuff, mostly functions, that have Posix analogs but named differently */ +#define S_IROTH _S_IREAD +#define S_IFIFO _S_IFIFO +/* #undef IPPROTO_IPV6 */ +/* #undef IPV6_V6ONLY */ +#define sigset_t int +#define mode_t int +#define SIGQUIT SIGTERM +#define SIGPIPE SIGINT +#define isnan _isnan +#define finite _finite +#define popen _popen +#define pclose _pclose +#define ssize_t SSIZE_T +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define snprintf _snprintf +#define strtok_r strtok_s +#define strtoll _strtoi64 +#define strtoull _strtoui64 +/* #undef vsnprintf */ +#if (_MSC_VER > 1310) +# define HAVE_SETENV +#define setenv(a,b,c) _putenv_s(a,b) +#endif + + + + +/* + MySQL features +*/ +#define ENABLED_LOCAL_INFILE 1 +#define ENABLED_PROFILING 1 +/* #undef EXTRA_DEBUG */ +/* #undef BACKUP_TEST */ +/* #undef CYBOZU */ + +/* Character sets and collations */ +#define MYSQL_DEFAULT_CHARSET_NAME "latin1" +#define MYSQL_DEFAULT_COLLATION_NAME "latin1_swedish_ci" + +#define USE_MB 1 +#define USE_MB_IDENT 1 +/* #undef USE_STRCOLL */ + +/* This should mean case insensitive file system */ +#define FN_NO_CASE_SENSE 1 + +#define HAVE_CHARSET_armscii8 1 +#define HAVE_CHARSET_ascii 1 +#define HAVE_CHARSET_big5 1 +#define HAVE_CHARSET_cp1250 1 +#define HAVE_CHARSET_cp1251 1 +#define HAVE_CHARSET_cp1256 1 +#define HAVE_CHARSET_cp1257 1 +#define HAVE_CHARSET_cp850 1 +#define HAVE_CHARSET_cp852 1 +#define HAVE_CHARSET_cp866 1 +#define HAVE_CHARSET_cp932 1 +#define HAVE_CHARSET_dec8 1 +#define HAVE_CHARSET_eucjpms 1 +#define HAVE_CHARSET_euckr 1 +#define HAVE_CHARSET_gb2312 1 +#define HAVE_CHARSET_gbk 1 +#define HAVE_CHARSET_geostd8 1 +#define HAVE_CHARSET_greek 1 +#define HAVE_CHARSET_hebrew 1 +#define HAVE_CHARSET_hp8 1 +#define HAVE_CHARSET_keybcs2 1 +#define HAVE_CHARSET_koi8r 1 +#define HAVE_CHARSET_koi8u 1 +#define HAVE_CHARSET_latin1 1 +#define HAVE_CHARSET_latin2 1 +#define HAVE_CHARSET_latin5 1 +#define HAVE_CHARSET_latin7 1 +#define HAVE_CHARSET_macce 1 +#define HAVE_CHARSET_macroman 1 +#define HAVE_CHARSET_sjis 1 +#define HAVE_CHARSET_swe7 1 +#define HAVE_CHARSET_tis620 1 +#define HAVE_CHARSET_ucs2 1 +#define HAVE_CHARSET_ujis 1 +#define HAVE_CHARSET_utf8mb4 1 +/* #undef HAVE_CHARSET_utf8mb3 */ +#define HAVE_CHARSET_utf8 1 +#define HAVE_CHARSET_utf16 1 +#define HAVE_CHARSET_utf32 1 +#define HAVE_UCA_COLLATIONS 1 +#define HAVE_COMPRESS 1 + + +/* + Stuff that always need to be defined (compile breaks without it) +*/ +#define HAVE_SPATIAL 1 +#define HAVE_RTREE_KEYS 1 +#define HAVE_QUERY_CACHE 1 +#define BIG_TABLES 1 + +/* + Important storage engines (those that really need define + WITH__STORAGE_ENGINE for the whole server) +*/ +#define WITH_MYISAM_STORAGE_ENGINE 1 +#define WITH_MYISAMMRG_STORAGE_ENGINE 1 +#define WITH_HEAP_STORAGE_ENGINE 1 +#define WITH_CSV_STORAGE_ENGINE 1 +#define WITH_PARTITION_STORAGE_ENGINE 1 +#define WITH_PERFSCHEMA_STORAGE_ENGINE 1 +/* #undef WITH_NDBCLUSTER_STORAGE_ENGINE */ +#if (WITH_NDBCLUSTER_STORAGE_ENGINE) && !defined(EMBEDDED_LIBRARY) +# define HAVE_NDB_BINLOG 1 +#endif + +#define DEFAULT_MYSQL_HOME "C:/Program Files/MySQL/MySQL Server 5.5" +#define SHAREDIR "share" +#define DEFAULT_BASEDIR "C:/Program Files/MySQL/MySQL Server 5.5" +#define MYSQL_DATADIR "C:/Program Files/MySQL/MySQL Server 5.5/data" +#define DEFAULT_CHARSET_HOME "C:/Program Files/MySQL/MySQL Server 5.5" +#define PLUGINDIR "C:/Program Files/MySQL/MySQL Server 5.5/lib/plugin" +/* #undef DEFAULT_SYSCONFDIR */ + +/* #undef SO_EXT */ + +#define MYSQL_MAJOR_VERSION 5 +#define MYSQL_MINOR_VERSION 5 + +#define PACKAGE "mysql" +#define PACKAGE_BUGREPORT "" +#define PACKAGE_NAME "MySQL Server" +#define PACKAGE_STRING "MySQL Server 5.5.9" +#define PACKAGE_TARNAME "mysql" +#define PACKAGE_VERSION "5.5.9" +#define VERSION "5.5.9" +#define PROTOCOL_VERSION 10 + + +#endif diff --git a/code/meosdb/mysql55/my_dbug.h b/code/meosdb/mysql55/my_dbug.h new file mode 100644 index 0000000..37382bd --- /dev/null +++ b/code/meosdb/mysql55/my_dbug.h @@ -0,0 +1,194 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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 */ + +#ifndef MY_DBUG_INCLUDED +#define MY_DBUG_INCLUDED + +#ifndef __WIN__ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#endif /* not __WIN__ */ + +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(DBUG_OFF) && !defined(_lint) + +struct _db_stack_frame_ { + const char *func; /* function name of the previous stack frame */ + const char *file; /* filename of the function of previous frame */ + uint level; /* this nesting level, highest bit enables tracing */ + struct _db_stack_frame_ *prev; /* pointer to the previous frame */ +}; + +struct _db_code_state_; +extern my_bool _dbug_on_; +extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int); +extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len); +extern int _db_explain_init_(char *buf, size_t len); +extern int _db_is_pushed_(void); +extern void _db_setjmp_(void); +extern void _db_longjmp_(void); +extern void _db_process_(const char *name); +extern void _db_push_(const char *control); +extern void _db_pop_(void); +extern void _db_set_(const char *control); +extern void _db_set_init_(const char *control); +extern void _db_enter_(const char *_func_, const char *_file_, uint _line_, + struct _db_stack_frame_ *_stack_frame_); +extern void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_); +extern void _db_pargs_(uint _line_,const char *keyword); +extern void _db_doprnt_(const char *format,...) + ATTRIBUTE_FORMAT(printf, 1, 2); +extern void _db_dump_(uint _line_,const char *keyword, + const unsigned char *memory, size_t length); +extern void _db_end_(void); +extern void _db_lock_file_(void); +extern void _db_unlock_file_(void); +extern FILE *_db_fp_(void); +extern void _db_flush_(); +extern const char* _db_get_func_(void); + +#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \ + _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_) +#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_) +#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) +#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) +#define DBUG_EXECUTE(keyword,a1) \ + do {if (_db_keyword_(0, (keyword), 0)) { a1 }} while(0) +#define DBUG_EXECUTE_IF(keyword,a1) \ + do {if (_db_keyword_(0, (keyword), 1)) { a1 }} while(0) +#define DBUG_EVALUATE(keyword,a1,a2) \ + (_db_keyword_(0,(keyword), 0) ? (a1) : (a2)) +#define DBUG_EVALUATE_IF(keyword,a1,a2) \ + (_db_keyword_(0,(keyword), 1) ? (a1) : (a2)) +#define DBUG_PRINT(keyword,arglist) \ + do {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;} while(0) +#define DBUG_PUSH(a1) _db_push_ (a1) +#define DBUG_POP() _db_pop_ () +#define DBUG_SET(a1) _db_set_ (a1) +#define DBUG_SET_INITIAL(a1) _db_set_init_ (a1) +#define DBUG_PROCESS(a1) _db_process_(a1) +#define DBUG_FILE _db_fp_() +#define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) +#define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) +#define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) +#define DBUG_END() _db_end_ () +#define DBUG_LOCK_FILE _db_lock_file_() +#define DBUG_UNLOCK_FILE _db_unlock_file_() +#define DBUG_ASSERT(A) assert(A) +#define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len)) +#define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len)) +#define DEBUGGER_OFF do { _dbug_on_= 0; } while(0) +#define DEBUGGER_ON do { _dbug_on_= 1; } while(0) +#ifndef __WIN__ +#define DBUG_ABORT() (_db_flush_(), abort()) +#else +/* + Avoid popup with abort/retry/ignore buttons. When BUG#31745 is fixed we can + call abort() instead of _exit(3) (now it would cause a "test signal" popup). +*/ +#include +#define DBUG_ABORT() (_db_flush_(),\ + (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE),\ + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\ + _exit(3)) +#endif +#define DBUG_CHECK_CRASH(func, op) \ + do { char _dbuf_[255]; strxnmov(_dbuf_, sizeof(_dbuf_)-1, (func), (op)); \ + DBUG_EXECUTE_IF(_dbuf_, DBUG_ABORT()); } while(0) +#define DBUG_CRASH_ENTER(func) \ + DBUG_ENTER(func); DBUG_CHECK_CRASH(func, "_crash_enter") +#define DBUG_CRASH_RETURN(val) \ + DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return") +#define DBUG_CRASH_VOID_RETURN \ + DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return") + +/* + Make the program fail, without creating a core file. + abort() will send SIGABRT which (most likely) generates core. + Use SIGKILL instead, which cannot be caught. + We also pause the current thread, until the signal is actually delivered. + An alternative would be to use _exit(EXIT_FAILURE), + but then valgrind would report lots of memory leaks. + */ +#ifdef __WIN__ +#define DBUG_SUICIDE() DBUG_ABORT() +#else +extern void _db_suicide_(); +#define DBUG_SUICIDE() (_db_flush_(), _db_suicide_()) +#endif + +#else /* No debugger */ + +#define DBUG_ENTER(a1) +#define DBUG_LEAVE +#define DBUG_RETURN(a1) do { return(a1); } while(0) +#define DBUG_VOID_RETURN do { return; } while(0) +#define DBUG_EXECUTE(keyword,a1) do { } while(0) +#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0) +#define DBUG_EVALUATE(keyword,a1,a2) (a2) +#define DBUG_EVALUATE_IF(keyword,a1,a2) (a2) +#define DBUG_PRINT(keyword,arglist) do { } while(0) +#define DBUG_PUSH(a1) do { } while(0) +#define DBUG_SET(a1) do { } while(0) +#define DBUG_SET_INITIAL(a1) do { } while(0) +#define DBUG_POP() do { } while(0) +#define DBUG_PROCESS(a1) do { } while(0) +#define DBUG_SETJMP(a1) setjmp(a1) +#define DBUG_LONGJMP(a1) longjmp(a1) +#define DBUG_DUMP(keyword,a1,a2) do { } while(0) +#define DBUG_END() do { } while(0) +#define DBUG_ASSERT(A) do { } while(0) +#define DBUG_LOCK_FILE do { } while(0) +#define DBUG_FILE (stderr) +#define DBUG_UNLOCK_FILE do { } while(0) +#define DBUG_EXPLAIN(buf,len) +#define DBUG_EXPLAIN_INITIAL(buf,len) +#define DEBUGGER_OFF do { } while(0) +#define DEBUGGER_ON do { } while(0) +#define DBUG_ABORT() do { } while(0) +#define DBUG_CRASH_ENTER(func) +#define DBUG_CRASH_RETURN(val) do { return(val); } while(0) +#define DBUG_CRASH_VOID_RETURN do { return; } while(0) +#define DBUG_SUICIDE() do { } while(0) + +#endif + +#ifdef EXTRA_DEBUG +/** + Sync points allow us to force the server to reach a certain line of code + and block there until the client tells the server it is ok to go on. + The client tells the server to block with SELECT GET_LOCK() + and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult + concurrency problems +*/ +#define DBUG_SYNC_POINT(lock_name,lock_timeout) \ + debug_sync_point(lock_name,lock_timeout) +void debug_sync_point(const char* lock_name, uint lock_timeout); +#else +#define DBUG_SYNC_POINT(lock_name,lock_timeout) +#endif /* EXTRA_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* MY_DBUG_INCLUDED */ diff --git a/code/meosdb/mysql55/my_dir.h b/code/meosdb/mysql55/my_dir.h new file mode 100644 index 0000000..7261a4b --- /dev/null +++ b/code/meosdb/mysql55/my_dir.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef MY_DIR_H +#define MY_DIR_H + +#include "my_global.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /* Defines for my_dir and my_stat */ + +#define MY_S_IFMT S_IFMT /* type of file */ +#define MY_S_IFDIR S_IFDIR /* directory */ +#define MY_S_IFCHR S_IFCHR /* character special */ +#define MY_S_IFBLK S_IFBLK /* block special */ +#define MY_S_IFREG S_IFREG /* regular */ +#define MY_S_IFIFO S_IFIFO /* fifo */ +#define MY_S_ISUID S_ISUID /* set user id on execution */ +#define MY_S_ISGID S_ISGID /* set group id on execution */ +#define MY_S_ISVTX S_ISVTX /* save swapped text even after use */ +#define MY_S_IREAD S_IREAD /* read permission, owner */ +#define MY_S_IWRITE S_IWRITE /* write permission, owner */ +#define MY_S_IEXEC S_IEXEC /* execute/search permission, owner */ + +#define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR) +#define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR) +#define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK) +#define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG) +#define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO) + +#define MY_DONT_SORT 512 /* my_lib; Don't sort files */ +#define MY_WANT_STAT 1024 /* my_lib; stat files */ + + /* typedefs for my_dir & my_stat */ + +#ifdef USE_MY_STAT_STRUCT + +typedef struct my_stat +{ + dev_t st_dev; /* major & minor device numbers */ + ino_t st_ino; /* inode number */ + ushort st_mode; /* file permissons (& suid sgid .. bits) */ + short st_nlink; /* number of links to file */ + ushort st_uid; /* user id */ + ushort st_gid; /* group id */ + dev_t st_rdev; /* more major & minor device numbers (???) */ + off_t st_size; /* size of file */ + time_t st_atime; /* time for last read */ + time_t st_mtime; /* time for last contens modify */ + time_t st_ctime; /* time for last inode or contents modify */ +} MY_STAT; + +#else + +#if(_MSC_VER) +#define MY_STAT struct _stati64 /* 64 bit file size */ +#else +#define MY_STAT struct stat /* Orginal struct have what we need */ +#endif + +#endif /* USE_MY_STAT_STRUCT */ + +/* Struct describing one file returned from my_dir */ +typedef struct fileinfo +{ + char *name; + MY_STAT *mystat; +} FILEINFO; + +typedef struct st_my_dir /* Struct returned from my_dir */ +{ + /* + These members are just copies of parts of DYNAMIC_ARRAY structure, + which is allocated right after the end of MY_DIR structure (MEM_ROOT + for storing names is also resides there). We've left them here because + we don't want to change code that uses my_dir. + */ + struct fileinfo *dir_entry; + uint number_off_files; +} MY_DIR; + +extern MY_DIR *my_dir(const char *path,myf MyFlags); +extern void my_dirend(MY_DIR *buffer); +extern MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags); +extern int my_fstat(int filenr, MY_STAT *stat_area, myf MyFlags); + +#ifdef __cplusplus +} +#endif + +#endif /* MY_DIR_H */ + diff --git a/code/meosdb/mysql55/my_getopt.h b/code/meosdb/mysql55/my_getopt.h new file mode 100644 index 0000000..3416eec --- /dev/null +++ b/code/meosdb/mysql55/my_getopt.h @@ -0,0 +1,123 @@ +/* Copyright (C) 2002-2004 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_getopt_h +#define _my_getopt_h + +#include "my_sys.h" /* loglevel */ + +C_MODE_START + +#define GET_NO_ARG 1 +#define GET_BOOL 2 +#define GET_INT 3 +#define GET_UINT 4 +#define GET_LONG 5 +#define GET_ULONG 6 +#define GET_LL 7 +#define GET_ULL 8 +#define GET_STR 9 +#define GET_STR_ALLOC 10 +#define GET_DISABLED 11 +#define GET_ENUM 12 +#define GET_SET 13 +#define GET_DOUBLE 14 +#define GET_FLAGSET 15 + +#define GET_ASK_ADDR 128 +#define GET_TYPE_MASK 127 + +/** + Enumeration of the my_option::arg_type attributes. + It should be noted that for historical reasons variables with the combination + arg_type=NO_ARG, my_option::var_type=GET_BOOL still accepts + arguments. This is someone counter intuitive and care should be taken + if the code is refactored. +*/ +enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG }; + +struct st_typelib; + +struct my_option +{ + const char *name; /**< Name of the option. name=NULL + marks the end of the my_option[] + array. + */ + int id; /**< For 0255 no short option + is created, but a long option still + can be identified uniquely in the + my_get_one_option() callback. + If an opton needs neither special + treatment in the my_get_one_option() + nor one-letter short equivalent + use id=0 + */ + const char *comment; /**< option comment, for autom. --help. + if it's NULL the option is not + visible in --help. + */ + void *value; /**< A pointer to the variable value */ + void *u_max_value; /**< The user def. max variable value */ + struct st_typelib *typelib; /**< Pointer to possible values */ + ulong var_type; /**< GET_BOOL, GET_ULL, etc */ + enum get_opt_arg_type arg_type; /**< e.g. REQUIRED_ARG or OPT_ARG */ + longlong def_value; /**< Default value */ + longlong min_value; /**< Min allowed value (for numbers) */ + longlong max_value; /**< Max allowed value (for numbers) */ + longlong sub_size; /**< Unused */ + long block_size; /**< Value should be a mult. of this (for numbers) */ + void *app_type; /**< To be used by an application */ +}; + + +typedef my_bool (*my_get_one_option)(int, const struct my_option *, char *); +typedef void (*my_error_reporter)(enum loglevel level, const char *format, ...); +/** + Used to retrieve a reference to the object (variable) that holds the value + for the given option. For example, if var_type is GET_UINT, the function + must return a pointer to a variable of type uint. A argument is stored in + the location pointed to by the returned pointer. +*/ +typedef void *(*my_getopt_value)(const char *, uint, const struct my_option *, + int *); + + +extern char *disabled_my_option; +extern my_bool my_getopt_print_errors; +extern my_bool my_getopt_skip_unknown; +extern my_error_reporter my_getopt_error_reporter; + +extern int handle_options (int *argc, char ***argv, + const struct my_option *longopts, my_get_one_option); +extern void my_cleanup_options(const struct my_option *options); +extern void my_print_help(const struct my_option *options); +extern void my_print_variables(const struct my_option *options); +extern void my_getopt_register_get_addr(my_getopt_value); + +ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp, + my_bool *fix); +longlong getopt_ll_limit_value(longlong, const struct my_option *, + my_bool *fix); +double getopt_double_limit_value(double num, const struct my_option *optp, + my_bool *fix); +my_bool getopt_compare_strings(const char *s, const char *t, uint length); + +C_MODE_END + +#endif /* _my_getopt_h */ + diff --git a/code/meosdb/mysql55/my_global.h b/code/meosdb/mysql55/my_global.h new file mode 100644 index 0000000..c2aed6f --- /dev/null +++ b/code/meosdb/mysql55/my_global.h @@ -0,0 +1,1483 @@ +/* Copyright (C) 2000-2003 MySQL AB, 2009 Sun Microsystems, Inc + + 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; version 2 of the License. + + 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 */ + +/* This is the include file that should be included 'first' in every C file. */ + +#ifndef _global_h +#define _global_h + +/* Client library users on Windows need this macro defined here. */ +#if !defined(__WIN__) && defined(_WIN32) +#define __WIN__ +#endif + +/* + InnoDB depends on some MySQL internals which other plugins should not + need. This is because of InnoDB's foreign key support, "safe" binlog + truncation, and other similar legacy features. + + We define accessors for these internals unconditionally, but do not + expose them in mysql/plugin.h. They are declared in ha_innodb.h for + InnoDB's use. +*/ +#define INNODB_COMPATIBILITY_HOOKS + +#ifdef __CYGWIN__ +/* We use a Unix API, so pretend it's not Windows */ +#undef WIN +#undef WIN32 +#undef _WIN +#undef _WIN32 +#undef _WIN64 +#undef __WIN__ +#undef __WIN32__ +#define HAVE_ERRNO_AS_DEFINE +#endif /* __CYGWIN__ */ + +/* to make command line shorter we'll define USE_PRAGMA_INTERFACE here */ +#ifdef USE_PRAGMA_IMPLEMENTATION +#define USE_PRAGMA_INTERFACE +#endif + +#if defined(__OpenBSD__) && (OpenBSD >= 200411) +#define HAVE_ERRNO_AS_DEFINE +#endif + +#if defined(i386) && !defined(__i386__) +#define __i386__ +#endif + +/* Macros to make switching between C and C++ mode easier */ +#ifdef __cplusplus +#define C_MODE_START extern "C" { +#define C_MODE_END } +#else +#define C_MODE_START +#define C_MODE_END +#endif + +#ifdef __cplusplus +#define CPP_UNNAMED_NS_START namespace { +#define CPP_UNNAMED_NS_END } +#endif + +#include + +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE +#define HAVE_PSI_INTERFACE +#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ + +/* Make it easier to add conditional code in _expressions_ */ +#ifdef __WIN__ +#define IF_WIN(A,B) A +#else +#define IF_WIN(A,B) B +#endif + +#ifdef HAVE_purify +#define IF_PURIFY(A,B) A +#else +#define IF_PURIFY(A,B) B +#endif + +#ifndef EMBEDDED_LIBRARY +#ifdef WITH_NDB_BINLOG +#define HAVE_NDB_BINLOG 1 +#endif +#endif /* !EMBEDDED_LIBRARY */ + +#ifndef EMBEDDED_LIBRARY +#define HAVE_REPLICATION +#define HAVE_EXTERNAL_CLIENT +#endif + +#if defined (_WIN32) +/* + off_t is 32 bit long. We do not use C runtime functions + with off_t but native Win32 file IO APIs, that work with + 64 bit offsets. +*/ +#undef SIZEOF_OFF_T +#define SIZEOF_OFF_T 8 + +/* + Prevent inclusion of Windows GDI headers - they define symbol + ERROR that conflicts with mysql headers. +*/ +#ifndef NOGDI +#define NOGDI +#endif + +/* Include common headers.*/ +#include +#include /* SOCKET */ +#include /* access(), chmod() */ +#include /* getpid() */ + +#define sleep(a) Sleep((a)*1000) + +/* Define missing access() modes. */ +#define F_OK 0 +#define W_OK 2 + +/* Define missing file locking constants. */ +#define F_RDLCK 1 +#define F_WRLCK 2 +#define F_UNLCK 3 +#define F_TO_EOF 0x3FFFFFFF + +/* Shared memory and named pipe connections are supported. */ +#define HAVE_SMEM 1 +#define HAVE_NAMED_PIPE 1 +#define shared_memory_buffer_length 16000 +#define default_shared_memory_base_name "MYSQL" +#endif /* _WIN32*/ + + +/* Workaround for _LARGE_FILES and _LARGE_FILE_API incompatibility on AIX */ +#if defined(_AIX) && defined(_LARGE_FILE_API) +#undef _LARGE_FILE_API +#endif + +/* + The macros below are used to allow build of Universal/fat binaries of + MySQL and MySQL applications under darwin. +*/ +#if defined(__APPLE__) && defined(__MACH__) +# undef SIZEOF_CHARP +# undef SIZEOF_SHORT +# undef SIZEOF_INT +# undef SIZEOF_LONG +# undef SIZEOF_LONG_LONG +# undef SIZEOF_OFF_T +# undef WORDS_BIGENDIAN +# define SIZEOF_SHORT 2 +# define SIZEOF_INT 4 +# define SIZEOF_LONG_LONG 8 +# define SIZEOF_OFF_T 8 +# if defined(__i386__) || defined(__ppc__) +# define SIZEOF_CHARP 4 +# define SIZEOF_LONG 4 +# elif defined(__x86_64__) || defined(__ppc64__) +# define SIZEOF_CHARP 8 +# define SIZEOF_LONG 8 +# else +# error Building FAT binary for an unknown architecture. +# endif +# if defined(__ppc__) || defined(__ppc64__) +# define WORDS_BIGENDIAN +# endif +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +/* + The macros below are borrowed from include/linux/compiler.h in the + Linux kernel. Use them to indicate the likelyhood of the truthfulness + of a condition. This serves two purposes - newer versions of gcc will be + able to optimize for branch predication, which could yield siginficant + performance gains in frequently executed sections of the code, and the + other reason to use them is for documentation +*/ + +#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) +#define __builtin_expect(x, expected_value) (x) +#endif + +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +/* Fix problem with S_ISLNK() on Linux */ +#if defined(TARGET_OS_LINUX) || defined(__GLIBC__) +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +/* + Temporary solution to solve bug#7156. Include "sys/types.h" before + the thread headers, else the function madvise() will not be defined +*/ +#if defined(HAVE_SYS_TYPES_H) && ( defined(sun) || defined(__sun) ) +#include +#endif + +#ifdef HAVE_THREADS_WITHOUT_SOCKETS +/* MIT pthreads does not work with unix sockets */ +#undef HAVE_SYS_UN_H +#endif + +#define __EXTENSIONS__ 1 /* We want some extension */ +#ifndef __STDC_EXT__ +#define __STDC_EXT__ 1 /* To get large file support on hpux */ +#endif + +/* + Solaris 9 include file refers to X/Open document + + System Interfaces and Headers, Issue 5 + + saying we should define _XOPEN_SOURCE=500 to get POSIX.1c prototypes, + but apparently other systems (namely FreeBSD) don't agree. + + On a newer Solaris 10, the above file recognizes also _XOPEN_SOURCE=600. + Furthermore, it tests that if a program requires older standard + (_XOPEN_SOURCE<600 or _POSIX_C_SOURCE<200112L) it cannot be + run on a new compiler (that defines _STDC_C99) and issues an #error. + It's also an #error if a program requires new standard (_XOPEN_SOURCE=600 + or _POSIX_C_SOURCE=200112L) and a compiler does not define _STDC_C99. + + To add more to this mess, Sun Studio C compiler defines _STDC_C99 while + C++ compiler does not! + + So, in a desperate attempt to get correct prototypes for both + C and C++ code, we define either _XOPEN_SOURCE=600 or _XOPEN_SOURCE=500 + depending on the compiler's announced C standard support. + + Cleaner solutions are welcome. +*/ +#ifdef __sun +#if __STDC_VERSION__ - 0 >= 199901L +#define _XOPEN_SOURCE 600 +#else +#define _XOPEN_SOURCE 500 +#endif +#endif + +#if !defined(__WIN__) +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */ +#endif + +#if !defined(SCO) +#define _REENTRANT 1 /* Some thread libraries require this */ +#endif +#if !defined(_THREAD_SAFE) && !defined(_AIX) +#define _THREAD_SAFE /* Required for OSF1 */ +#endif +#if defined(HPUX10) || defined(HPUX11) +C_MODE_START /* HPUX needs this, signal.h bug */ +#include +C_MODE_END +#else +#include /* AIX must have this included first */ +#endif +#if !defined(SCO) && !defined(_REENTRANT) +#define _REENTRANT 1 /* Threads requires reentrant code */ +#endif +#endif /* !defined(__WIN__) */ + +/* Go around some bugs in different OS and compilers */ +#ifdef _AIX /* By soren@t.dk */ +#define _H_STRINGS +#define _SYS_STREAM_H +/* #define _AIX32_CURSES */ /* XXX: this breaks AIX 4.3.3 (others?). */ +#define ulonglong2double(A) my_ulonglong2double(A) +#define my_off_t2double(A) my_ulonglong2double(A) +C_MODE_START +double my_ulonglong2double(unsigned long long A); +C_MODE_END +#endif /* _AIX */ + +#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */ +#undef HAVE_SNPRINTF +#endif +#ifdef HAVE_BROKEN_PREAD +/* + pread()/pwrite() are not 64 bit safe on HP-UX 11.0 without + installing the kernel patch PHKL_20349 or greater +*/ +#undef HAVE_PREAD +#undef HAVE_PWRITE +#endif + +#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */ +#undef HAVE_GETHOSTBYNAME_R +#endif +#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */ +#undef HAVE_INITGROUPS +#endif + +/* gcc/egcs issues */ + +#if defined(__GNUC) && defined(__EXCEPTIONS) +#error "Please add -fno-exceptions to CXXFLAGS and reconfigure/recompile" +#endif + +#if defined(_lint) && !defined(lint) +#define lint +#endif +#if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG) +#define _LONG_LONG 1 /* For AIX string library */ +#endif + +#ifndef stdin +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDDEF_H +#include +#endif + +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_FENV_H +#include /* For fesetround() */ +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_TIMEB_H +#include /* Avoid warnings on SCO */ +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA) +#undef HAVE_ALLOCA +#undef HAVE_ALLOCA_H +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif + +#include /* Recommended by debian */ +/* We need the following to go around a problem with openssl on solaris */ +#if defined(HAVE_CRYPT_H) +#include +#endif + +/* + A lot of our programs uses asserts, so better to always include it + This also fixes a problem when people uses DBUG_ASSERT without including + assert.h +*/ +#include + +/* an assert that works at compile-time. only for constant expression */ +#ifndef __GNUC__ +#define compile_time_assert(X) do { } while(0) +#else +#define compile_time_assert(X) \ + do \ + { \ + typedef char compile_time_assert[(X) ? 1 : -1]; \ + } while(0) +#endif + +/* Go around some bugs in different OS and compilers */ +#if defined (HPUX11) && defined(_LARGEFILE_SOURCE) +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif + +#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) +#include /* HPUX 10.20 defines ulong here. UGLY !!! */ +#define HAVE_ULONG +#endif +#if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) +/* Fix bug in setrlimit */ +#undef setrlimit +#define setrlimit cma_setrlimit64 +#endif +/* Declare madvise where it is not declared for C++, like Solaris */ +#if HAVE_MADVISE && !HAVE_DECL_MADVISE && defined(__cplusplus) +extern "C" int madvise(void *addr, size_t len, int behav); +#endif + +#define QUOTE_ARG(x) #x /* Quote argument (before cpp) */ +#define STRINGIFY_ARG(x) QUOTE_ARG(x) /* Quote argument, after cpp */ + +/* Paranoid settings. Define I_AM_PARANOID if you are paranoid */ +#ifdef I_AM_PARANOID +#define DONT_ALLOW_USER_CHANGE 1 +#define DONT_USE_MYSQL_PWD 1 +#endif + +/* Does the system remember a signal handler after a signal ? */ +#if !defined(HAVE_BSD_SIGNALS) && !defined(HAVE_SIGACTION) +#define SIGNAL_HANDLER_RESET_ON_DELIVERY +#endif + +/* + Deprecated workaround for false-positive uninitialized variables + warnings. Those should be silenced using tool-specific heuristics. + + Enabled by default for g++ due to the bug referenced below. +*/ +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \ + (defined(__GNUC__) && defined(__cplusplus)) +#define LINT_INIT(var) var= 0 +#else +#define LINT_INIT(var) +#endif + +#ifndef SO_EXT +#ifdef _WIN32 +#define SO_EXT ".dll" +#elif defined(__APPLE__) +#define SO_EXT ".dylib" +#else +#define SO_EXT ".so" +#endif +#endif + +/* + Suppress uninitialized variable warning without generating code. + + The _cplusplus is a temporary workaround for C++ code pending a fix + for a g++ bug (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34772). +*/ +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \ + defined(__cplusplus) || !defined(__GNUC__) +#define UNINIT_VAR(x) x= 0 +#else +/* GCC specific self-initialization which inhibits the warning. */ +#define UNINIT_VAR(x) x= x +#endif + +#if !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT +typedef unsigned int uint; +typedef unsigned short ushort; +#endif + +#define swap_variables(t, a, b) { t dummy; dummy= a; a= b; b= dummy; } +#define test(a) ((a) ? 1 : 0) +#define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0) +#define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0) +#define test_all_bits(a,b) (((a) & (b)) == (b)) +#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) + +/* Define some general constants */ +#ifndef TRUE +#define TRUE (1) /* Logical true */ +#define FALSE (0) /* Logical false */ +#endif + +#include + +/* + Wen using the embedded library, users might run into link problems, + duplicate declaration of __cxa_pure_virtual, solved by declaring it a + weak symbol. +*/ +#if defined(USE_MYSYS_NEW) && ! defined(DONT_DECLARE_CXA_PURE_VIRTUAL) +C_MODE_START +int __cxa_pure_virtual () __attribute__ ((weak)); +C_MODE_END +#endif + +/* The DBUG_ON flag always takes precedence over default DBUG_OFF */ +#if defined(DBUG_ON) && defined(DBUG_OFF) +#undef DBUG_OFF +#endif + +/* We might be forced to turn debug off, if not turned off already */ +#if (defined(FORCE_DBUG_OFF) || defined(_lint)) && !defined(DBUG_OFF) +# define DBUG_OFF +# ifdef DBUG_ON +# undef DBUG_ON +# endif +#endif + +/* Some types that is different between systems */ + +typedef int File; /* File descriptor */ +#ifdef _WIN32 +typedef SOCKET my_socket; +#else +typedef int my_socket; /* File descriptor for sockets */ +#define INVALID_SOCKET -1 +#endif +/* Type for fuctions that handles signals */ +#define sig_handler RETSIGTYPE +C_MODE_START +typedef void (*sig_return)();/* Returns type from signal */ +C_MODE_END +#if defined(__GNUC__) && !defined(_lint) +typedef char pchar; /* Mixed prototypes can take char */ +typedef char puchar; /* Mixed prototypes can take char */ +typedef char pbool; /* Mixed prototypes can take char */ +typedef short pshort; /* Mixed prototypes can take short int */ +typedef float pfloat; /* Mixed prototypes can take float */ +#else +typedef int pchar; /* Mixed prototypes can't take char */ +typedef uint puchar; /* Mixed prototypes can't take char */ +typedef int pbool; /* Mixed prototypes can't take char */ +typedef int pshort; /* Mixed prototypes can't take short int */ +typedef double pfloat; /* Mixed prototypes can't take float */ +#endif +C_MODE_START +typedef int (*qsort_cmp)(const void *,const void *); +typedef int (*qsort_cmp2)(void*, const void *,const void *); +C_MODE_END +#define qsort_t RETQSORTTYPE /* Broken GCC cant handle typedef !!!! */ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +typedef SOCKET_SIZE_TYPE size_socket; + +#ifndef SOCKOPT_OPTLEN_TYPE +#define SOCKOPT_OPTLEN_TYPE size_socket +#endif + +/* file create flags */ + +#ifndef O_SHARE /* Probably not windows */ +#define O_SHARE 0 /* Flag to my_open for shared files */ +#ifndef O_BINARY +#define O_BINARY 0 /* Flag to my_open for binary files */ +#endif +#ifndef FILE_BINARY +#define FILE_BINARY O_BINARY /* Flag to my_fopen for binary streams */ +#endif +#ifdef HAVE_FCNTL +#define HAVE_FCNTL_LOCK +#define F_TO_EOF 0L /* Param to lockf() to lock rest of file */ +#endif +#endif /* O_SHARE */ + +#ifndef O_TEMPORARY +#define O_TEMPORARY 0 +#endif +#ifndef O_SHORT_LIVED +#define O_SHORT_LIVED 0 +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 +#endif + +/* additional file share flags for win32 */ +#ifdef __WIN__ +#define _SH_DENYRWD 0x110 /* deny read/write mode & delete */ +#define _SH_DENYWRD 0x120 /* deny write mode & delete */ +#define _SH_DENYRDD 0x130 /* deny read mode & delete */ +#define _SH_DENYDEL 0x140 /* deny delete only */ +#endif /* __WIN__ */ + + +/* General constants */ +#define FN_LEN 256 /* Max file name len */ +#define FN_HEADLEN 253 /* Max length of filepart of file name */ +#define FN_EXTLEN 20 /* Max length of extension (part of FN_LEN) */ +#define FN_REFLEN 512 /* Max length of full path-name */ +#define FN_EXTCHAR '.' +#define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ +#define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ +#define FN_PARENTDIR ".." /* Parent directory; Must be a string */ + +#ifdef _WIN32 +#define FN_LIBCHAR '\\' +#define FN_LIBCHAR2 '/' +#define FN_DIRSEP "/\\" /* Valid directory separators */ +#define FN_ROOTDIR "\\" +#define FN_DEVCHAR ':' +#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ +#define FN_NO_CASE_SENCE /* Files are not case-sensitive */ +#else +#define FN_LIBCHAR '/' +#define FN_LIBCHAR2 '/' +#define FN_DIRSEP "/" /* Valid directory separators */ +#define FN_ROOTDIR "/" +#endif + +/* + MY_FILE_MIN is Windows speciality and is used to quickly detect + the mismatch of CRT and mysys file IO usage on Windows at runtime. + CRT file descriptors can be in the range 0-2047, whereas descriptors returned + by my_open() will start with 2048. If a file descriptor with value less then + MY_FILE_MIN is passed to mysys IO function, chances are it stemms from + open()/fileno() and not my_open()/my_fileno. + + For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN + is logically 0. +*/ + +#ifdef _WIN32 +#define MY_FILE_MIN 2048 +#else +#define MY_FILE_MIN 0 +#endif + +/* + MY_NFILE is the default size of my_file_info array. + + It is larger on Windows, because it all file handles are stored in my_file_info + Default size is 16384 and this should be enough for most cases.If it is not + enough, --max-open-files with larger value can be used. + + For Posix , my_file_info array is only used to store filenames for + error reporting and its size is not a limitation for number of open files. +*/ +#ifdef _WIN32 +#define MY_NFILE (16384 + MY_FILE_MIN) +#else +#define MY_NFILE 64 +#endif + +#ifndef OS_FILE_LIMIT +#define OS_FILE_LIMIT UINT_MAX +#endif + +/* + Io buffer size; Must be a power of 2 and a multiple of 512. May be + smaller what the disk page size. This influences the speed of the + isam btree library. eg to big to slow. +*/ +#define IO_SIZE 4096 +/* + How much overhead does malloc have. The code often allocates + something like 1024-MALLOC_OVERHEAD bytes +*/ +#define MALLOC_OVERHEAD 8 + + /* get memory in huncs */ +#define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD) + /* Typical record cash */ +#define RECORD_CACHE_SIZE (uint) (64*1024-MALLOC_OVERHEAD) + /* Typical key cash */ +#define KEY_CACHE_SIZE (uint) (8*1024*1024) + /* Default size of a key cache block */ +#define KEY_CACHE_BLOCK_SIZE (uint) 1024 + + + /* Some things that this system doesn't have */ + +#ifdef _WIN32 +#define NO_DIR_LIBRARY /* Not standard dir-library */ +#endif + +/* Some defines of functions for portability */ + +#undef remove /* Crashes MySQL on SCO 5.0.0 */ +#ifndef __WIN__ +#define closesocket(A) close(A) +#endif + +#if (_MSC_VER) +#if !defined(_WIN64) +inline double my_ulonglong2double(unsigned long long value) +{ + long long nr=(long long) value; + if (nr >= 0) + return (double) nr; + return (18446744073709551616.0 + (double) nr); +} +#define ulonglong2double my_ulonglong2double +#define my_off_t2double my_ulonglong2double +#endif /* _WIN64 */ +inline unsigned long long my_double2ulonglong(double d) +{ + double t= d - (double) 0x8000000000000000ULL; + + if (t >= 0) + return ((unsigned long long) t) + 0x8000000000000000ULL; + return (unsigned long long) d; +} +#define double2ulonglong my_double2ulonglong +#endif + +#ifndef ulonglong2double +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) +#endif +#ifndef double2ulonglong +#define double2ulonglong(A) ((ulonglong) (double) (A)) +#endif + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#define ulong_to_double(X) ((double) (ulong) (X)) + +#ifndef STACK_DIRECTION +#error "please add -DSTACK_DIRECTION=1 or -1 to your CPPFLAGS" +#endif + +#if !defined(HAVE_STRTOK_R) +#define strtok_r(A,B,C) strtok((A),(B)) +#endif + +/* This is from the old m-machine.h file */ + +#if SIZEOF_LONG_LONG > 4 +#define HAVE_LONG_LONG 1 +#endif + +/* + Some pre-ANSI-C99 systems like AIX 5.1 and Linux/GCC 2.95 define + ULONGLONG_MAX, LONGLONG_MIN, LONGLONG_MAX; we use them if they're defined. +*/ + +#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) +#define LONGLONG_MIN ((long long) 0x8000000000000000LL) +#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) +#endif + +#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) +/* First check for ANSI C99 definition: */ +#ifdef ULLONG_MAX +#define ULONGLONG_MAX ULLONG_MAX +#else +#define ULONGLONG_MAX ((unsigned long long)(~0ULL)) +#endif +#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ + +#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL) +#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL +#define INT_MIN32 (~0x7FFFFFFFL) +#define INT_MAX32 0x7FFFFFFFL +#define UINT_MAX32 0xFFFFFFFFL +#define INT_MIN24 (~0x007FFFFF) +#define INT_MAX24 0x007FFFFF +#define UINT_MAX24 0x00FFFFFF +#define INT_MIN16 (~0x7FFF) +#define INT_MAX16 0x7FFF +#define UINT_MAX16 0xFFFF +#define INT_MIN8 (~0x7F) +#define INT_MAX8 0x7F +#define UINT_MAX8 0xFF + +/* From limits.h instead */ +#ifndef DBL_MIN +#define DBL_MIN 4.94065645841246544e-324 +#define FLT_MIN ((float)1.40129846432481707e-45) +#endif +#ifndef DBL_MAX +#define DBL_MAX 1.79769313486231470e+308 +#define FLT_MAX ((float)3.40282346638528860e+38) +#endif +#ifndef SIZE_T_MAX +#define SIZE_T_MAX (~((size_t) 0)) +#endif + +#ifndef isfinite +#ifdef HAVE_FINITE +#define isfinite(x) finite(x) +#else +#define finite(x) (1.0 / fabs(x) > 0.0) +#endif /* HAVE_FINITE */ +#endif /* isfinite */ + +#ifndef HAVE_ISNAN +#define isnan(x) ((x) != (x)) +#endif + +#ifdef HAVE_ISINF +/* Check if C compiler is affected by GCC bug #39228 */ +#if !defined(__cplusplus) && defined(HAVE_BROKEN_ISINF) +/* Force store/reload of the argument to/from a 64-bit double */ +static inline double my_isinf(double x) +{ + volatile double t= x; + return isinf(t); +} +#else +/* System-provided isinf() is available and safe to use */ +#define my_isinf(X) isinf(X) +#endif +#else /* !HAVE_ISINF */ +#define my_isinf(X) (!finite(X) && !isnan(X)) +#endif + +/* Define missing math constants. */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_E +#define M_E 2.7182818284590452354 +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +/* + Max size that must be added to a so that we know Size to make + adressable obj. +*/ +#if SIZEOF_CHARP == 4 +typedef long my_ptrdiff_t; +#else +typedef long long my_ptrdiff_t; +#endif + +#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) +#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) +/* Size to make adressable obj. */ +#define ADD_TO_PTR(ptr,size,type) (type) ((uchar*) (ptr)+size) +#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((uchar*) (A) - (uchar*) (B)) + +/* + Custom version of standard offsetof() macro which can be used to get + offsets of members in class for non-POD types (according to the current + version of C++ standard offsetof() macro can't be used in such cases and + attempt to do so causes warnings to be emitted, OTOH in many cases it is + still OK to assume that all instances of the class has the same offsets + for the same members). + + This is temporary solution which should be removed once File_parser class + and related routines are refactored. +*/ + +#define my_offsetof(TYPE, MEMBER) \ + ((size_t)((char *)&(((TYPE *)0x10)->MEMBER) - (char*)0x10)) + +#define NullS (char *) 0 + +#ifdef STDCALL +#undef STDCALL +#endif + +#ifdef _WIN32 +#define STDCALL __stdcall +#else +#define STDCALL +#endif + +/* Typdefs for easyier portability */ + +#ifndef HAVE_UCHAR +typedef unsigned char uchar; /* Short for unsigned char */ +#endif + +#ifndef HAVE_INT8 +typedef signed char int8; /* Signed integer >= 8 bits */ +#endif +#ifndef HAVE_UINT8 +typedef unsigned char uint8; /* Unsigned integer >= 8 bits */ +#endif +#ifndef HAVE_INT16 +typedef short int16; +#endif +#ifndef HAVE_UINT16 +typedef unsigned short uint16; +#endif +#if SIZEOF_INT == 4 +#ifndef HAVE_INT32 +typedef int int32; +#endif +#ifndef HAVE_UINT32 +typedef unsigned int uint32; +#endif +#elif SIZEOF_LONG == 4 +#ifndef HAVE_INT32 +typedef long int32; +#endif +#ifndef HAVE_UINT32 +typedef unsigned long uint32; +#endif +#else +#error Neither int or long is of 4 bytes width +#endif + +#if !defined(HAVE_ULONG) && !defined(__USE_MISC) +typedef unsigned long ulong; /* Short for unsigned long */ +#endif +#ifndef longlong_defined +/* + Using [unsigned] long long is preferable as [u]longlong because we use + [unsigned] long long unconditionally in many places, + for example in constants with [U]LL suffix. +*/ +#if defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 +typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ +typedef long long int longlong; +#else +typedef unsigned long ulonglong; /* ulong or unsigned long long */ +typedef long longlong; +#endif +#endif +#ifndef HAVE_INT64 +typedef longlong int64; +#endif +#ifndef HAVE_UINT64 +typedef ulonglong uint64; +#endif + +#if defined(NO_CLIENT_LONG_LONG) +typedef unsigned long my_ulonglong; +#elif defined (__WIN__) +typedef unsigned __int64 my_ulonglong; +#else +typedef unsigned long long my_ulonglong; +#endif + +#if SIZEOF_CHARP == SIZEOF_INT +typedef int intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG +typedef long intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG_LONG +typedef long long intptr; +#else +#error sizeof(void *) is neither sizeof(int) nor sizeof(long) nor sizeof(long long) +#endif + +#define MY_ERRPTR ((void*)(intptr)1) + +#if defined(_WIN32) +typedef unsigned long long my_off_t; +typedef unsigned long long os_off_t; +#else +typedef off_t os_off_t; +#if SIZEOF_OFF_T > 4 +typedef ulonglong my_off_t; +#else +typedef unsigned long my_off_t; +#endif +#endif /*_WIN32*/ +#define MY_FILEPOS_ERROR (~(my_off_t) 0) + +/* + TODO Convert these to use Bitmap class. + */ +typedef ulonglong table_map; /* Used for table bits in join */ +typedef ulong nesting_map; /* Used for flags of nesting constructs */ + +#if defined(__WIN__) +#define socket_errno WSAGetLastError() +#define SOCKET_EINTR WSAEINTR +#define SOCKET_EAGAIN WSAEINPROGRESS +#define SOCKET_ETIMEDOUT WSAETIMEDOUT +#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK +#define SOCKET_EADDRINUSE WSAEADDRINUSE +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#else /* Unix */ +#define socket_errno errno +#define closesocket(A) close(A) +#define SOCKET_EINTR EINTR +#define SOCKET_EAGAIN EAGAIN +#define SOCKET_ETIMEDOUT SOCKET_EINTR +#define SOCKET_EWOULDBLOCK EWOULDBLOCK +#define SOCKET_EADDRINUSE EADDRINUSE +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#endif + +typedef int myf; /* Type of MyFlags in my_funcs */ +typedef char my_bool; /* Small bool */ + +/* Macros for converting *constants* to the right type */ +#define MYF(v) (myf) (v) + +#ifndef LL +#ifdef HAVE_LONG_LONG +#define LL(A) A ## LL +#else +#define LL(A) A ## L +#endif +#endif + +#ifndef ULL +#ifdef HAVE_LONG_LONG +#define ULL(A) A ## ULL +#else +#define ULL(A) A ## UL +#endif +#endif + +/* + Defines to make it possible to prioritize register assignments. No + longer that important with modern compilers. +*/ +#ifndef USING_X +#define reg1 register +#define reg2 register +#define reg3 register +#define reg4 register +#define reg5 register +#define reg6 register +#define reg7 register +#define reg8 register +#define reg9 register +#define reg10 register +#define reg11 register +#define reg12 register +#define reg13 register +#define reg14 register +#define reg15 register +#define reg16 register +#endif + +#include + +/* Some helper macros */ +#define YESNO(X) ((X) ? "yes" : "no") + +#define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */ +#define MY_HOW_OFTEN_TO_WRITE 1000 /* How often we want info on screen */ + + + +/* + Define-funktions for reading and storing in machine independent format + (low byte first) +*/ + +/* Optimized store functions for Intel x86 */ +#if defined(__i386__) || defined(_WIN32) +#define sint2korr(A) (*((int16 *) (A))) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (*((long *) (A))) +#define uint2korr(A) (*((uint16 *) (A))) +#if defined(HAVE_purify) && !defined(_WIN32) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#else +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) +#endif /* HAVE_purify && !_WIN32 */ +#define uint4korr(A) (*((uint32 *) (A))) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) + \ + (((uint32) ((uchar) (A)[1])) << 8) + \ + (((uint32) ((uchar) (A)[2])) << 16) + \ + (((uint32) ((uchar) (A)[3])) << 24)) + \ + (((ulonglong) ((uchar) (A)[4])) << 32) + \ + (((ulonglong) ((uchar) (A)[5])) << 40)) +#define uint8korr(A) (*((ulonglong *) (A))) +#define sint8korr(A) (*((longlong *) (A))) +#define int2store(T,A) *((uint16*) (T))= (uint16) (A) +#define int3store(T,A) do { *(T)= (uchar) ((A));\ + *(T+1)=(uchar) (((uint) (A) >> 8));\ + *(T+2)=(uchar) (((A) >> 16)); } while (0) +#define int4store(T,A) *((long *) (T))= (long) (A) +#define int5store(T,A) do { *(T)= (uchar)((A));\ + *((T)+1)=(uchar) (((A) >> 8));\ + *((T)+2)=(uchar) (((A) >> 16));\ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); } while(0) +#define int6store(T,A) do { *(T)= (uchar)((A)); \ + *((T)+1)=(uchar) (((A) >> 8)); \ + *((T)+2)=(uchar) (((A) >> 16)); \ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); \ + *((T)+5)=(uchar) (((A) >> 40)); } while(0) +#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) + +typedef union { + double v; + long m[2]; +} doubleget_union; +#define doubleget(V,M) \ +do { doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } while(0) +#define doublestore(T,V) do { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ + *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; \ + } while (0) +#define float4get(V,M) do { *((float *) &(V)) = *((float*) (M)); } while(0) +#define float8get(V,M) doubleget((V),(M)) +#define float4store(V,M) memcpy((uchar*) V,(uchar*) (&M),sizeof(float)) +#define floatstore(T,V) memcpy((uchar*)(T), (uchar*)(&V),sizeof(float)) +#define floatget(V,M) memcpy((uchar*) &V,(uchar*) (M),sizeof(float)) +#define float8store(V,M) doublestore((V),(M)) +#else + +/* + We're here if it's not a IA-32 architecture (Win32 and UNIX IA-32 defines + were done before) +*/ +#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\ + ((int16) ((int16) (A)[1]) << 8)) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\ + (((int32) ((uchar) (A)[1]) << 8)) +\ + (((int32) ((uchar) (A)[2]) << 16)) +\ + (((int32) ((int16) (A)[3]) << 24))) +#define sint8korr(A) (longlong) uint8korr(A) +#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\ + ((uint16) ((uchar) (A)[1]) << 8)) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) + \ + (((uint32) ((uchar) (A)[1])) << 8) + \ + (((uint32) ((uchar) (A)[2])) << 16) + \ + (((uint32) ((uchar) (A)[3])) << 24)) + \ + (((ulonglong) ((uchar) (A)[4])) << 32) + \ + (((ulonglong) ((uchar) (A)[5])) << 40)) +#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) (((uint32) ((uchar) (A)[4])) +\ + (((uint32) ((uchar) (A)[5])) << 8) +\ + (((uint32) ((uchar) (A)[6])) << 16) +\ + (((uint32) ((uchar) (A)[7])) << 24))) <<\ + 32)) +#define int2store(T,A) do { uint def_temp= (uint) (A) ;\ + *((uchar*) (T))= (uchar)(def_temp); \ + *((uchar*) (T)+1)=(uchar)((def_temp >> 8)); \ + } while(0) +#define int3store(T,A) do { /*lint -save -e734 */\ + *((uchar*)(T))=(uchar) ((A));\ + *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ + *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ + /*lint -restore */} while(0) +#define int4store(T,A) do { *((char *)(T))=(char) ((A));\ + *(((char *)(T))+1)=(char) (((A) >> 8));\ + *(((char *)(T))+2)=(char) (((A) >> 16));\ + *(((char *)(T))+3)=(char) (((A) >> 24)); } while(0) +#define int5store(T,A) do { *((char *)(T))= (char)((A)); \ + *(((char *)(T))+1)= (char)(((A) >> 8)); \ + *(((char *)(T))+2)= (char)(((A) >> 16)); \ + *(((char *)(T))+3)= (char)(((A) >> 24)); \ + *(((char *)(T))+4)= (char)(((A) >> 32)); \ + } while(0) +#define int6store(T,A) do { *((char *)(T))= (char)((A)); \ + *(((char *)(T))+1)= (char)(((A) >> 8)); \ + *(((char *)(T))+2)= (char)(((A) >> 16)); \ + *(((char *)(T))+3)= (char)(((A) >> 24)); \ + *(((char *)(T))+4)= (char)(((A) >> 32)); \ + *(((char *)(T))+5)= (char)(((A) >> 40)); \ + } while(0) +#define int8store(T,A) do { uint def_temp= (uint) (A), def_temp2= (uint) ((A) >> 32); \ + int4store((T),def_temp); \ + int4store((T+4),def_temp2); } while(0) +#ifdef WORDS_BIGENDIAN +#define float4store(T,A) do { *(T)= ((uchar *) &A)[3];\ + *((T)+1)=(char) ((uchar *) &A)[2];\ + *((T)+2)=(char) ((uchar *) &A)[1];\ + *((T)+3)=(char) ((uchar *) &A)[0]; } while(0) + +#define float4get(V,M) do { float def_temp;\ + ((uchar*) &def_temp)[0]=(M)[3];\ + ((uchar*) &def_temp)[1]=(M)[2];\ + ((uchar*) &def_temp)[2]=(M)[1];\ + ((uchar*) &def_temp)[3]=(M)[0];\ + (V)=def_temp; } while(0) +#define float8store(T,V) do { *(T)= ((uchar *) &V)[7];\ + *((T)+1)=(char) ((uchar *) &V)[6];\ + *((T)+2)=(char) ((uchar *) &V)[5];\ + *((T)+3)=(char) ((uchar *) &V)[4];\ + *((T)+4)=(char) ((uchar *) &V)[3];\ + *((T)+5)=(char) ((uchar *) &V)[2];\ + *((T)+6)=(char) ((uchar *) &V)[1];\ + *((T)+7)=(char) ((uchar *) &V)[0]; } while(0) + +#define float8get(V,M) do { double def_temp;\ + ((uchar*) &def_temp)[0]=(M)[7];\ + ((uchar*) &def_temp)[1]=(M)[6];\ + ((uchar*) &def_temp)[2]=(M)[5];\ + ((uchar*) &def_temp)[3]=(M)[4];\ + ((uchar*) &def_temp)[4]=(M)[3];\ + ((uchar*) &def_temp)[5]=(M)[2];\ + ((uchar*) &def_temp)[6]=(M)[1];\ + ((uchar*) &def_temp)[7]=(M)[0];\ + (V) = def_temp; } while(0) +#else +#define float4get(V,M) memcpy(&V, (M), sizeof(float)) +#define float4store(V,M) memcpy(V, (&M), sizeof(float)) + +#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) +#define doublestore(T,V) do { *(((char*)T)+0)=(char) ((uchar *) &V)[4];\ + *(((char*)T)+1)=(char) ((uchar *) &V)[5];\ + *(((char*)T)+2)=(char) ((uchar *) &V)[6];\ + *(((char*)T)+3)=(char) ((uchar *) &V)[7];\ + *(((char*)T)+4)=(char) ((uchar *) &V)[0];\ + *(((char*)T)+5)=(char) ((uchar *) &V)[1];\ + *(((char*)T)+6)=(char) ((uchar *) &V)[2];\ + *(((char*)T)+7)=(char) ((uchar *) &V)[3]; }\ + while(0) +#define doubleget(V,M) do { double def_temp;\ + ((uchar*) &def_temp)[0]=(M)[4];\ + ((uchar*) &def_temp)[1]=(M)[5];\ + ((uchar*) &def_temp)[2]=(M)[6];\ + ((uchar*) &def_temp)[3]=(M)[7];\ + ((uchar*) &def_temp)[4]=(M)[0];\ + ((uchar*) &def_temp)[5]=(M)[1];\ + ((uchar*) &def_temp)[6]=(M)[2];\ + ((uchar*) &def_temp)[7]=(M)[3];\ + (V) = def_temp; } while(0) +#endif /* __FLOAT_WORD_ORDER */ + +#define float8get(V,M) doubleget((V),(M)) +#define float8store(V,M) doublestore((V),(M)) +#endif /* WORDS_BIGENDIAN */ + +#endif /* __i386__ OR _WIN32 */ + +/* + Macro for reading 32-bit integer from network byte order (big-endian) + from unaligned memory location. +*/ +#define int4net(A) (int32) (((uint32) ((uchar) (A)[3])) |\ + (((uint32) ((uchar) (A)[2])) << 8) |\ + (((uint32) ((uchar) (A)[1])) << 16) |\ + (((uint32) ((uchar) (A)[0])) << 24)) +/* + Define-funktions for reading and storing in machine format from/to + short/long to/from some place in memory V should be a (not + register) variable, M is a pointer to byte +*/ + +#ifdef WORDS_BIGENDIAN + +#define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\ + ((uint16) ((uint16) (M)[0]) << 8)); } while(0) +#define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\ + ((short) ((short) (M)[0]) << 8)); } while(0) +#define longget(V,M) do { int32 def_temp;\ + ((uchar*) &def_temp)[0]=(M)[0];\ + ((uchar*) &def_temp)[1]=(M)[1];\ + ((uchar*) &def_temp)[2]=(M)[2];\ + ((uchar*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define ulongget(V,M) do { uint32 def_temp;\ + ((uchar*) &def_temp)[0]=(M)[0];\ + ((uchar*) &def_temp)[1]=(M)[1];\ + ((uchar*) &def_temp)[2]=(M)[2];\ + ((uchar*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define shortstore(T,A) do { uint def_temp=(uint) (A) ;\ + *(((char*)T)+1)=(char)(def_temp); \ + *(((char*)T)+0)=(char)(def_temp >> 8); } while(0) +#define longstore(T,A) do { *(((char*)T)+3)=((A));\ + *(((char*)T)+2)=(((A) >> 8));\ + *(((char*)T)+1)=(((A) >> 16));\ + *(((char*)T)+0)=(((A) >> 24)); } while(0) + +#define floatget(V,M) memcpy(&V, (M), sizeof(float)) +#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) +#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) +#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) +#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) + +#else + +#define ushortget(V,M) do { V = uint2korr(M); } while(0) +#define shortget(V,M) do { V = sint2korr(M); } while(0) +#define longget(V,M) do { V = sint4korr(M); } while(0) +#define ulongget(V,M) do { V = uint4korr(M); } while(0) +#define shortstore(T,V) int2store(T,V) +#define longstore(T,V) int4store(T,V) +#ifndef floatstore +#define floatstore(T,V) memcpy((T), (void *) (&V), sizeof(float)) +#define floatget(V,M) memcpy(&V, (M), sizeof(float)) +#endif +#ifndef doubleget +#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) +#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) +#endif /* doubleget */ +#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) + +#endif /* WORDS_BIGENDIAN */ + +#ifdef HAVE_CHARSET_utf8 +#define MYSQL_UNIVERSAL_CLIENT_CHARSET "utf8" +#else +#define MYSQL_UNIVERSAL_CLIENT_CHARSET MYSQL_DEFAULT_CHARSET_NAME +#endif + +#if defined(EMBEDDED_LIBRARY) && !defined(HAVE_EMBEDDED_PRIVILEGE_CONTROL) +#define NO_EMBEDDED_ACCESS_CHECKS +#endif + +#if defined(_WIN32) +#define dlsym(lib, name) (void*)GetProcAddress((HMODULE)lib, name) +#define dlopen(libname, unused) LoadLibraryEx(libname, NULL, 0) +#define dlclose(lib) FreeLibrary((HMODULE)lib) +#ifndef HAVE_DLOPEN +#define HAVE_DLOPEN +#endif +#endif + +#ifdef HAVE_DLOPEN +#if defined(HAVE_DLFCN_H) +#include +#endif +#endif + +#ifndef HAVE_DLERROR +#ifdef _WIN32 +#define dlerror() "" +#else +#define dlerror() "No support for dynamic loading (static build?)" +#endif +#endif + + +/* + * Include standard definitions of operator new and delete. + */ +#ifdef __cplusplus +#include +#endif + +/* Length of decimal number represented by INT32. */ +#define MY_INT32_NUM_DECIMAL_DIGITS 11 + +/* Length of decimal number represented by INT64. */ +#define MY_INT64_NUM_DECIMAL_DIGITS 21 + +/* Define some useful general macros (should be done after all headers). */ +#if !defined(max) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* + Only Linux is known to need an explicit sync of the directory to make sure a + file creation/deletion/renaming in(from,to) this directory durable. +*/ +#ifdef TARGET_OS_LINUX +#define NEED_EXPLICIT_SYNC_DIR 1 +#endif + +#if !defined(__cplusplus) && !defined(bool) +#define bool In_C_you_should_use_my_bool_instead() +#endif + +/* Provide __func__ macro definition for platforms that miss it. */ +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 +# define __func__ "" +# else +# define __func__ __FUNCTION__ +# endif +#elif defined(__BORLANDC__) +# define __func__ __FUNC__ +#else +# define __func__ "" +#endif + +#ifndef HAVE_RINT +/** + All integers up to this number can be represented exactly as double precision + values (DBL_MANT_DIG == 53 for IEEE 754 hardware). +*/ +#define MAX_EXACT_INTEGER ((1LL << DBL_MANT_DIG) - 1) + +/** + rint(3) implementation for platforms that do not have it. + Always rounds to the nearest integer with ties being rounded to the nearest + even integer to mimic glibc's rint() behavior in the "round-to-nearest" + FPU mode. Hardware-specific optimizations are possible (frndint on x86). + Unlike this implementation, hardware will also honor the FPU rounding mode. +*/ + +static inline double rint(double x) +{ + double f, i; + f = modf(x, &i); + /* + All doubles with absolute values > MAX_EXACT_INTEGER are even anyway, + no need to check it. + */ + if (x > 0.0) + i += (double) ((f > 0.5) || (f == 0.5 && + i <= (double) MAX_EXACT_INTEGER && + (longlong) i % 2)); + else + i -= (double) ((f < -0.5) || (f == -0.5 && + i >= (double) -MAX_EXACT_INTEGER && + (longlong) i % 2)); + return i; +} +#endif /* HAVE_RINT */ + +/* + MYSQL_PLUGIN_IMPORT macro is used to export mysqld data + (i.e variables) for usage in storage engine loadable plugins. + Outside of Windows, it is dummy. +*/ +#ifndef MYSQL_PLUGIN_IMPORT +#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN)) +#define MYSQL_PLUGIN_IMPORT __declspec(dllimport) +#else +#define MYSQL_PLUGIN_IMPORT +#endif +#endif + +/* Defines that are unique to the embedded version of MySQL */ + +#ifdef EMBEDDED_LIBRARY + +/* Things we don't need in the embedded version of MySQL */ +/* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ + +#undef HAVE_OPENSSL +#undef HAVE_SMEM /* No shared memory */ +#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ + +#endif /* EMBEDDED_LIBRARY */ + +#endif /* my_global_h */ diff --git a/code/meosdb/mysql55/my_list.h b/code/meosdb/mysql55/my_list.h new file mode 100644 index 0000000..87426fe --- /dev/null +++ b/code/meosdb/mysql55/my_list.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _list_h_ +#define _list_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_list { + struct st_list *prev,*next; + void *data; +} LIST; + +typedef int (*list_walk_action)(void *,void *); + +extern LIST *list_add(LIST *root,LIST *element); +extern LIST *list_delete(LIST *root,LIST *element); +extern LIST *list_cons(void *data,LIST *root); +extern LIST *list_reverse(LIST *root); +extern void list_free(LIST *root,unsigned int free_data); +extern unsigned int list_length(LIST *); +extern int list_walk(LIST *,list_walk_action action,unsigned char * argument); + +#define list_rest(a) ((a)->next) +#define list_push(a,b) (a)=list_cons((b),(a)) +#define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old); my_free(old); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/meosdb/mysql55/my_net.h b/code/meosdb/mysql55/my_net.h new file mode 100644 index 0000000..e04c7e6 --- /dev/null +++ b/code/meosdb/mysql55/my_net.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + This file is also used to make handling of sockets and ioctl() + portable accross systems. + +*/ + +#ifndef _my_net_h +#define _my_net_h + +#include "my_global.h" /* C_MODE_START, C_MODE_END */ + +C_MODE_START + +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_POLL +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#if !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) +#include +#include +#include +#if !defined(alpha_linux_port) +#include +#endif +#endif + +#if defined(__WIN__) +#define O_NONBLOCK 1 /* For emulation of fcntl() */ + +/* + SHUT_RDWR is called SD_BOTH in windows and + is defined to 2 in winsock2.h + #define SD_BOTH 0x02 +*/ +#define SHUT_RDWR 0x02 + +#endif + +/* + On OSes which don't have the in_addr_t, we guess that using uint32 is the best + possible choice. We guess this from the fact that on HP-UX64bit & FreeBSD64bit + & Solaris64bit, in_addr_t is equivalent to uint32. And on Linux32bit too. +*/ +#ifndef HAVE_IN_ADDR_T +#define in_addr_t uint32 +#endif + +/* + Handling of gethostbyname_r() +*/ + +#if !defined(HAVE_GETHOSTBYNAME_R) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +void my_gethostbyname_r_free(); +#elif defined(HAVE_PTHREAD_ATTR_CREATE) || defined(_AIX) || defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +#define my_gethostbyname_r_free() +#if !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) && !defined(HPUX10) +#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data) +#endif /* !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) */ + +#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT) +#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +#define my_gethostbyname_r_free() +#else +#define my_gethostbyname_r(A,B,C,D,E) gethostbyname_r((A),(B),(C),(D),(E)) +#define my_gethostbyname_r_free() +#endif /* !defined(HAVE_GETHOSTBYNAME_R) */ + +#ifndef GETHOSTBYNAME_BUFF_SIZE +#define GETHOSTBYNAME_BUFF_SIZE 2048 +#endif + +C_MODE_END +#endif diff --git a/code/meosdb/mysql55/my_pthread.h b/code/meosdb/mysql55/my_pthread.h new file mode 100644 index 0000000..93a20d4 --- /dev/null +++ b/code/meosdb/mysql55/my_pthread.h @@ -0,0 +1,943 @@ +/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +/* Defines to make different thread packages compatible */ + +#ifndef _my_pthread_h +#define _my_pthread_h + +#include "my_global.h" /* myf */ + +#ifndef ETIME +#define ETIME ETIMEDOUT /* For FreeBSD */ +#endif + +#ifdef __cplusplus +#define EXTERNC extern "C" +extern "C" { +#else +#define EXTERNC +#endif /* __cplusplus */ + +#if defined(__WIN__) +typedef CRITICAL_SECTION pthread_mutex_t; +typedef DWORD pthread_t; +typedef struct thread_attr { + DWORD dwStackSize ; + DWORD dwCreatingFlag ; +} pthread_attr_t ; + +typedef struct { int dummy; } pthread_condattr_t; + +/* Implementation of posix conditions */ + +typedef struct st_pthread_link { + DWORD thread_id; + struct st_pthread_link *next; +} pthread_link; + +/** + Implementation of Windows condition variables. + We use native conditions on Vista and later, and fallback to own + implementation on earlier OS version. +*/ +typedef union +{ + /* Native condition (used on Vista and later) */ + CONDITION_VARIABLE native_cond; + + /* Own implementation (used on XP) */ + struct + { + uint32 waiting; + CRITICAL_SECTION lock_waiting; + enum + { + SIGNAL= 0, + BROADCAST= 1, + MAX_EVENTS= 2 + } EVENTS; + HANDLE events[MAX_EVENTS]; + HANDLE broadcast_block_event; + }; +} pthread_cond_t; + + +typedef int pthread_mutexattr_t; +#define pthread_self() GetCurrentThreadId() +#define pthread_handler_t EXTERNC void * __cdecl +typedef void * (__cdecl *pthread_handler)(void *); + +typedef volatile LONG my_pthread_once_t; +#define MY_PTHREAD_ONCE_INIT 0 +#define MY_PTHREAD_ONCE_INPROGRESS 1 +#define MY_PTHREAD_ONCE_DONE 2 + +/* + Struct and macros to be used in combination with the + windows implementation of pthread_cond_timedwait +*/ + +/* + Declare a union to make sure FILETIME is properly aligned + so it can be used directly as a 64 bit value. The value + stored is in 100ns units. + */ + union ft64 { + FILETIME ft; + __int64 i64; + }; +struct timespec { + union ft64 tv; + /* The max timeout value in millisecond for pthread_cond_timedwait */ + long max_timeout_msec; +}; +#define set_timespec(ABSTIME,SEC) { \ + GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \ + (ABSTIME).tv.i64+= (__int64)(SEC)*10000000; \ + (ABSTIME).max_timeout_msec= (long)((SEC)*1000); \ +} +#define set_timespec_nsec(ABSTIME,NSEC) { \ + GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \ + (ABSTIME).tv.i64+= (__int64)(NSEC)/100; \ + (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \ +} + +/** + Compare two timespec structs. + + @retval 1 If TS1 ends after TS2. + + @retval 0 If TS1 is equal to TS2. + + @retval -1 If TS1 ends before TS2. +*/ +#define cmp_timespec(TS1, TS2) \ + ((TS1.tv.i64 > TS2.tv.i64) ? 1 : \ + ((TS1.tv.i64 < TS2.tv.i64) ? -1 : 0)) + + +int win_pthread_mutex_trylock(pthread_mutex_t *mutex); +int pthread_create(pthread_t *, const pthread_attr_t *, pthread_handler, void *); +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_cond_destroy(pthread_cond_t *cond); +int pthread_attr_init(pthread_attr_t *connect_att); +int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack); +int pthread_attr_destroy(pthread_attr_t *connect_att); +int my_pthread_once(my_pthread_once_t *once_control,void (*init_routine)(void)); +struct tm *localtime_r(const time_t *timep,struct tm *tmp); +struct tm *gmtime_r(const time_t *timep,struct tm *tmp); + +void pthread_exit(void *a); +int pthread_join(pthread_t thread, void **value_ptr); +int pthread_cancel(pthread_t thread); + +#ifndef ETIMEDOUT +#define ETIMEDOUT 145 /* Win32 doesn't have this */ +#endif +#define HAVE_LOCALTIME_R 1 +#define _REENTRANT 1 +#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 + + +#undef SAFE_MUTEX /* This will cause conflicts */ +#define pthread_key(T,V) DWORD V +#define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) +#define pthread_key_delete(A) TlsFree(A) +#define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) +#define pthread_setspecific(A,B) (!TlsSetValue((A),(B))) +#define pthread_getspecific(A) (TlsGetValue(A)) +#define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) +#define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) + +#define pthread_equal(A,B) ((A) == (B)) +#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) +#define pthread_mutex_lock(A) (EnterCriticalSection(A),0) +#define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A)) +#define pthread_mutex_unlock(A) (LeaveCriticalSection(A), 0) +#define pthread_mutex_destroy(A) (DeleteCriticalSection(A), 0) +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) + + +/* Dummy defines for easier code */ +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_attr_setscope(A,B) +#define pthread_detach_this_thread() +#define pthread_condattr_init(A) +#define pthread_condattr_destroy(A) +#define pthread_yield() SwitchToThread() +#define my_sigset(A,B) signal(A,B) + +#else /* Normal threads */ + +#ifdef HAVE_rts_threads +#define sigwait org_sigwait +#include +#undef sigwait +#endif +#include +#ifndef _REENTRANT +#define _REENTRANT +#endif +#ifdef HAVE_THR_SETCONCURRENCY +#include /* Probably solaris */ +#endif +#ifdef HAVE_SCHED_H +#include +#endif +#ifdef HAVE_SYNCH_H +#include +#endif + +#define pthread_key(T,V) pthread_key_t V +#define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) +#define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) +#define pthread_detach_this_thread() +#define pthread_handler_t EXTERNC void * +typedef void *(* pthread_handler)(void *); + +#define my_pthread_once_t pthread_once_t +#if defined(PTHREAD_ONCE_INITIALIZER) +#define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INITIALIZER +#else +#define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT +#endif +#define my_pthread_once(C,F) pthread_once(C,F) + +/* Test first for RTS or FSU threads */ + +#if defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) +#define HAVE_rts_threads +extern int my_pthread_create_detached; +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define PTHREAD_CREATE_DETACHED &my_pthread_create_detached +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL +#define USE_ALARM_THREAD +#endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */ + +#if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910 +int sigwait(sigset_t *set, int *sig); +#endif + +#ifndef HAVE_NONPOSIX_SIGWAIT +#define my_sigwait(A,B) sigwait((A),(B)) +#else +int my_sigwait(const sigset_t *set,int *sig); +#endif + +#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT +#ifndef SAFE_MUTEX +#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b)) +extern int my_pthread_mutex_init(pthread_mutex_t *mp, + const pthread_mutexattr_t *attr); +#endif /* SAFE_MUTEX */ +#define pthread_cond_init(a,b) my_pthread_cond_init((a),(b)) +extern int my_pthread_cond_init(pthread_cond_t *mp, + const pthread_condattr_t *attr); +#endif /* HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */ + +#if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK) +#define pthread_sigmask(A,B,C) sigthreadmask((A),(B),(C)) +#endif + +#if !defined(HAVE_SIGWAIT) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX) +int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */ +#endif + + +/* + We define my_sigset() and use that instead of the system sigset() so that + we can favor an implementation based on sigaction(). On some systems, such + as Mac OS X, sigset() results in flags such as SA_RESTART being set, and + we want to make sure that no such flags are set. +*/ +#if defined(HAVE_SIGACTION) && !defined(my_sigset) +#define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; \ + DBUG_ASSERT((A) != 0); \ + sigemptyset(&l_set); \ + l_s.sa_handler = (B); \ + l_s.sa_mask = l_set; \ + l_s.sa_flags = 0; \ + sigaction((A), &l_s, NULL); \ + } while (0) +#elif defined(HAVE_SIGSET) && !defined(my_sigset) +#define my_sigset(A,B) sigset((A),(B)) +#elif !defined(my_sigset) +#define my_sigset(A,B) signal((A),(B)) +#endif + +#if !defined(HAVE_PTHREAD_ATTR_SETSCOPE) || defined(HAVE_DEC_3_2_THREADS) +#define pthread_attr_setscope(A,B) +#undef HAVE_GETHOSTBYADDR_R /* No definition */ +#endif + +#if defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT) && !defined(SAFE_MUTEX) +extern int my_pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + struct timespec *abstime); +#define pthread_cond_timedwait(A,B,C) my_pthread_cond_timedwait((A),(B),(C)) +#endif + +#if !defined( HAVE_NONPOSIX_PTHREAD_GETSPECIFIC) +#define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B)) +#else +#define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B)) +void *my_pthread_getspecific_imp(pthread_key_t key); +#endif + +#ifndef HAVE_LOCALTIME_R +struct tm *localtime_r(const time_t *clock, struct tm *res); +#endif + +#ifndef HAVE_GMTIME_R +struct tm *gmtime_r(const time_t *clock, struct tm *res); +#endif + +#ifdef HAVE_PTHREAD_CONDATTR_CREATE +/* DCE threads on HPUX 10.20 */ +#define pthread_condattr_init pthread_condattr_create +#define pthread_condattr_destroy pthread_condattr_delete +#endif + +/* FSU THREADS */ +#if !defined(HAVE_PTHREAD_KEY_DELETE) && !defined(pthread_key_delete) +#define pthread_key_delete(A) pthread_dummy(0) +#endif + +#ifdef HAVE_CTHREADS_WRAPPER /* For MacOSX */ +#define pthread_cond_destroy(A) pthread_dummy(0) +#define pthread_mutex_destroy(A) pthread_dummy(0) +#define pthread_attr_delete(A) pthread_dummy(0) +#define pthread_condattr_delete(A) pthread_dummy(0) +#define pthread_attr_setstacksize(A,B) pthread_dummy(0) +#define pthread_equal(A,B) ((A) == (B)) +#define pthread_cond_timedwait(a,b,c) pthread_cond_wait((a),(b)) +#define pthread_attr_init(A) pthread_attr_create(A) +#define pthread_attr_destroy(A) pthread_attr_delete(A) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } +#endif + +#ifdef HAVE_DARWIN5_THREADS +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) +#define pthread_condattr_init(A) pthread_dummy(0) +#define pthread_condattr_destroy(A) pthread_dummy(0) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(tmp); } +#endif + +#if ((defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT)) || defined(HAVE_DEC_3_2_THREADS)) && !defined(HAVE_CTHREADS_WRAPPER) +/* This is set on AIX_3_2 and Siemens unix (and DEC OSF/1 3.2 too) */ +#define pthread_key_create(A,B) \ + pthread_keycreate(A,(B) ?\ + (pthread_destructor_t) (B) :\ + (pthread_destructor_t) pthread_dummy) +#define pthread_attr_init(A) pthread_attr_create(A) +#define pthread_attr_destroy(A) pthread_attr_delete(A) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) +#ifndef pthread_sigmask +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#endif +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } +#else /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */ +#define HAVE_PTHREAD_KILL +#endif + +#endif /* defined(__WIN__) */ + +#if defined(HPUX10) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_cond_timedwait +#define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c)) +int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +#endif + +#if defined(HPUX10) +#define pthread_attr_getstacksize(A,B) my_pthread_attr_getstacksize(A,B) +void my_pthread_attr_getstacksize(pthread_attr_t *attrib, size_t *size); +#endif + +#if defined(HAVE_POSIX1003_4a_MUTEX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_mutex_trylock +#define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a)) +int my_pthread_mutex_trylock(pthread_mutex_t *mutex); +#endif + +#if !defined(HAVE_PTHREAD_YIELD_ONE_ARG) && !defined(HAVE_PTHREAD_YIELD_ZERO_ARG) +/* no pthread_yield() available */ +#ifdef HAVE_SCHED_YIELD +#define pthread_yield() sched_yield() +#elif defined(HAVE_PTHREAD_YIELD_NP) /* can be Mac OS X */ +#define pthread_yield() pthread_yield_np() +#elif defined(HAVE_THR_YIELD) +#define pthread_yield() thr_yield() +#endif +#endif + +/* + The defines set_timespec and set_timespec_nsec should be used + for calculating an absolute time at which + pthread_cond_timedwait should timeout +*/ +#ifdef HAVE_TIMESPEC_TS_SEC +#ifndef set_timespec +#define set_timespec(ABSTIME,SEC) \ +{ \ + (ABSTIME).ts_sec=time(0) + (time_t) (SEC); \ + (ABSTIME).ts_nsec=0; \ +} +#endif /* !set_timespec */ +#ifndef set_timespec_nsec +#define set_timespec_nsec(ABSTIME,NSEC) \ +{ \ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).ts_sec= (now / ULL(10000000)); \ + (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ +} +#endif /* !set_timespec_nsec */ +#else +#ifndef set_timespec +#define set_timespec(ABSTIME,SEC) \ +{\ + struct timeval tv;\ + gettimeofday(&tv,0);\ + (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\ + (ABSTIME).tv_nsec=tv.tv_usec*1000;\ +} +#endif /* !set_timespec */ +#ifndef set_timespec_nsec +#define set_timespec_nsec(ABSTIME,NSEC) \ +{\ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).tv_sec= (time_t) (now / ULL(10000000)); \ + (ABSTIME).tv_nsec= (long) (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ +} +#endif /* !set_timespec_nsec */ +#endif /* HAVE_TIMESPEC_TS_SEC */ + +/** + Compare two timespec structs. + + @retval 1 If TS1 ends after TS2. + + @retval 0 If TS1 is equal to TS2. + + @retval -1 If TS1 ends before TS2. +*/ +#ifdef HAVE_TIMESPEC_TS_SEC +#ifndef cmp_timespec +#define cmp_timespec(TS1, TS2) \ + ((TS1.ts_sec > TS2.ts_sec || \ + (TS1.ts_sec == TS2.ts_sec && TS1.ts_nsec > TS2.ts_nsec)) ? 1 : \ + ((TS1.ts_sec < TS2.ts_sec || \ + (TS1.ts_sec == TS2.ts_sec && TS1.ts_nsec < TS2.ts_nsec)) ? -1 : 0)) +#endif /* !cmp_timespec */ +#else +#ifndef cmp_timespec +#define cmp_timespec(TS1, TS2) \ + ((TS1.tv_sec > TS2.tv_sec || \ + (TS1.tv_sec == TS2.tv_sec && TS1.tv_nsec > TS2.tv_nsec)) ? 1 : \ + ((TS1.tv_sec < TS2.tv_sec || \ + (TS1.tv_sec == TS2.tv_sec && TS1.tv_nsec < TS2.tv_nsec)) ? -1 : 0)) +#endif /* !cmp_timespec */ +#endif /* HAVE_TIMESPEC_TS_SEC */ + + /* safe_mutex adds checking to mutex for easier debugging */ + +typedef struct st_safe_mutex_t +{ + pthread_mutex_t global,mutex; + const char *file; + uint line,count; + pthread_t thread; +#ifdef SAFE_MUTEX_DETECT_DESTROY + struct st_safe_mutex_info_t *info; /* to track destroying of mutexes */ +#endif +} safe_mutex_t; + +#ifdef SAFE_MUTEX_DETECT_DESTROY +/* + Used to track the destroying of mutexes. This needs to be a seperate + structure because the safe_mutex_t structure could be freed before + the mutexes are destroyed. +*/ + +typedef struct st_safe_mutex_info_t +{ + struct st_safe_mutex_info_t *next; + struct st_safe_mutex_info_t *prev; + const char *init_file; + uint32 init_line; +} safe_mutex_info_t; +#endif /* SAFE_MUTEX_DETECT_DESTROY */ + +int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, + const char *file, uint line); +int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line); +int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); +int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); +int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, + uint line); +int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, + const struct timespec *abstime, + const char *file, uint line); +void safe_mutex_global_init(void); +void safe_mutex_end(FILE *file); + + /* Wrappers if safe mutex is actually used */ +#ifdef SAFE_MUTEX +#undef pthread_mutex_init +#undef pthread_mutex_lock +#undef pthread_mutex_unlock +#undef pthread_mutex_destroy +#undef pthread_mutex_wait +#undef pthread_mutex_timedwait +#undef pthread_mutex_t +#undef pthread_cond_wait +#undef pthread_cond_timedwait +#undef pthread_mutex_trylock +#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__) +#define pthread_mutex_lock(A) safe_mutex_lock((A), FALSE, __FILE__, __LINE__) +#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__) +#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) +#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) +#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) +#define pthread_mutex_trylock(A) safe_mutex_lock((A), TRUE, __FILE__, __LINE__) +#define pthread_mutex_t safe_mutex_t +#define safe_mutex_assert_owner(mp) \ + DBUG_ASSERT((mp)->count > 0 && \ + pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_assert_not_owner(mp) \ + DBUG_ASSERT(! (mp)->count || \ + ! pthread_equal(pthread_self(), (mp)->thread)) +#else +#define safe_mutex_assert_owner(mp) +#define safe_mutex_assert_not_owner(mp) +#endif /* SAFE_MUTEX */ + +#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) +typedef struct st_my_pthread_fastmutex_t +{ + pthread_mutex_t mutex; + uint spins; + uint rng_state; +} my_pthread_fastmutex_t; +void fastmutex_global_init(void); + +int my_pthread_fastmutex_init(my_pthread_fastmutex_t *mp, + const pthread_mutexattr_t *attr); +int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp); + +#undef pthread_mutex_init +#undef pthread_mutex_lock +#undef pthread_mutex_unlock +#undef pthread_mutex_destroy +#undef pthread_mutex_wait +#undef pthread_mutex_timedwait +#undef pthread_mutex_t +#undef pthread_cond_wait +#undef pthread_cond_timedwait +#undef pthread_mutex_trylock +#define pthread_mutex_init(A,B) my_pthread_fastmutex_init((A),(B)) +#define pthread_mutex_lock(A) my_pthread_fastmutex_lock(A) +#define pthread_mutex_unlock(A) pthread_mutex_unlock(&(A)->mutex) +#define pthread_mutex_destroy(A) pthread_mutex_destroy(&(A)->mutex) +#define pthread_cond_wait(A,B) pthread_cond_wait((A),&(B)->mutex) +#define pthread_cond_timedwait(A,B,C) pthread_cond_timedwait((A),&(B)->mutex,(C)) +#define pthread_mutex_trylock(A) pthread_mutex_trylock(&(A)->mutex) +#define pthread_mutex_t my_pthread_fastmutex_t +#endif /* defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) */ + + /* READ-WRITE thread locking */ + +#ifdef HAVE_BROKEN_RWLOCK /* For OpenUnix */ +#undef HAVE_PTHREAD_RWLOCK_RDLOCK +#undef HAVE_RWLOCK_INIT +#undef HAVE_RWLOCK_T +#endif + +#if defined(USE_MUTEX_INSTEAD_OF_RW_LOCKS) +/* use these defs for simple mutex locking */ +#define rw_lock_t pthread_mutex_t +#define my_rwlock_init(A,B) pthread_mutex_init((A),(B)) +#define rw_rdlock(A) pthread_mutex_lock((A)) +#define rw_wrlock(A) pthread_mutex_lock((A)) +#define rw_tryrdlock(A) pthread_mutex_trylock((A)) +#define rw_trywrlock(A) pthread_mutex_trylock((A)) +#define rw_unlock(A) pthread_mutex_unlock((A)) +#define rwlock_destroy(A) pthread_mutex_destroy((A)) +#elif defined(HAVE_PTHREAD_RWLOCK_RDLOCK) +#define rw_lock_t pthread_rwlock_t +#define my_rwlock_init(A,B) pthread_rwlock_init((A),(B)) +#define rw_rdlock(A) pthread_rwlock_rdlock(A) +#define rw_wrlock(A) pthread_rwlock_wrlock(A) +#define rw_tryrdlock(A) pthread_rwlock_tryrdlock((A)) +#define rw_trywrlock(A) pthread_rwlock_trywrlock((A)) +#define rw_unlock(A) pthread_rwlock_unlock(A) +#define rwlock_destroy(A) pthread_rwlock_destroy(A) +#elif defined(HAVE_RWLOCK_INIT) +#ifdef HAVE_RWLOCK_T /* For example Solaris 2.6-> */ +#define rw_lock_t rwlock_t +#endif +#define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) +#else +/* Use our own version of read/write locks */ +#define NEED_MY_RW_LOCK 1 +#define rw_lock_t my_rw_lock_t +#define my_rwlock_init(A,B) my_rw_init((A)) +#define rw_rdlock(A) my_rw_rdlock((A)) +#define rw_wrlock(A) my_rw_wrlock((A)) +#define rw_tryrdlock(A) my_rw_tryrdlock((A)) +#define rw_trywrlock(A) my_rw_trywrlock((A)) +#define rw_unlock(A) my_rw_unlock((A)) +#define rwlock_destroy(A) my_rw_destroy((A)) +#define rw_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A)) +#define rw_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A)) +#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ + + +/** + Portable implementation of special type of read-write locks. + + These locks have two properties which are unusual for rwlocks: + 1) They "prefer readers" in the sense that they do not allow + situations in which rwlock is rd-locked and there is a + pending rd-lock which is blocked (e.g. due to pending + request for wr-lock). + This is a stronger guarantee than one which is provided for + PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux. + MDL subsystem deadlock detector relies on this property for + its correctness. + 2) They are optimized for uncontended wr-lock/unlock case. + This is scenario in which they are most oftenly used + within MDL subsystem. Optimizing for it gives significant + performance improvements in some of tests involving many + connections. + + Another important requirement imposed on this type of rwlock + by the MDL subsystem is that it should be OK to destroy rwlock + object which is in unlocked state even though some threads might + have not yet fully left unlock operation for it (of course there + is an external guarantee that no thread will try to lock rwlock + which is destroyed). + Putting it another way the unlock operation should not access + rwlock data after changing its state to unlocked. + + TODO/FIXME: We should consider alleviating this requirement as + it blocks us from doing certain performance optimizations. +*/ + +typedef struct st_rw_pr_lock_t { + /** + Lock which protects the structure. + Also held for the duration of wr-lock. + */ + pthread_mutex_t lock; + /** + Condition variable which is used to wake-up + writers waiting for readers to go away. + */ + pthread_cond_t no_active_readers; + /** Number of active readers. */ + uint active_readers; + /** Number of writers waiting for readers to go away. */ + uint writers_waiting_readers; + /** Indicates whether there is an active writer. */ + my_bool active_writer; +#ifdef SAFE_MUTEX + /** Thread holding wr-lock (for debug purposes only). */ + pthread_t writer_thread; +#endif +} rw_pr_lock_t; + +extern int rw_pr_init(rw_pr_lock_t *); +extern int rw_pr_rdlock(rw_pr_lock_t *); +extern int rw_pr_wrlock(rw_pr_lock_t *); +extern int rw_pr_unlock(rw_pr_lock_t *); +extern int rw_pr_destroy(rw_pr_lock_t *); +#ifdef SAFE_MUTEX +#define rw_pr_lock_assert_write_owner(A) \ + DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \ + (A)->writer_thread)) +#define rw_pr_lock_assert_not_write_owner(A) \ + DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \ + (A)->writer_thread)) +#else +#define rw_pr_lock_assert_write_owner(A) +#define rw_pr_lock_assert_not_write_owner(A) +#endif /* SAFE_MUTEX */ + + +#ifdef NEED_MY_RW_LOCK + +#ifdef _WIN32 + +/** + Implementation of Windows rwlock. + + We use native (slim) rwlocks on Win7 and later, and fallback to portable + implementation on earlier Windows. + + slim rwlock are also available on Vista/WS2008, but we do not use it + ("trylock" APIs are missing on Vista) +*/ +typedef union +{ + /* Native rwlock (is_srwlock == TRUE) */ + struct + { + SRWLOCK srwlock; /* native reader writer lock */ + BOOL have_exclusive_srwlock; /* used for unlock */ + }; + + /* + Portable implementation (is_srwlock == FALSE) + Fields are identical with Unix my_rw_lock_t fields. + */ + struct + { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ +#ifdef SAFE_MUTEX + pthread_t write_thread; +#endif + }; +} my_rw_lock_t; + + +#else /* _WIN32 */ + +/* + On systems which don't support native read/write locks we have + to use own implementation. +*/ +typedef struct st_my_rw_lock_t { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ +#ifdef SAFE_MUTEX + pthread_t write_thread; +#endif +} my_rw_lock_t; + +#endif /*! _WIN32 */ + +extern int my_rw_init(my_rw_lock_t *); +extern int my_rw_destroy(my_rw_lock_t *); +extern int my_rw_rdlock(my_rw_lock_t *); +extern int my_rw_wrlock(my_rw_lock_t *); +extern int my_rw_unlock(my_rw_lock_t *); +extern int my_rw_tryrdlock(my_rw_lock_t *); +extern int my_rw_trywrlock(my_rw_lock_t *); +#ifdef SAFE_MUTEX +#define my_rw_lock_assert_write_owner(A) \ + DBUG_ASSERT((A)->state == -1 && pthread_equal(pthread_self(), \ + (A)->write_thread)) +#define my_rw_lock_assert_not_write_owner(A) \ + DBUG_ASSERT((A)->state >= 0 || ! pthread_equal(pthread_self(), \ + (A)->write_thread)) +#else +#define my_rw_lock_assert_write_owner(A) +#define my_rw_lock_assert_not_write_owner(A) +#endif +#endif /* NEED_MY_RW_LOCK */ + + +#define GETHOSTBYADDR_BUFF_SIZE 2048 + +#ifndef HAVE_THR_SETCONCURRENCY +#define thr_setconcurrency(A) pthread_dummy(0) +#endif +#if !defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && ! defined(pthread_attr_setstacksize) +#define pthread_attr_setstacksize(A,B) pthread_dummy(0) +#endif + +/* Define mutex types, see my_thr_init.c */ +#define MY_MUTEX_INIT_SLOW NULL +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_fast_mutexattr; +#define MY_MUTEX_INIT_FAST &my_fast_mutexattr +#else +#define MY_MUTEX_INIT_FAST NULL +#endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_errorcheck_mutexattr; +#define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr +#else +#define MY_MUTEX_INIT_ERRCHK NULL +#endif + +#ifndef ESRCH +/* Define it to something */ +#define ESRCH 1 +#endif + +typedef ulong my_thread_id; + +extern my_bool my_thread_global_init(void); +extern my_bool my_thread_basic_global_init(void); +extern void my_thread_basic_global_reinit(void); +extern void my_thread_global_end(void); +extern my_bool my_thread_init(void); +extern void my_thread_end(void); +extern const char *my_thread_name(void); +extern my_thread_id my_thread_dbug_id(void); +extern int pthread_dummy(int); + +/* All thread specific variables are in the following struct */ + +#define THREAD_NAME_SIZE 10 +#ifndef DEFAULT_THREAD_STACK +#if SIZEOF_CHARP > 4 +/* + MySQL can survive with 32K, but some glibc libraries require > 128K stack + To resolve hostnames. Also recursive stored procedures needs stack. +*/ +#define DEFAULT_THREAD_STACK (256*1024L) +#else +#define DEFAULT_THREAD_STACK (192*1024) +#endif +#endif + +#include + +#define INSTRUMENT_ME 0 + +struct st_my_thread_var +{ + int thr_errno; + mysql_cond_t suspend; + mysql_mutex_t mutex; + mysql_mutex_t * volatile current_mutex; + mysql_cond_t * volatile current_cond; + pthread_t pthread_self; + my_thread_id id; + int cmp_length; + int volatile abort; + my_bool init; + struct st_my_thread_var *next,**prev; + void *opt_info; + void *stack_ends_here; +#ifndef DBUG_OFF + void *dbug; + char name[THREAD_NAME_SIZE+1]; +#endif +}; + +extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const)); +extern void **my_thread_var_dbug(); +extern uint my_thread_end_wait_time; +#define my_thread_var (_my_thread_var()) +#define my_errno my_thread_var->thr_errno +/* + Keep track of shutdown,signal, and main threads so that my_end() will not + report errors with them +*/ + +/* Which kind of thread library is in use */ + +#define THD_LIB_OTHER 1 +#define THD_LIB_NPTL 2 +#define THD_LIB_LT 4 + +extern uint thd_lib_detected; + +/* + thread_safe_xxx functions are for critical statistic or counters. + The implementation is guaranteed to be thread safe, on all platforms. + Note that the calling code should *not* assume the counter is protected + by the mutex given, as the implementation of these helpers may change + to use my_atomic operations instead. +*/ + +#ifndef thread_safe_increment +#ifdef _WIN32 +#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) +#define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) +#else +#define thread_safe_increment(V,L) \ + (mysql_mutex_lock((L)), (V)++, mysql_mutex_unlock((L))) +#define thread_safe_decrement(V,L) \ + (mysql_mutex_lock((L)), (V)--, mysql_mutex_unlock((L))) +#endif +#endif + +#ifndef thread_safe_add +#ifdef _WIN32 +#define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) +#define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C)) +#else +#define thread_safe_add(V,C,L) \ + (mysql_mutex_lock((L)), (V)+=(C), mysql_mutex_unlock((L))) +#define thread_safe_sub(V,C,L) \ + (mysql_mutex_lock((L)), (V)-=(C), mysql_mutex_unlock((L))) +#endif +#endif + + +/* + statistics_xxx functions are for non critical statistic, + maintained in global variables. + When compiling with SAFE_STATISTICS: + - race conditions can not occur. + - some locking occurs, which may cause performance degradation. + + When compiling without SAFE_STATISTICS: + - race conditions can occur, making the result slightly inaccurate. + - the lock given is not honored. +*/ +#ifdef SAFE_STATISTICS +#define statistic_increment(V,L) thread_safe_increment((V),(L)) +#define statistic_decrement(V,L) thread_safe_decrement((V),(L)) +#define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) +#define statistic_sub(V,C,L) thread_safe_sub((V),(C),(L)) +#else +#define statistic_decrement(V,L) (V)-- +#define statistic_increment(V,L) (V)++ +#define statistic_add(V,C,L) (V)+=(C) +#define statistic_sub(V,C,L) (V)-=(C) +#endif /* SAFE_STATISTICS */ + +/* + No locking needed, the counter is owned by the thread +*/ +#define status_var_increment(V) (V)++ +#define status_var_decrement(V) (V)-- +#define status_var_add(V,C) (V)+=(C) +#define status_var_sub(V,C) (V)-=(C) + +#ifdef __cplusplus +} +#endif +#endif /* _my_ptread_h */ diff --git a/code/meosdb/mysql55/my_sys.h b/code/meosdb/mysql55/my_sys.h new file mode 100644 index 0000000..103d002 --- /dev/null +++ b/code/meosdb/mysql55/my_sys.h @@ -0,0 +1,959 @@ +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_sys_h +#define _my_sys_h + +#include "my_global.h" /* C_MODE_START, C_MODE_END */ + +C_MODE_START + +#ifdef HAVE_AIOWAIT +#include /* Used by record-cache */ +typedef struct my_aio_result { + aio_result_t result; + int pending; +} my_aio_result; +#endif + +#ifdef HAVE_VALGRIND +# include +# define MEM_UNDEFINED(a,len) VALGRIND_MAKE_MEM_UNDEFINED(a,len) +# define MEM_NOACCESS(a,len) VALGRIND_MAKE_MEM_NOACCESS(a,len) +# define MEM_CHECK_ADDRESSABLE(a,len) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,len) +# define MEM_CHECK_DEFINED(a,len) VALGRIND_CHECK_MEM_IS_DEFINED(a,len) +#else /* HAVE_VALGRIND */ +# define MEM_UNDEFINED(a,len) ((void) 0) +# define MEM_NOACCESS(a,len) ((void) 0) +# define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0) +# define MEM_CHECK_DEFINED(a,len) ((void) 0) +#endif /* HAVE_VALGRIND */ + +#include + +#include /* for CHARSET_INFO */ +#include +#include +#ifdef _WIN32 +#include /*for alloca*/ +#endif + +#define MY_INIT(name) { my_progname= name; my_init(); } + +/** + Max length of an error message generated by mysys utilities. + Some mysys functions produce error messages. These mostly go + to stderr. + This constant defines the size of the buffer used to format + the message. It should be kept in sync with MYSQL_ERRMSG_SIZE, + since sometimes mysys errors are stored in the server diagnostics + area, and we would like to avoid unexpected truncation. +*/ +#define MYSYS_ERRMSG_SIZE (512) + +#define MY_FILE_ERROR ((size_t) -1) + + /* General bitmaps for my_func's */ +#define MY_FFNF 1 /* Fatal if file not found */ +#define MY_FNABP 2 /* Fatal if not all bytes read/writen */ +#define MY_NABP 4 /* Error if not all bytes read/writen */ +#define MY_FAE 8 /* Fatal if any error */ +#define MY_WME 16 /* Write message on error */ +#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */ +#define MY_IGNORE_BADFD 32 /* my_sync: ignore 'bad descriptor' errors */ +#define MY_SYNC_DIR 8192 /* my_create/delete/rename: sync directory */ +#define MY_UNUSED 64 /* Unused (was support for RAID) */ +#define MY_FULL_IO 512 /* For my_read - loop intil I/O is complete */ +#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */ +#define MY_LINK_WARNING 32 /* my_redel() gives warning if links */ +#define MY_COPYTIME 64 /* my_redel() copys time */ +#define MY_DELETE_OLD 256 /* my_create_with_symlink() */ +#define MY_RESOLVE_LINK 128 /* my_realpath(); Only resolve links */ +#define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */ +#define MY_REDEL_MAKE_BACKUP 256 +#define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */ +#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */ +#define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */ +#define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */ +#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */ +#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ +#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy: Don't overwrite file */ +#define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ +#define MY_SYNC 4096 /* my_copy(): sync dst file */ + +#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ +#define MY_GIVE_INFO 2 /* Give time info about process*/ +#define MY_DONT_FREE_DBUG 4 /* Do not call DBUG_END() in my_end() */ + +#define ME_HIGHBYTE 8 /* Shift for colours */ +#define ME_NOCUR 1 /* Don't use curses message */ +#define ME_OLDWIN 2 /* Use old window */ +#define ME_BELL 4 /* Ring bell then printing message */ +#define ME_HOLDTANG 8 /* Don't delete last keys */ +#define ME_WAITTOT 16 /* Wait for errtime secs of for a action */ +#define ME_WAITTANG 32 /* Wait for a user action */ +#define ME_NOREFRESH 64 /* Dont refresh screen */ +#define ME_NOINPUT 128 /* Dont use the input libary */ +#define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */ +#define ME_COLOUR2 ((2 << ME_HIGHBYTE)) +#define ME_COLOUR3 ((3 << ME_HIGHBYTE)) +#define ME_FATALERROR 1024 /* Fatal statement error */ + + /* Bits in last argument to fn_format */ +#define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */ +#define MY_REPLACE_EXT 2 /* replace extension with 'ext' */ +#define MY_UNPACK_FILENAME 4 /* Unpack name (~ -> home) */ +#define MY_PACK_FILENAME 8 /* Pack name (home -> ~) */ +#define MY_RESOLVE_SYMLINKS 16 /* Resolve all symbolic links */ +#define MY_RETURN_REAL_PATH 32 /* return full path for file */ +#define MY_SAFE_PATH 64 /* Return NULL if too long path */ +#define MY_RELATIVE_PATH 128 /* name is relative to 'dir' */ +#define MY_APPEND_EXT 256 /* add 'ext' as additional extension*/ + + + /* My seek flags */ +#define MY_SEEK_SET 0 +#define MY_SEEK_CUR 1 +#define MY_SEEK_END 2 + + /* Some constants */ +#define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */ +#define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */ +#define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */ +#define DFLT_INIT_HITS 3 + + /* root_alloc flags */ +#define MY_KEEP_PREALLOC 1 +#define MY_MARK_BLOCKS_FREE 2 /* move used to free list and reuse them */ + + /* Internal error numbers (for assembler functions) */ +#define MY_ERRNO_EDOM 33 +#define MY_ERRNO_ERANGE 34 + + /* Bits for get_date timeflag */ +#define GETDATE_DATE_TIME 1 +#define GETDATE_SHORT_DATE 2 +#define GETDATE_HHMMSSTIME 4 +#define GETDATE_GMT 8 +#define GETDATE_FIXEDLENGTH 16 + + /* defines when allocating data */ +extern void *my_malloc(size_t Size,myf MyFlags); +extern void *my_multi_malloc(myf MyFlags, ...); +extern void *my_realloc(void *oldpoint, size_t Size, myf MyFlags); +extern void my_free(void *ptr); +extern void *my_memdup(const void *from,size_t length,myf MyFlags); +extern char *my_strdup(const char *from,myf MyFlags); +extern char *my_strndup(const char *from, size_t length, + myf MyFlags); +#define TRASH(A,B) do{MEM_CHECK_ADDRESSABLE(A,B);MEM_UNDEFINED(A,B);} while (0) +#if defined(ENABLED_DEBUG_SYNC) +extern void (*debug_sync_C_callback_ptr)(const char *, size_t); +#define DEBUG_SYNC_C(_sync_point_name_) do { \ + if (debug_sync_C_callback_ptr != NULL) \ + (*debug_sync_C_callback_ptr)(STRING_WITH_LEN(_sync_point_name_)); } \ + while(0) +#else +#define DEBUG_SYNC_C(_sync_point_name_) +#endif /* defined(ENABLED_DEBUG_SYNC) */ + +#ifdef HAVE_LARGE_PAGES +extern uint my_get_large_page_size(void); +extern uchar * my_large_malloc(size_t size, myf my_flags); +extern void my_large_free(uchar *ptr); +#else +#define my_get_large_page_size() (0) +#define my_large_malloc(A,B) my_malloc_lock((A),(B)) +#define my_large_free(A) my_free_lock((A)) +#endif /* HAVE_LARGE_PAGES */ + +#ifdef HAVE_ALLOCA +#if defined(_AIX) && !defined(__GNUC__) && !defined(_AIX43) +#pragma alloca +#endif /* _AIX */ +#if defined(__MWERKS__) +#undef alloca +#define alloca _alloca +#endif /* __MWERKS__ */ +#if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) && ! defined(alloca) +#define alloca __builtin_alloca +#endif /* GNUC */ +#define my_alloca(SZ) alloca((size_t) (SZ)) +#define my_afree(PTR) {} +#else +#define my_alloca(SZ) my_malloc(SZ,MYF(MY_FAE)) +#define my_afree(PTR) my_free(PTR) +#endif /* HAVE_ALLOCA */ + +#ifndef errno /* did we already get it? */ +#ifdef HAVE_ERRNO_AS_DEFINE +#include /* errno is a define */ +#else +extern int errno; /* declare errno */ +#endif +#endif /* #ifndef errno */ +extern char *home_dir; /* Home directory for user */ +extern const char *my_progname; /* program-name (printed in errors) */ +extern char curr_dir[]; /* Current directory for user */ +extern void (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); +extern void (*fatal_error_handler_hook)(uint my_err, const char *str, + myf MyFlags); +extern uint my_file_limit; +extern ulong my_thread_stack_size; + +extern const char *(*proc_info_hook)(void *, const char *, const char *, + const char *, const unsigned int); + +#ifdef HAVE_LARGE_PAGES +extern my_bool my_use_large_pages; +extern uint my_large_page_size; +#endif + +/* charsets */ +#define MY_ALL_CHARSETS_SIZE 2048 +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *default_charset_info; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *all_charsets[MY_ALL_CHARSETS_SIZE]; +extern CHARSET_INFO compiled_charsets[]; + +/* statistics */ +extern ulong my_file_opened,my_stream_opened, my_tmp_file_created; +extern ulong my_file_total_opened; +extern uint mysys_usage_id; +extern my_bool my_init_done; + + /* Point to current my_message() */ +extern void (*my_sigtstp_cleanup)(void), + /* Executed before jump to shell */ + (*my_sigtstp_restart)(void), + (*my_abort_hook)(int); + /* Executed when comming from shell */ +extern MYSQL_PLUGIN_IMPORT int my_umask; /* Default creation mask */ +extern int my_umask_dir, + my_recived_signals, /* Signals we have got */ + my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ + my_dont_interrupt; /* call remember_intr when set */ +extern my_bool my_use_symdir; + +extern ulong my_default_record_cache_size; +extern my_bool my_disable_locking, my_disable_async_io, + my_disable_flush_key_blocks, my_disable_symlinks; +extern char wild_many,wild_one,wild_prefix; +extern const char *charsets_dir; +/* from default.c */ +extern const char *my_defaults_extra_file; +extern const char *my_defaults_group_suffix; +extern const char *my_defaults_file; + +extern my_bool timed_mutexes; + +enum loglevel { + ERROR_LEVEL, + WARNING_LEVEL, + INFORMATION_LEVEL +}; + +enum cache_type +{ + TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE, + SEQ_READ_APPEND /* sequential read or append */, + READ_FIFO, READ_NET,WRITE_NET}; + +enum flush_type +{ + FLUSH_KEEP, /* flush block and keep it in the cache */ + FLUSH_RELEASE, /* flush block and remove it from the cache */ + FLUSH_IGNORE_CHANGED, /* remove block from the cache */ + /* + As my_disable_flush_pagecache_blocks is always 0, the following option + is strictly equivalent to FLUSH_KEEP + */ + FLUSH_FORCE_WRITE +}; + +typedef struct st_record_cache /* Used when cacheing records */ +{ + File file; + int rc_seek,error,inited; + uint rc_length,read_length,reclength; + my_off_t rc_record_pos,end_of_file; + uchar *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos; +#ifdef HAVE_AIOWAIT + int use_async_io; + my_aio_result aio_result; +#endif + enum cache_type type; +} RECORD_CACHE; + +enum file_type +{ + UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, STREAM_BY_FOPEN, STREAM_BY_FDOPEN, + FILE_BY_MKSTEMP, FILE_BY_DUP +}; + +struct st_my_file_info +{ + char *name; +#ifdef _WIN32 + HANDLE fhandle; /* win32 file handle */ + int oflag; /* open flags, e.g O_APPEND */ +#endif + enum file_type type; +#if !defined(HAVE_PREAD) && !defined(_WIN32) + mysql_mutex_t mutex; +#endif +}; + +extern struct st_my_file_info *my_file_info; + +typedef struct st_dynamic_array +{ + uchar *buffer; + uint elements,max_element; + uint alloc_increment; + uint size_of_element; +} DYNAMIC_ARRAY; + +typedef struct st_my_tmpdir +{ + DYNAMIC_ARRAY full_list; + char **list; + uint cur, max; + mysql_mutex_t mutex; +} MY_TMPDIR; + +typedef struct st_dynamic_string +{ + char *str; + size_t length,max_length,alloc_increment; +} DYNAMIC_STRING; + +struct st_io_cache; +typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*); + +typedef struct st_io_cache_share +{ + mysql_mutex_t mutex; /* To sync on reads into buffer. */ + mysql_cond_t cond; /* To wait for signals. */ + mysql_cond_t cond_writer; /* For a synchronized writer. */ + /* Offset in file corresponding to the first byte of buffer. */ + my_off_t pos_in_file; + /* If a synchronized write cache is the source of the data. */ + struct st_io_cache *source_cache; + uchar *buffer; /* The read buffer. */ + uchar *read_end; /* Behind last valid byte of buffer. */ + int running_threads; /* threads not in lock. */ + int total_threads; /* threads sharing the cache. */ + int error; /* Last error. */ +#ifdef NOT_YET_IMPLEMENTED + /* whether the structure should be free'd */ + my_bool alloced; +#endif +} IO_CACHE_SHARE; + +typedef struct st_io_cache /* Used when cacheing files */ +{ + /* Offset in file corresponding to the first byte of uchar* buffer. */ + my_off_t pos_in_file; + /* + The offset of end of file for READ_CACHE and WRITE_CACHE. + For SEQ_READ_APPEND it the maximum of the actual end of file and + the position represented by read_end. + */ + my_off_t end_of_file; + /* Points to current read position in the buffer */ + uchar *read_pos; + /* the non-inclusive boundary in the buffer for the currently valid read */ + uchar *read_end; + uchar *buffer; /* The read buffer */ + /* Used in ASYNC_IO */ + uchar *request_pos; + + /* Only used in WRITE caches and in SEQ_READ_APPEND to buffer writes */ + uchar *write_buffer; + /* + Only used in SEQ_READ_APPEND, and points to the current read position + in the write buffer. Note that reads in SEQ_READ_APPEND caches can + happen from both read buffer (uchar* buffer) and write buffer + (uchar* write_buffer). + */ + uchar *append_read_pos; + /* Points to current write position in the write buffer */ + uchar *write_pos; + /* The non-inclusive boundary of the valid write area */ + uchar *write_end; + + /* + Current_pos and current_end are convenience variables used by + my_b_tell() and other routines that need to know the current offset + current_pos points to &write_pos, and current_end to &write_end in a + WRITE_CACHE, and &read_pos and &read_end respectively otherwise + */ + uchar **current_pos, **current_end; + + /* + The lock is for append buffer used in SEQ_READ_APPEND cache + need mutex copying from append buffer to read buffer. + */ + mysql_mutex_t append_buffer_lock; + /* + The following is used when several threads are reading the + same file in parallel. They are synchronized on disk + accesses reading the cached part of the file asynchronously. + It should be set to NULL to disable the feature. Only + READ_CACHE mode is supported. + */ + IO_CACHE_SHARE *share; + + /* + A caller will use my_b_read() macro to read from the cache + if the data is already in cache, it will be simply copied with + memcpy() and internal variables will be accordinging updated with + no functions invoked. However, if the data is not fully in the cache, + my_b_read() will call read_function to fetch the data. read_function + must never be invoked directly. + */ + int (*read_function)(struct st_io_cache *,uchar *,size_t); + /* + Same idea as in the case of read_function, except my_b_write() needs to + be replaced with my_b_append() for a SEQ_READ_APPEND cache + */ + int (*write_function)(struct st_io_cache *,const uchar *,size_t); + /* + Specifies the type of the cache. Depending on the type of the cache + certain operations might not be available and yield unpredicatable + results. Details to be documented later + */ + enum cache_type type; + /* + Callbacks when the actual read I/O happens. These were added and + are currently used for binary logging of LOAD DATA INFILE - when a + block is read from the file, we create a block create/append event, and + when IO_CACHE is closed, we create an end event. These functions could, + of course be used for other things + */ + IO_CACHE_CALLBACK pre_read; + IO_CACHE_CALLBACK post_read; + IO_CACHE_CALLBACK pre_close; + /* + Counts the number of times, when we were forced to use disk. We use it to + increase the binlog_cache_disk_use and binlog_stmt_cache_disk_use status + variables. + */ + ulong disk_writes; + void* arg; /* for use by pre/post_read */ + char *file_name; /* if used with 'open_cached_file' */ + char *dir,*prefix; + File file; /* file descriptor */ + /* + seek_not_done is set by my_b_seek() to inform the upcoming read/write + operation that a seek needs to be preformed prior to the actual I/O + error is 0 if the cache operation was successful, -1 if there was a + "hard" error, and the actual number of I/O-ed bytes if the read/write was + partial. + */ + int seek_not_done,error; + /* buffer_length is memory size allocated for buffer or write_buffer */ + size_t buffer_length; + /* read_length is the same as buffer_length except when we use async io */ + size_t read_length; + myf myflags; /* Flags used to my_read/my_write */ + /* + alloced_buffer is 1 if the buffer was allocated by init_io_cache() and + 0 if it was supplied by the user. + Currently READ_NET is the only one that will use a buffer allocated + somewhere else + */ + my_bool alloced_buffer; +#ifdef HAVE_AIOWAIT + /* + As inidicated by ifdef, this is for async I/O, which is not currently + used (because it's not reliable on all systems) + */ + uint inited; + my_off_t aio_read_pos; + my_aio_result aio_result; +#endif +} IO_CACHE; + +typedef int (*qsort2_cmp)(const void *, const void *, const void *); + + /* defines for mf_iocache */ + + /* Test if buffer is inited */ +#define my_b_clear(info) (info)->buffer=0 +#define my_b_inited(info) (info)->buffer +#define my_b_EOF INT_MIN + +#define my_b_read(info,Buffer,Count) \ + ((info)->read_pos + (Count) <= (info)->read_end ?\ + (memcpy(Buffer,(info)->read_pos,(size_t) (Count)), \ + ((info)->read_pos+=(Count)),0) :\ + (*(info)->read_function)((info),Buffer,Count)) + +#define my_b_write(info,Buffer,Count) \ + ((info)->write_pos + (Count) <=(info)->write_end ?\ + (memcpy((info)->write_pos, (Buffer), (size_t)(Count)),\ + ((info)->write_pos+=(Count)),0) : \ + (*(info)->write_function)((info),(uchar *)(Buffer),(Count))) + +#define my_b_get(info) \ + ((info)->read_pos != (info)->read_end ?\ + ((info)->read_pos++, (int) (uchar) (info)->read_pos[-1]) :\ + _my_b_get(info)) + + /* my_b_write_byte dosn't have any err-check */ +#define my_b_write_byte(info,chr) \ + (((info)->write_pos < (info)->write_end) ?\ + ((*(info)->write_pos++)=(chr)) :\ + (_my_b_write(info,0,0) , ((*(info)->write_pos++)=(chr)))) + +#define my_b_fill_cache(info) \ + (((info)->read_end=(info)->read_pos),(*(info)->read_function)(info,0,0)) + +#define my_b_tell(info) ((info)->pos_in_file + \ + (size_t) (*(info)->current_pos - (info)->request_pos)) + +#define my_b_get_buffer_start(info) (info)->request_pos +#define my_b_get_bytes_in_buffer(info) (char*) (info)->read_end - \ + (char*) my_b_get_buffer_start(info) +#define my_b_get_pos_in_file(info) (info)->pos_in_file + +/* tell write offset in the SEQ_APPEND cache */ +int my_b_copy_to_file(IO_CACHE *cache, FILE *file); +my_off_t my_b_append_tell(IO_CACHE* info); +my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ + +#define my_b_bytes_in_cache(info) (size_t) (*(info)->current_end - \ + *(info)->current_pos) + +typedef uint32 ha_checksum; + +/* Define the type of function to be passed to process_default_option_files */ +typedef int (*Process_option_func)(void *ctx, const char *group_name, + const char *option); + +#include + + + /* Prototypes for mysys and my_func functions */ + +extern int my_copy(const char *from,const char *to,myf MyFlags); +extern int my_delete(const char *name,myf MyFlags); +extern int my_getwd(char * buf,size_t size,myf MyFlags); +extern int my_setwd(const char *dir,myf MyFlags); +extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags); +extern void *my_once_alloc(size_t Size,myf MyFlags); +extern void my_once_free(void); +extern char *my_once_strdup(const char *src,myf myflags); +extern void *my_once_memdup(const void *src, size_t len, myf myflags); +extern File my_open(const char *FileName,int Flags,myf MyFlags); +extern File my_register_filename(File fd, const char *FileName, + enum file_type type_of_file, + uint error_message_number, myf MyFlags); +extern File my_create(const char *FileName,int CreateFlags, + int AccessFlags, myf MyFlags); +extern int my_close(File Filedes,myf MyFlags); +extern int my_mkdir(const char *dir, int Flags, myf MyFlags); +extern int my_readlink(char *to, const char *filename, myf MyFlags); +extern int my_is_symlink(const char *filename); +extern int my_realpath(char *to, const char *filename, myf MyFlags); +extern File my_create_with_symlink(const char *linkname, const char *filename, + int createflags, int access_flags, + myf MyFlags); +extern int my_delete_with_symlink(const char *name, myf MyFlags); +extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags); +extern int my_symlink(const char *content, const char *linkname, myf MyFlags); +extern size_t my_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags); +extern size_t my_pread(File Filedes,uchar *Buffer,size_t Count,my_off_t offset, + myf MyFlags); +extern int my_rename(const char *from,const char *to,myf MyFlags); +extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_tell(File fd,myf MyFlags); +extern size_t my_write(File Filedes,const uchar *Buffer,size_t Count, + myf MyFlags); +extern size_t my_pwrite(File Filedes,const uchar *Buffer,size_t Count, + my_off_t offset,myf MyFlags); +extern size_t my_fread(FILE *stream,uchar *Buffer,size_t Count,myf MyFlags); +extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count, + myf MyFlags); +extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_ftell(FILE *stream,myf MyFlags); + +/* implemented in my_memmem.c */ +extern void *my_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); + + +#ifdef _WIN32 +extern int my_access(const char *path, int amode); +#else +#define my_access access +#endif + +extern int check_if_legal_filename(const char *path); +extern int check_if_legal_tablename(const char *path); + +#ifdef _WIN32 +extern int nt_share_delete(const char *name,myf MyFlags); +#define my_delete_allow_opened(fname,flags) nt_share_delete((fname),(flags)) +#else +#define my_delete_allow_opened(fname,flags) my_delete((fname),(flags)) +#endif + +#ifdef _WIN32 +/* Windows-only functions (CRT equivalents)*/ +extern HANDLE my_get_osfhandle(File fd); +extern void my_osmaperr(unsigned long last_error); +#endif + +extern void init_glob_errs(void); +extern const char** get_global_errmsgs(); +extern void wait_for_free_space(const char *filename, int errors); +extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); +extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); +extern FILE *my_freopen(const char *path, const char *mode, FILE *stream); +extern int my_fclose(FILE *fd,myf MyFlags); +extern File my_fileno(FILE *fd); +extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); +extern int my_sync(File fd, myf my_flags); +extern int my_sync_dir(const char *dir_name, myf my_flags); +extern int my_sync_dir_by_file(const char *file_name, myf my_flags); +extern void my_error(int nr,myf MyFlags, ...); +extern void my_printf_error(uint my_err, const char *format, + myf MyFlags, ...) + ATTRIBUTE_FORMAT(printf, 2, 4); +extern void my_printv_error(uint error, const char *format, myf MyFlags, + va_list ap); +extern int my_error_register(const char** (*get_errmsgs) (), + int first, int last); +extern const char **my_error_unregister(int first, int last); +extern void my_message(uint my_err, const char *str,myf MyFlags); +extern void my_message_stderr(uint my_err, const char *str, myf MyFlags); +extern my_bool my_basic_init(void); +extern my_bool my_init(void); +extern void my_end(int infoflag); +extern int my_redel(const char *from, const char *to, int MyFlags); +extern int my_copystat(const char *from, const char *to, int MyFlags); +extern char * my_filename(File fd); + +#ifdef EXTRA_DEBUG +void my_print_open_files(void); +#else +#define my_print_open_files() +#endif + +extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist); +extern char *my_tmpdir(MY_TMPDIR *tmpdir); +extern void free_tmpdir(MY_TMPDIR *tmpdir); + +extern void my_remember_signal(int signal_number,sig_handler (*func)(int)); +extern size_t dirname_part(char * to,const char *name, size_t *to_res_length); +extern size_t dirname_length(const char *name); +#define base_name(A) (A+dirname_length(A)) +extern int test_if_hard_path(const char *dir_name); +extern my_bool has_path(const char *name); +extern char *convert_dirname(char *to, const char *from, const char *from_end); +extern void to_unix_path(char * name); +extern char * fn_ext(const char *name); +extern char * fn_same(char * toname,const char *name,int flag); +extern char * fn_format(char * to,const char *name,const char *dir, + const char *form, uint flag); +extern size_t strlength(const char *str); +extern void pack_dirname(char * to,const char *from); +extern size_t normalize_dirname(char * to, const char *from); +extern size_t unpack_dirname(char * to,const char *from); +extern size_t cleanup_dirname(char * to,const char *from); +extern size_t system_filename(char * to,const char *from); +extern size_t unpack_filename(char * to,const char *from); +extern char * intern_filename(char * to,const char *from); +extern char * directory_file_name(char * dst, const char *src); +extern int pack_filename(char * to, const char *name, size_t max_length); +extern char * my_path(char * to,const char *progname, + const char *own_pathname_part); +extern char * my_load_path(char * to, const char *path, + const char *own_path_prefix); +extern int wild_compare(const char *str,const char *wildstr, + pbool str_is_pattern); +extern my_bool array_append_string_unique(const char *str, + const char **array, size_t size); +extern void get_date(char * to,int timeflag,time_t use_time); +extern void soundex(CHARSET_INFO *, char * out_pntr, char * in_pntr, + pbool remove_garbage); +extern int init_record_cache(RECORD_CACHE *info,size_t cachesize,File file, + size_t reclength,enum cache_type type, + pbool use_async_io); +extern int read_cache_record(RECORD_CACHE *info,uchar *to); +extern int end_record_cache(RECORD_CACHE *info); +extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos, + const uchar *record,size_t length); +extern int flush_write_cache(RECORD_CACHE *info); +extern void handle_recived_signals(void); + +extern sig_handler my_set_alarm_variable(int signo); +extern void my_string_ptr_sort(uchar *base,uint items,size_t size); +extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, + size_t size_of_element,uchar *buffer[]); +extern qsort_t my_qsort(void *base_ptr, size_t total_elems, size_t size, + qsort_cmp cmp); +extern qsort_t my_qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); +extern qsort2_cmp get_ptr_compare(size_t); +void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos); +my_off_t my_get_ptr(uchar *ptr, size_t pack_length); +extern int init_io_cache(IO_CACHE *info,File file,size_t cachesize, + enum cache_type type,my_off_t seek_offset, + pbool use_async_io, myf cache_myflags); +extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, + my_off_t seek_offset,pbool use_async_io, + pbool clear_cache); +extern void setup_io_cache(IO_CACHE* info); +extern int _my_b_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_read_r(IO_CACHE *info,uchar *Buffer,size_t Count); +extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, + IO_CACHE *write_cache, uint num_threads); +extern void remove_io_thread(IO_CACHE *info); +extern int _my_b_seq_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_net_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_get(IO_CACHE *info); +extern int _my_b_async_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_write(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_b_append(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_b_safe_write(IO_CACHE *info,const uchar *Buffer,size_t Count); + +extern int my_block_write(IO_CACHE *info, const uchar *Buffer, + size_t Count, my_off_t pos); +extern int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock); + +#define flush_io_cache(info) my_b_flush_io_cache((info),1) + +extern int end_io_cache(IO_CACHE *info); +extern size_t my_b_fill(IO_CACHE *info); +extern void my_b_seek(IO_CACHE *info,my_off_t pos); +extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length); +extern my_off_t my_b_filelength(IO_CACHE *info); +extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...); +extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); +extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, + const char *prefix, size_t cache_size, + myf cache_myflags); +extern my_bool real_open_cached_file(IO_CACHE *cache); +extern void close_cached_file(IO_CACHE *cache); +File create_temp_file(char *to, const char *dir, const char *pfx, + int mode, myf MyFlags); +#define my_init_dynamic_array(A,B,C,D) init_dynamic_array2(A,B,NULL,C,D) +#define my_init_dynamic_array_ci(A,B,C,D) init_dynamic_array2(A,B,NULL,C,D) +#define my_init_dynamic_array2(A,B,C,D,E) init_dynamic_array2(A,B,C,D,E) +#define my_init_dynamic_array2_ci(A,B,C,D,E) init_dynamic_array2(A,B,C,D,E) +extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size, + void *init_buffer, uint init_alloc, + uint alloc_increment); +/* init_dynamic_array() function is deprecated */ +extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size, + uint init_alloc, uint alloc_increment); +extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,uchar * element); +extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array); +extern uchar *pop_dynamic(DYNAMIC_ARRAY*); +extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index); +extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements); +extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index); +extern void delete_dynamic(DYNAMIC_ARRAY *array); +extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index); +extern void freeze_size(DYNAMIC_ARRAY *array); +extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element); +#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element) +#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) +#define push_dynamic(A,B) insert_dynamic((A),(B)) +#define reset_dynamic(array) ((array)->elements= 0) +#define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) + +extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, + size_t init_alloc,size_t alloc_increment); +extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append); +my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, + size_t length); +extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, + ...); +extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str); +extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size); +extern my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n); +extern void dynstr_free(DYNAMIC_STRING *str); +#ifdef HAVE_MLOCK +extern void *my_malloc_lock(size_t length,myf flags); +extern void my_free_lock(void *ptr); +#else +#define my_malloc_lock(A,B) my_malloc((A),(B)) +#define my_free_lock(A) my_free((A)) +#endif +#define alloc_root_inited(A) ((A)->min_malloc != 0) +#define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8) +#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; (A)->min_malloc=0;} while(0) +extern void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, + size_t pre_alloc_size); +extern void *alloc_root(MEM_ROOT *mem_root, size_t Size); +extern void *multi_alloc_root(MEM_ROOT *mem_root, ...); +extern void free_root(MEM_ROOT *root, myf MyFLAGS); +extern void set_prealloc_root(MEM_ROOT *root, char *ptr); +extern void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, + size_t prealloc_size); +extern char *strdup_root(MEM_ROOT *root,const char *str); +static inline char *safe_strdup_root(MEM_ROOT *root, const char *str) +{ + return str ? strdup_root(root, str) : 0; +} +extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len); +extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len); +extern int get_defaults_options(int argc, char **argv, + char **defaults, char **extra_defaults, + char **group_suffix); +extern const char *args_separator; +extern int my_load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv, const char ***); +extern int load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv); +extern int my_search_option_files(const char *conf_file, int *argc, + char ***argv, uint *args_used, + Process_option_func func, void *func_ctx, + const char **default_directories); +extern void free_defaults(char **argv); +extern void my_print_default_files(const char *conf_file); +extern void print_defaults(const char *conf_file, const char **groups); +extern my_bool my_compress(uchar *, size_t *, size_t *); +extern my_bool my_uncompress(uchar *, size_t , size_t *); +extern uchar *my_compress_alloc(const uchar *packet, size_t *len, + size_t *complen); +extern int packfrm(uchar *, size_t, uchar **, size_t *); +extern int unpackfrm(uchar **, size_t *, const uchar *); + +extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem, + size_t count); +extern void my_sleep(ulong m_seconds); +extern ulong crc32(ulong crc, const uchar *buf, uint len); +extern uint my_set_max_open_files(uint files); +void my_free_open_file_info(void); + +extern time_t my_time(myf flags); +extern ulonglong my_getsystime(void); +extern ulonglong my_micro_time(); +extern ulonglong my_micro_time_and_time(time_t *time_arg); +time_t my_time_possible_from_micro(ulonglong microtime); +extern my_bool my_gethwaddr(uchar *to); +extern int my_getncpus(); + +#ifdef HAVE_SYS_MMAN_H +#include + +#ifndef MAP_NOSYNC +#define MAP_NOSYNC 0 +#endif +#ifndef MAP_NORESERVE +#define MAP_NORESERVE 0 /* For irix and AIX */ +#endif + +#ifdef HAVE_MMAP64 +#define my_mmap(a,b,c,d,e,f) mmap64(a,b,c,d,e,f) +#else +#define my_mmap(a,b,c,d,e,f) mmap(a,b,c,d,e,f) +#endif +#define my_munmap(a,b) munmap((a),(b)) + +#else +/* not a complete set of mmap() flags, but only those that nesessary */ +#define PROT_READ 1 +#define PROT_WRITE 2 +#define MAP_NORESERVE 0 +#define MAP_SHARED 0x0001 +#define MAP_PRIVATE 0x0002 +#define MAP_NOSYNC 0x0800 +#define MAP_FAILED ((void *)-1) +#define MS_SYNC 0x0000 + +#define HAVE_MMAP +void *my_mmap(void *, size_t, int, int, int, my_off_t); +int my_munmap(void *, size_t); +#endif + +/* my_getpagesize */ +#ifdef HAVE_GETPAGESIZE +#define my_getpagesize() getpagesize() +#else +int my_getpagesize(void); +#endif + +int my_msync(int, void *, size_t, int); + +/* character sets */ +extern uint get_charset_number(const char *cs_name, uint cs_flags); +extern uint get_collation_number(const char *name); +extern const char *get_charset_name(uint cs_number); + +extern CHARSET_INFO *get_charset(uint cs_number, myf flags); +extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); +extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, + uint cs_flags, myf my_flags); + +extern my_bool resolve_charset(const char *cs_name, + CHARSET_INFO *default_cs, + CHARSET_INFO **cs); +extern my_bool resolve_collation(const char *cl_name, + CHARSET_INFO *default_cl, + CHARSET_INFO **cl); +extern void free_charsets(void); +extern char *get_charsets_dir(char *buf); +extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); +extern my_bool init_compiled_charsets(myf flags); +extern void add_compiled_collation(CHARSET_INFO *cs); +extern size_t escape_string_for_mysql(CHARSET_INFO *charset_info, + char *to, size_t to_length, + const char *from, size_t length); +#ifdef __WIN__ +#define BACKSLASH_MBTAIL +/* File system character set */ +extern CHARSET_INFO *fs_character_set(void); +#endif +extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info, + char *to, size_t to_length, + const char *from, size_t length); + +extern void thd_increment_bytes_sent(ulong length); +extern void thd_increment_bytes_received(ulong length); +extern void thd_increment_net_big_packet_count(ulong length); + +#ifdef __WIN__ +extern my_bool have_tcpip; /* Is set if tcpip is used */ + +/* implemented in my_windac.c */ + +int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror, + DWORD owner_rights, DWORD everybody_rights); + +void my_security_attr_free(SECURITY_ATTRIBUTES *sa); + +/* implemented in my_conio.c */ +char* my_cgets(char *string, size_t clen, size_t* plen); + +#endif + +#include + +#ifdef HAVE_PSI_INTERFACE +extern MYSQL_PLUGIN_IMPORT struct PSI_bootstrap *PSI_hook; +void my_init_mysys_psi_keys(void); +#endif + +struct st_mysql_file; +extern struct st_mysql_file *mysql_stdin; + +C_MODE_END +#endif /* _my_sys_h */ diff --git a/code/meosdb/mysql55/my_xml.h b/code/meosdb/mysql55/my_xml.h new file mode 100644 index 0000000..6fd0f28 --- /dev/null +++ b/code/meosdb/mysql55/my_xml.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + + +#ifndef _my_xml_h +#define _my_xml_h + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MY_XML_OK 0 +#define MY_XML_ERROR 1 + +/* + A flag whether to use absolute tag names in call-back functions, + like "a", "a.b" and "a.b.c" (used in character set file parser), + or relative names like "a", "b" and "c". +*/ +#define MY_XML_FLAG_RELATIVE_NAMES 1 + +/* + A flag whether to skip normilization of text values before calling + call-back functions: i.e. skip leading/trailing spaces, + \r, \n, \t characters. +*/ +#define MY_XML_FLAG_SKIP_TEXT_NORMALIZATION 2 + +enum my_xml_node_type +{ + MY_XML_NODE_TAG, /* can have TAG, ATTR and TEXT children */ + MY_XML_NODE_ATTR, /* can have TEXT children */ + MY_XML_NODE_TEXT /* cannot have children */ +}; + +typedef struct xml_stack_st +{ + int flags; + enum my_xml_node_type current_node_type; + char errstr[128]; + char attr[128]; + char *attrend; + const char *beg; + const char *cur; + const char *end; + void *user_data; + int (*enter)(struct xml_stack_st *st,const char *val, size_t len); + int (*value)(struct xml_stack_st *st,const char *val, size_t len); + int (*leave_xml)(struct xml_stack_st *st,const char *val, size_t len); +} MY_XML_PARSER; + +void my_xml_parser_create(MY_XML_PARSER *st); +void my_xml_parser_free(MY_XML_PARSER *st); +int my_xml_parse(MY_XML_PARSER *st,const char *str, size_t len); + +void my_xml_set_value_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + size_t len)); +void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + size_t len)); +void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + size_t len)); +void my_xml_set_user_data(MY_XML_PARSER *st, void *); + +size_t my_xml_error_pos(MY_XML_PARSER *st); +uint my_xml_error_lineno(MY_XML_PARSER *st); + +const char *my_xml_error_string(MY_XML_PARSER *st); + +#ifdef __cplusplus +} +#endif + +#endif /* _my_xml_h */ diff --git a/code/meosdb/mysql55/mysql.h b/code/meosdb/mysql55/mysql.h new file mode 100644 index 0000000..61a5978 --- /dev/null +++ b/code/meosdb/mysql55/mysql.h @@ -0,0 +1,713 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* + This file defines the client API to MySQL and also the ABI of the + dynamically linked libmysqlclient. + + The ABI should never be changed in a released product of MySQL, + thus you need to take great care when changing the file. In case + the file is changed so the ABI is broken, you must also update + the SHARED_LIB_MAJOR_VERSION in cmake/mysql_version.cmake +*/ + +#ifndef _mysql_h +#define _mysql_h + +#ifdef _AIX /* large-file support will break without this */ +#include +#endif + +#ifdef __CYGWIN__ /* CYGWIN implements a UNIX API */ +#undef WIN +#undef _WIN +#undef _WIN32 +#undef _WIN64 +#undef __WIN__ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _global_h /* If not standard header */ +#ifndef MYSQL_ABI_CHECK +#include +#endif +#ifdef __LCC__ +#include /* For windows */ +#endif +typedef char my_bool; +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__WIN__) +#define __WIN__ +#endif +#if !defined(__WIN__) +#define STDCALL +#else +#define STDCALL __stdcall +#endif + +#ifndef my_socket_defined +#ifdef __WIN__ +#define my_socket SOCKET +#else +typedef int my_socket; +#endif /* __WIN__ */ +#endif /* my_socket_defined */ +#endif /* _global_h */ + +#include "mysql_version.h" +#include "mysql_com.h" +#include "mysql_time.h" + +#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ + +extern unsigned int mysql_port; +extern char *mysql_unix_port; + +#define CLIENT_NET_READ_TIMEOUT 365*24*3600 /* Timeout on read */ +#define CLIENT_NET_WRITE_TIMEOUT 365*24*3600 /* Timeout on write */ + +#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) +#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) +#define IS_BLOB(n) ((n) & BLOB_FLAG) +/** + Returns true if the value is a number which does not need quotes for + the sql_lex.cc parser to parse correctly. +*/ +#define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) +#define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING) + + +typedef struct st_mysql_field { + char *name; /* Name of column */ + char *org_name; /* Original column name, if an alias */ + char *table; /* Table of column if column was a field */ + char *org_table; /* Org table name, if table was an alias */ + char *db; /* Database for table */ + char *catalog; /* Catalog for table */ + char *def; /* Default value (set by mysql_list_fields) */ + unsigned long length; /* Width of column (create length) */ + unsigned long max_length; /* Max width for selected set */ + unsigned int name_length; + unsigned int org_name_length; + unsigned int table_length; + unsigned int org_table_length; + unsigned int db_length; + unsigned int catalog_length; + unsigned int def_length; + unsigned int flags; /* Div flags */ + unsigned int decimals; /* Number of decimals in field */ + unsigned int charsetnr; /* Character set */ + enum enum_field_types type; /* Type of field. See mysql_com.h for types */ + void *extension; +} MYSQL_FIELD; + +typedef char **MYSQL_ROW; /* return data as array of strings */ +typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */ + +#ifndef _global_h +#if defined(NO_CLIENT_LONG_LONG) +typedef unsigned long my_ulonglong; +#elif defined (__WIN__) +typedef unsigned __int64 my_ulonglong; +#else +typedef unsigned long long my_ulonglong; +#endif +#endif + +#include "typelib.h" + +#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0) + +/* backward compatibility define - to be removed eventually */ +#define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED + +typedef struct st_mysql_rows { + struct st_mysql_rows *next; /* list of rows */ + MYSQL_ROW data; + unsigned long length; +} MYSQL_ROWS; + +typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ + +#include "my_alloc.h" + +typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; +typedef struct st_mysql_data { + MYSQL_ROWS *data; + struct embedded_query_result *embedded_info; + MEM_ROOT alloc; + my_ulonglong rows; + unsigned int fields; + /* extra info for embedded library */ + void *extension; +} MYSQL_DATA; + +enum mysql_option +{ + MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, + MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, + MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, + MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, + MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, + MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH +}; + +/** + @todo remove the "extension", move st_mysql_options completely + out of mysql.h +*/ +struct st_mysql_options_extention; + +struct st_mysql_options { + unsigned int connect_timeout, read_timeout, write_timeout; + unsigned int port, protocol; + unsigned long client_flag; + char *host,*user,*password,*unix_socket,*db; + struct st_dynamic_array *init_commands; + char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; + char *ssl_key; /* PEM key file */ + char *ssl_cert; /* PEM cert file */ + char *ssl_ca; /* PEM CA file */ + char *ssl_capath; /* PEM directory of CA-s? */ + char *ssl_cipher; /* cipher to use */ + char *shared_memory_base_name; + unsigned long max_allowed_packet; + my_bool use_ssl; /* if to use SSL or not */ + my_bool compress,named_pipe; + my_bool unused1; + my_bool unused2; + my_bool unused3; + my_bool unused4; + enum mysql_option methods_to_use; + char *client_ip; + /* Refuse client connecting to server if it uses old (pre-4.1.1) protocol */ + my_bool secure_auth; + /* 0 - never report, 1 - always report (default) */ + my_bool report_data_truncation; + + /* function pointers for local infile support */ + int (*local_infile_init)(void **, const char *, void *); + int (*local_infile_read)(void *, char *, unsigned int); + void (*local_infile_end)(void *); + int (*local_infile_error)(void *, char *, unsigned int); + void *local_infile_userdata; + struct st_mysql_options_extention *extension; +}; + +enum mysql_status +{ + MYSQL_STATUS_READY, MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT, + MYSQL_STATUS_STATEMENT_GET_RESULT +}; + +enum mysql_protocol_type +{ + MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET, + MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY +}; + +typedef struct character_set +{ + unsigned int number; /* character set number */ + unsigned int state; /* character set state */ + const char *csname; /* collation name */ + const char *name; /* character set name */ + const char *comment; /* comment */ + const char *dir; /* character set directory */ + unsigned int mbminlen; /* min. length for multibyte strings */ + unsigned int mbmaxlen; /* max. length for multibyte strings */ +} MY_CHARSET_INFO; + +struct st_mysql_methods; +struct st_mysql_stmt; + +typedef struct st_mysql +{ + NET net; /* Communication parameters */ + unsigned char *connector_fd; /* ConnectorFd for SSL */ + char *host,*user,*passwd,*unix_socket,*server_version,*host_info; + char *info, *db; + struct charset_info_st *charset; + MYSQL_FIELD *fields; + MEM_ROOT field_alloc; + my_ulonglong affected_rows; + my_ulonglong insert_id; /* id if insert on table with NEXTNR */ + my_ulonglong extra_info; /* Not used */ + unsigned long thread_id; /* Id for connection in server */ + unsigned long packet_length; + unsigned int port; + unsigned long client_flag,server_capabilities; + unsigned int protocol_version; + unsigned int field_count; + unsigned int server_status; + unsigned int server_language; + unsigned int warning_count; + struct st_mysql_options options; + enum mysql_status status; + my_bool free_me; /* If free in mysql_close */ + my_bool reconnect; /* set to 1 if automatic reconnect */ + + /* session-wide random string */ + char scramble[SCRAMBLE_LENGTH+1]; + my_bool unused1; + void *unused2, *unused3, *unused4, *unused5; + + LIST *stmts; /* list of all statements */ + const struct st_mysql_methods *methods; + void *thd; + /* + Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag + from mysql_stmt_close if close had to cancel result set of this object. + */ + my_bool *unbuffered_fetch_owner; + /* needed for embedded server - no net buffer to store the 'info' */ + char *info_buffer; + void *extension; +} MYSQL; + + +typedef struct st_mysql_res { + my_ulonglong row_count; + MYSQL_FIELD *fields; + MYSQL_DATA *data; + MYSQL_ROWS *data_cursor; + unsigned long *lengths; /* column lengths of current row */ + MYSQL *handle; /* for unbuffered reads */ + const struct st_mysql_methods *methods; + MYSQL_ROW row; /* If unbuffered read */ + MYSQL_ROW current_row; /* buffer to current row */ + MEM_ROOT field_alloc; + unsigned int field_count, current_field; + my_bool eof; /* Used by mysql_fetch_row */ + /* mysql_stmt_close() had to cancel this result */ + my_bool unbuffered_fetch_cancelled; + void *extension; +} MYSQL_RES; + + +#if !defined(MYSQL_SERVER) && !defined(MYSQL_CLIENT) +#define MYSQL_CLIENT +#endif + + +typedef struct st_mysql_parameters +{ + unsigned long *p_max_allowed_packet; + unsigned long *p_net_buffer_length; + void *extension; +} MYSQL_PARAMETERS; + +#if !defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) +#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet) +#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length) +#endif + +/* + Set up and bring down the server; to ensure that applications will + work when linked against either the standard client library or the + embedded server library, these functions should be called. +*/ +int STDCALL mysql_server_init(int argc, char **argv, char **groups); +void STDCALL mysql_server_end(void); + +/* + mysql_server_init/end need to be called when using libmysqld or + libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so + you don't need to call it explicitely; but you need to call + mysql_server_end() to free memory). The names are a bit misleading + (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general + names which suit well whether you're using libmysqld or libmysqlclient. We + intend to promote these aliases over the mysql_server* ones. +*/ +#define mysql_library_init mysql_server_init +#define mysql_library_end mysql_server_end + +MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); + +/* + Set up and bring down a thread; these function should be called + for each thread in an application which opens at least one MySQL + connection. All uses of the connection(s) should be between these + function calls. +*/ +my_bool STDCALL mysql_thread_init(void); +void STDCALL mysql_thread_end(void); + +/* + Functions to get information from the MYSQL and MYSQL_RES structures + Should definitely be used if one uses shared libraries. +*/ + +my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res); +unsigned int STDCALL mysql_num_fields(MYSQL_RES *res); +my_bool STDCALL mysql_eof(MYSQL_RES *res); +MYSQL_FIELD *STDCALL mysql_fetch_field_direct(MYSQL_RES *res, + unsigned int fieldnr); +MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res); +MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res); +MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res); + +unsigned int STDCALL mysql_field_count(MYSQL *mysql); +my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); +my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); +unsigned int STDCALL mysql_errno(MYSQL *mysql); +const char * STDCALL mysql_error(MYSQL *mysql); +const char *STDCALL mysql_sqlstate(MYSQL *mysql); +unsigned int STDCALL mysql_warning_count(MYSQL *mysql); +const char * STDCALL mysql_info(MYSQL *mysql); +unsigned long STDCALL mysql_thread_id(MYSQL *mysql); +const char * STDCALL mysql_character_set_name(MYSQL *mysql); +int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); + +MYSQL * STDCALL mysql_init(MYSQL *mysql); +my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, + const char *cert, const char *ca, + const char *capath, const char *cipher); +const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); +my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, + const char *passwd, const char *db); +MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, + const char *user, + const char *passwd, + const char *db, + unsigned int port, + const char *unix_socket, + unsigned long clientflag); +int STDCALL mysql_select_db(MYSQL *mysql, const char *db); +int STDCALL mysql_query(MYSQL *mysql, const char *q); +int STDCALL mysql_send_query(MYSQL *mysql, const char *q, + unsigned long length); +int STDCALL mysql_real_query(MYSQL *mysql, const char *q, + unsigned long length); +MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); + +void STDCALL mysql_get_character_set_info(MYSQL *mysql, + MY_CHARSET_INFO *charset); + +/* local infile support */ + +#define LOCAL_INFILE_ERROR_LEN 512 + +void +mysql_set_local_infile_handler(MYSQL *mysql, + int (*local_infile_init)(void **, const char *, + void *), + int (*local_infile_read)(void *, char *, + unsigned int), + void (*local_infile_end)(void *), + int (*local_infile_error)(void *, char*, + unsigned int), + void *); + +void +mysql_set_local_infile_default(MYSQL *mysql); + +int STDCALL mysql_shutdown(MYSQL *mysql, + enum mysql_enum_shutdown_level + shutdown_level); +int STDCALL mysql_dump_debug_info(MYSQL *mysql); +int STDCALL mysql_refresh(MYSQL *mysql, + unsigned int refresh_options); +int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid); +int STDCALL mysql_set_server_option(MYSQL *mysql, + enum enum_mysql_set_option + option); +int STDCALL mysql_ping(MYSQL *mysql); +const char * STDCALL mysql_stat(MYSQL *mysql); +const char * STDCALL mysql_get_server_info(MYSQL *mysql); +const char * STDCALL mysql_get_client_info(void); +unsigned long STDCALL mysql_get_client_version(void); +const char * STDCALL mysql_get_host_info(MYSQL *mysql); +unsigned long STDCALL mysql_get_server_version(MYSQL *mysql); +unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild); +MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild); +MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); +int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, + const void *arg); +void STDCALL mysql_free_result(MYSQL_RES *result); +void STDCALL mysql_data_seek(MYSQL_RES *result, + my_ulonglong offset); +MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, + MYSQL_ROW_OFFSET offset); +MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, + MYSQL_FIELD_OFFSET offset); +MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); +unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); +MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); +MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, + const char *wild); +unsigned long STDCALL mysql_escape_string(char *to,const char *from, + unsigned long from_length); +unsigned long STDCALL mysql_hex_string(char *to,const char *from, + unsigned long from_length); +unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, + char *to,const char *from, + unsigned long length); +void STDCALL mysql_debug(const char *debug); +void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); +unsigned int STDCALL mysql_thread_safe(void); +my_bool STDCALL mysql_embedded(void); +my_bool STDCALL mysql_read_query_result(MYSQL *mysql); + + +/* + The following definitions are added for the enhanced + client-server protocol +*/ + +/* statement state */ +enum enum_mysql_stmt_state +{ + MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE, + MYSQL_STMT_FETCH_DONE +}; + + +/* + This structure is used to define bind information, and + internally by the client library. + Public members with their descriptions are listed below + (conventionally `On input' refers to the binds given to + mysql_stmt_bind_param, `On output' refers to the binds given + to mysql_stmt_bind_result): + + buffer_type - One of the MYSQL_* types, used to describe + the host language type of buffer. + On output: if column type is different from + buffer_type, column value is automatically converted + to buffer_type before it is stored in the buffer. + buffer - On input: points to the buffer with input data. + On output: points to the buffer capable to store + output data. + The type of memory pointed by buffer must correspond + to buffer_type. See the correspondence table in + the comment to mysql_stmt_bind_param. + + The two above members are mandatory for any kind of bind. + + buffer_length - the length of the buffer. You don't have to set + it for any fixed length buffer: float, double, + int, etc. It must be set however for variable-length + types, such as BLOBs or STRINGs. + + length - On input: in case when lengths of input values + are different for each execute, you can set this to + point at a variable containining value length. This + way the value length can be different in each execute. + If length is not NULL, buffer_length is not used. + Note, length can even point at buffer_length if + you keep bind structures around while fetching: + this way you can change buffer_length before + each execution, everything will work ok. + On output: if length is set, mysql_stmt_fetch will + write column length into it. + + is_null - On input: points to a boolean variable that should + be set to TRUE for NULL values. + This member is useful only if your data may be + NULL in some but not all cases. + If your data is never NULL, is_null should be set to 0. + If your data is always NULL, set buffer_type + to MYSQL_TYPE_NULL, and is_null will not be used. + + is_unsigned - On input: used to signify that values provided for one + of numeric types are unsigned. + On output describes signedness of the output buffer. + If, taking into account is_unsigned flag, column data + is out of range of the output buffer, data for this column + is regarded truncated. Note that this has no correspondence + to the sign of result set column, if you need to find it out + use mysql_stmt_result_metadata. + error - where to write a truncation error if it is present. + possible error value is: + 0 no truncation + 1 value is out of range or buffer is too small + + Please note that MYSQL_BIND also has internals members. +*/ + +typedef struct st_mysql_bind +{ + unsigned long *length; /* output length pointer */ + my_bool *is_null; /* Pointer to null indicator */ + void *buffer; /* buffer to get/put data */ + /* set this if you want to track data truncations happened during fetch */ + my_bool *error; + unsigned char *row_ptr; /* for the current data position */ + void (*store_param_func)(NET *net, struct st_mysql_bind *param); + void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + /* output buffer length, must be set when fetching str/binary */ + unsigned long buffer_length; + unsigned long offset; /* offset position for char/binary fetch */ + unsigned long length_value; /* Used if length is 0 */ + unsigned int param_number; /* For null count and error messages */ + unsigned int pack_length; /* Internal length for packed data */ + enum enum_field_types buffer_type; /* buffer type */ + my_bool error_value; /* used if error is 0 */ + my_bool is_unsigned; /* set if integer type is unsigned */ + my_bool long_data_used; /* If used with mysql_send_long_data */ + my_bool is_null_value; /* Used if is_null is 0 */ + void *extension; +} MYSQL_BIND; + + +/* statement handler */ +typedef struct st_mysql_stmt +{ + MEM_ROOT mem_root; /* root allocations */ + LIST list; /* list to keep track of all stmts */ + MYSQL *mysql; /* connection handle */ + MYSQL_BIND *params; /* input parameters */ + MYSQL_BIND *bind; /* output parameters */ + MYSQL_FIELD *fields; /* result set metadata */ + MYSQL_DATA result; /* cached result set */ + MYSQL_ROWS *data_cursor; /* current row in cached result */ + /* + mysql_stmt_fetch() calls this function to fetch one row (it's different + for buffered, unbuffered and cursor fetch). + */ + int (*read_row_func)(struct st_mysql_stmt *stmt, + unsigned char **row); + /* copy of mysql->affected_rows after statement execution */ + my_ulonglong affected_rows; + my_ulonglong insert_id; /* copy of mysql->insert_id */ + unsigned long stmt_id; /* Id for prepared statement */ + unsigned long flags; /* i.e. type of cursor to open */ + unsigned long prefetch_rows; /* number of rows per one COM_FETCH */ + /* + Copied from mysql->server_status after execute/fetch to know + server-side cursor status for this statement. + */ + unsigned int server_status; + unsigned int last_errno; /* error code */ + unsigned int param_count; /* input parameter count */ + unsigned int field_count; /* number of columns in result set */ + enum enum_mysql_stmt_state state; /* statement state */ + char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ + char sqlstate[SQLSTATE_LENGTH+1]; + /* Types of input parameters should be sent to server */ + my_bool send_types_to_server; + my_bool bind_param_done; /* input buffers were supplied */ + unsigned char bind_result_done; /* output buffers were supplied */ + /* mysql_stmt_close() had to cancel this result */ + my_bool unbuffered_fetch_cancelled; + /* + Is set to true if we need to calculate field->max_length for + metadata fields when doing mysql_stmt_store_result. + */ + my_bool update_max_length; + void *extension; +} MYSQL_STMT; + +enum enum_stmt_attr_type +{ + /* + When doing mysql_stmt_store_result calculate max_length attribute + of statement metadata. This is to be consistent with the old API, + where this was done automatically. + In the new API we do that only by request because it slows down + mysql_stmt_store_result sufficiently. + */ + STMT_ATTR_UPDATE_MAX_LENGTH, + /* + unsigned long with combination of cursor flags (read only, for update, + etc) + */ + STMT_ATTR_CURSOR_TYPE, + /* + Amount of rows to retrieve from server per one fetch if using cursors. + Accepts unsigned long attribute in the range 1 - ulong_max + */ + STMT_ATTR_PREFETCH_ROWS +}; + + +MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql); +int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, + unsigned long length); +int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, + unsigned int column, + unsigned long offset); +int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); +unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + const void *attr); +my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + void *attr); +my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); +my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, + unsigned int param_number, + const char *data, + unsigned long length); +MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt); +MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, + MYSQL_ROW_OFFSET offset); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt); +void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset); +my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt); + +my_bool STDCALL mysql_commit(MYSQL * mysql); +my_bool STDCALL mysql_rollback(MYSQL * mysql); +my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); +my_bool STDCALL mysql_more_results(MYSQL *mysql); +int STDCALL mysql_next_result(MYSQL *mysql); +int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt); +void STDCALL mysql_close(MYSQL *sock); + + +/* status return codes */ +#define MYSQL_NO_DATA 100 +#define MYSQL_DATA_TRUNCATED 101 + +#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) + +#ifdef USE_OLD_FUNCTIONS +MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, + const char *user, const char *passwd); +int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); +int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); +#endif +#define HAVE_MYSQL_REAL_CONNECT + +#ifdef __cplusplus +} +#endif + +#endif /* _mysql_h */ diff --git a/code/meosdb/mysql55/mysql/client_plugin.h b/code/meosdb/mysql55/mysql/client_plugin.h new file mode 100644 index 0000000..d380e32 --- /dev/null +++ b/code/meosdb/mysql55/mysql/client_plugin.h @@ -0,0 +1,163 @@ +#ifndef MYSQL_CLIENT_PLUGIN_INCLUDED +/* Copyright (C) 2010 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +/** + @file + + MySQL Client Plugin API + + This file defines the API for plugins that work on the client side +*/ +#define MYSQL_CLIENT_PLUGIN_INCLUDED + +#ifndef MYSQL_ABI_CHECK +#include +#include +#endif + +/* known plugin types */ +#define MYSQL_CLIENT_reserved1 0 +#define MYSQL_CLIENT_reserved2 1 +#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 + +#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 + +#define MYSQL_CLIENT_MAX_PLUGINS 3 + +#define mysql_declare_client_plugin(X) \ + MYSQL_PLUGIN_EXPORT struct st_mysql_client_plugin_ ## X \ + _mysql_client_plugin_declaration_ = { \ + MYSQL_CLIENT_ ## X ## _PLUGIN, \ + MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION, +#define mysql_end_client_plugin } + +/* generic plugin header structure */ +#define MYSQL_CLIENT_PLUGIN_HEADER \ + int type; \ + unsigned int interface_version; \ + const char *name; \ + const char *author; \ + const char *desc; \ + unsigned int version[3]; \ + const char *license; \ + void *mysql_api; \ + int (*init)(char *, size_t, int, va_list); \ + int (*deinit)(); \ + int (*options)(const char *option, const void *); + +struct st_mysql_client_plugin +{ + MYSQL_CLIENT_PLUGIN_HEADER +}; + +struct st_mysql; + +/******** authentication plugin specific declarations *********/ +#include + +struct st_mysql_client_plugin_AUTHENTICATION +{ + MYSQL_CLIENT_PLUGIN_HEADER + int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); +}; + +/******** using plugins ************/ + +/** + loads a plugin and initializes it + + @param mysql MYSQL structure. + @param name a name of the plugin to load + @param type type of plugin that should be loaded, -1 to disable type check + @param argc number of arguments to pass to the plugin initialization + function + @param ... arguments for the plugin initialization function + + @retval + a pointer to the loaded plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, + int argc, ...); + +/** + loads a plugin and initializes it, taking va_list as an argument + + This is the same as mysql_load_plugin, but take va_list instead of + a list of arguments. + + @param mysql MYSQL structure. + @param name a name of the plugin to load + @param type type of plugin that should be loaded, -1 to disable type check + @param argc number of arguments to pass to the plugin initialization + function + @param args arguments for the plugin initialization function + + @retval + a pointer to the loaded plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, + int argc, va_list args); + +/** + finds an already loaded plugin by name, or loads it, if necessary + + @param mysql MYSQL structure. + @param name a name of the plugin to load + @param type type of plugin that should be loaded + + @retval + a pointer to the plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); + +/** + adds a plugin structure to the list of loaded plugins + + This is useful if an application has the necessary functionality + (for example, a special load data handler) statically linked into + the application binary. It can use this function to register the plugin + directly, avoiding the need to factor it out into a shared object. + + @param mysql MYSQL structure. It is only used for error reporting + @param plugin an st_mysql_client_plugin structure to register + + @retval + a pointer to the plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_client_register_plugin(struct st_mysql *mysql, + struct st_mysql_client_plugin *plugin); + +/** + set plugin options + + Can be used to set extra options and affect behavior for a plugin. + This function may be called multiple times to set several options + + @param plugin an st_mysql_client_plugin structure + @param option a string which specifies the option to set + @param value value for the option. + + @retval 0 on success, 1 in case of failure +**/ +int STDCALL mysql_plugin_options(struct st_mysql_client_plugin *plugin, + const char *option, + const void *value); +#endif + diff --git a/code/meosdb/mysql55/mysql/innodb_priv.h b/code/meosdb/mysql55/mysql/innodb_priv.h new file mode 100644 index 0000000..b204fff --- /dev/null +++ b/code/meosdb/mysql55/mysql/innodb_priv.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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 */ + +#ifndef INNODB_PRIV_INCLUDED +#define INNODB_PRIV_INCLUDED + +/** @file Declaring server-internal functions that are used by InnoDB. */ + +#include + +class THD; + +int get_quote_char_for_identifier(THD *thd, const char *name, uint length); +bool schema_table_store_record(THD *thd, TABLE *table); +void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); +bool check_global_access(THD *thd, ulong want_access); +uint strconvert(CHARSET_INFO *from_cs, const char *from, + CHARSET_INFO *to_cs, char *to, uint to_length, + uint *errors); +void sql_print_error(const char *format, ...); + + + +#endif /* INNODB_PRIV_INCLUDED */ diff --git a/code/meosdb/mysql55/mysql/plugin.h b/code/meosdb/mysql55/mysql/plugin.h new file mode 100644 index 0000000..7f91b6c --- /dev/null +++ b/code/meosdb/mysql55/mysql/plugin.h @@ -0,0 +1,633 @@ +/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_plugin_h +#define _my_plugin_h + +/* + On Windows, exports from DLL need to be declared + Also, plugin needs to be declared as extern "C" because MSVC + unlike other compilers, uses C++ mangling for variables not only + for functions. +*/ +#if defined(_MSC_VER) +#if defined(MYSQL_DYNAMIC_PLUGIN) + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) + #else + #define MYSQL_PLUGIN_EXPORT __declspec(dllexport) + #endif +#else /* MYSQL_DYNAMIC_PLUGIN */ + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" + #else + #define MYSQL_PLUGIN_EXPORT + #endif +#endif /*MYSQL_DYNAMIC_PLUGIN */ +#else /*_MSC_VER */ +#define MYSQL_PLUGIN_EXPORT +#endif + +#ifdef __cplusplus +class THD; +class Item; +#define MYSQL_THD THD* +#else +#define MYSQL_THD void* +#endif + +#include + +#define MYSQL_XIDDATASIZE 128 +/** + struct st_mysql_xid is binary compatible with the XID structure as + in the X/Open CAE Specification, Distributed Transaction Processing: + The XA Specification, X/Open Company Ltd., 1991. + http://www.opengroup.org/bookstore/catalog/c193.htm + + @see XID in sql/handler.h +*/ +struct st_mysql_xid { + long formatID; + long gtrid_length; + long bqual_length; + char data[MYSQL_XIDDATASIZE]; /* Not \0-terminated */ +}; +typedef struct st_mysql_xid MYSQL_XID; + +/************************************************************************* + Plugin API. Common for all plugin types. +*/ + +#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0102 + +/* + The allowable types of plugins +*/ +#define MYSQL_UDF_PLUGIN 0 /* User-defined function */ +#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */ +#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */ +#define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */ +#define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */ +#define MYSQL_AUDIT_PLUGIN 5 /* The Audit plugin type */ +#define MYSQL_REPLICATION_PLUGIN 6 /* The replication plugin type */ +#define MYSQL_AUTHENTICATION_PLUGIN 7 /* The authentication plugin type */ +#define MYSQL_MAX_PLUGIN_TYPE_NUM 8 /* The number of plugin types */ + +/* We use the following strings to define licenses for plugins */ +#define PLUGIN_LICENSE_PROPRIETARY 0 +#define PLUGIN_LICENSE_GPL 1 +#define PLUGIN_LICENSE_BSD 2 + +#define PLUGIN_LICENSE_PROPRIETARY_STRING "PROPRIETARY" +#define PLUGIN_LICENSE_GPL_STRING "GPL" +#define PLUGIN_LICENSE_BSD_STRING "BSD" + +/* + Macros for beginning and ending plugin declarations. Between + mysql_declare_plugin and mysql_declare_plugin_end there should + be a st_mysql_plugin struct for each plugin to be declared. +*/ + + +#ifndef MYSQL_DYNAMIC_PLUGIN +#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int PSIZE= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin DECLS[]= { +#else +#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]= { +#endif + +#define mysql_declare_plugin(NAME) \ +__MYSQL_DECLARE_PLUGIN(NAME, \ + builtin_ ## NAME ## _plugin_interface_version, \ + builtin_ ## NAME ## _sizeof_struct_st_plugin, \ + builtin_ ## NAME ## _plugin) + +#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0}} + +/* + declarations for SHOW STATUS support in plugins +*/ +enum enum_mysql_show_type +{ + SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG, + SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, + SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, + SHOW_always_last +}; + +struct st_mysql_show_var { + const char *name; + char *value; + enum enum_mysql_show_type type; +}; + +#define SHOW_VAR_FUNC_BUFF_SIZE 1024 +typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, char *); + + +/* + declarations for server variables and command line options +*/ + + +#define PLUGIN_VAR_BOOL 0x0001 +#define PLUGIN_VAR_INT 0x0002 +#define PLUGIN_VAR_LONG 0x0003 +#define PLUGIN_VAR_LONGLONG 0x0004 +#define PLUGIN_VAR_STR 0x0005 +#define PLUGIN_VAR_ENUM 0x0006 +#define PLUGIN_VAR_SET 0x0007 +#define PLUGIN_VAR_UNSIGNED 0x0080 +#define PLUGIN_VAR_THDLOCAL 0x0100 /* Variable is per-connection */ +#define PLUGIN_VAR_READONLY 0x0200 /* Server variable is read only */ +#define PLUGIN_VAR_NOSYSVAR 0x0400 /* Not a server variable */ +#define PLUGIN_VAR_NOCMDOPT 0x0800 /* Not a command line option */ +#define PLUGIN_VAR_NOCMDARG 0x1000 /* No argument for cmd line */ +#define PLUGIN_VAR_RQCMDARG 0x0000 /* Argument required for cmd line */ +#define PLUGIN_VAR_OPCMDARG 0x2000 /* Argument optional for cmd line */ +#define PLUGIN_VAR_MEMALLOC 0x8000 /* String needs memory allocated */ + +struct st_mysql_sys_var; +struct st_mysql_value; + +/* + SYNOPSIS + (*mysql_var_check_func)() + thd thread handle + var dynamic variable being altered + save pointer to temporary storage + value user provided value + RETURN + 0 user provided value is OK and the update func may be called. + any other value indicates error. + + This function should parse the user provided value and store in the + provided temporary storage any data as required by the update func. + There is sufficient space in the temporary storage to store a double. + Note that the update func may not be called if any other error occurs + so any memory allocated should be thread-local so that it may be freed + automatically at the end of the statement. +*/ + +typedef int (*mysql_var_check_func)(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value); + +/* + SYNOPSIS + (*mysql_var_update_func)() + thd thread handle + var dynamic variable being altered + var_ptr pointer to dynamic variable + save pointer to temporary storage + RETURN + NONE + + This function should use the validated value stored in the temporary store + and persist it in the provided pointer to the dynamic variable. + For example, strings may require memory to be allocated. +*/ +typedef void (*mysql_var_update_func)(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *var_ptr, const void *save); + + +/* the following declarations are for internal use only */ + + +#define PLUGIN_VAR_MASK \ + (PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | \ + PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_NOCMDARG | \ + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC) + +#define MYSQL_PLUGIN_VAR_HEADER \ + int flags; \ + const char *name; \ + const char *comment; \ + mysql_var_check_func check; \ + mysql_var_update_func update + +#define MYSQL_SYSVAR_NAME(name) mysql_sysvar_ ## name +#define MYSQL_SYSVAR(name) \ + ((struct st_mysql_sys_var *)&(MYSQL_SYSVAR_NAME(name))) + +/* + for global variables, the value pointer is the first + element after the header, the default value is the second. + for thread variables, the value offset is the first + element after the header, the default value is the second. +*/ + + +#define DECLARE_MYSQL_SYSVAR_BASIC(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; \ + const type def_val; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_SYSVAR_SIMPLE(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; type def_val; \ + type min_val; type max_val; \ + type blk_sz; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_SYSVAR_TYPELIB(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; type def_val; \ + TYPELIB *typelib; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_THDVAR_FUNC(type) \ + type *(*resolve)(MYSQL_THD thd, int offset) + +#define DECLARE_MYSQL_THDVAR_BASIC(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + const type def_val; \ + DECLARE_THDVAR_FUNC(type); \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_THDVAR_SIMPLE(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + type def_val; type min_val; \ + type max_val; type blk_sz; \ + DECLARE_THDVAR_FUNC(type); \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_THDVAR_TYPELIB(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + type def_val; \ + DECLARE_THDVAR_FUNC(type); \ + TYPELIB *typelib; \ +} MYSQL_SYSVAR_NAME(name) + + +/* + the following declarations are for use by plugin implementors +*/ + +#define MYSQL_SYSVAR_BOOL(name, varname, opt, comment, check, update, def) \ +DECLARE_MYSQL_SYSVAR_BASIC(name, char) = { \ + PLUGIN_VAR_BOOL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def} + +#define MYSQL_SYSVAR_STR(name, varname, opt, comment, check, update, def) \ +DECLARE_MYSQL_SYSVAR_BASIC(name, char *) = { \ + PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def} + +#define MYSQL_SYSVAR_INT(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, int) = { \ + PLUGIN_VAR_INT | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_UINT(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_LONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, long) = { \ + PLUGIN_VAR_LONG | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ULONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_LONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, long long) = { \ + PLUGIN_VAR_LONGLONG | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ULONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ENUM(name, varname, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long) = { \ + PLUGIN_VAR_ENUM | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, typelib } + +#define MYSQL_SYSVAR_SET(name, varname, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long long) = { \ + PLUGIN_VAR_SET | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, typelib } + +#define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ +DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ + PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL} + +#define MYSQL_THDVAR_STR(name, opt, comment, check, update, def) \ +DECLARE_MYSQL_THDVAR_BASIC(name, char *) = { \ + PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL} + +#define MYSQL_THDVAR_INT(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_UINT(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_LONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ULONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_LONGLONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ULONGLONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ENUM(name, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long) = { \ + PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL, typelib } + +#define MYSQL_THDVAR_SET(name, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long long) = { \ + PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL, typelib } + +/* accessor macros */ + +#define SYSVAR(name) \ + (*(MYSQL_SYSVAR_NAME(name).value)) + +/* when thd == null, result points to global value */ +#define THDVAR(thd, name) \ + (*(MYSQL_SYSVAR_NAME(name).resolve(thd, MYSQL_SYSVAR_NAME(name).offset))) + + +/* + Plugin description structure. +*/ + +struct st_mysql_plugin +{ + int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + void *info; /* pointer to type-specific plugin descriptor */ + const char *name; /* plugin name */ + const char *author; /* plugin author (for I_S.PLUGINS) */ + const char *descr; /* general descriptive text (for I_S.PLUGINS) */ + int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ + int (*init)(void *); /* the function to invoke when plugin is loaded */ + int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ + unsigned int version; /* plugin version (for I_S.PLUGINS) */ + struct st_mysql_show_var *status_vars; + struct st_mysql_sys_var **system_vars; + void * __reserved1; /* reserved for dependency checking */ +}; + +/************************************************************************* + API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) +*/ +#include "plugin_ftparser.h" + +/************************************************************************* + API for Storage Engine plugin. (MYSQL_DAEMON_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_daemon +{ + int interface_version; +}; + + +/************************************************************************* + API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_information_schema +{ + int interface_version; +}; + + +/************************************************************************* + API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_HANDLERTON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + The real API is in the sql/handler.h + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_storage_engine +{ + int interface_version; +}; + +struct handlerton; + + +/* + API for Replication plugin. (MYSQL_REPLICATION_PLUGIN) +*/ + #define MYSQL_REPLICATION_INTERFACE_VERSION 0x0100 + + /** + Replication plugin descriptor + */ + struct Mysql_replication { + int interface_version; + }; + +/************************************************************************* + st_mysql_value struct for reading values from mysqld. + Used by server variables framework to parse user-provided values. + Will be used for arguments when implementing UDFs. + + Note that val_str() returns a string in temporary memory + that will be freed at the end of statement. Copy the string + if you need it to persist. +*/ + +#define MYSQL_VALUE_TYPE_STRING 0 +#define MYSQL_VALUE_TYPE_REAL 1 +#define MYSQL_VALUE_TYPE_INT 2 + +struct st_mysql_value +{ + int (*value_type)(struct st_mysql_value *); + const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length); + int (*val_real)(struct st_mysql_value *, double *realbuf); + int (*val_int)(struct st_mysql_value *, long long *intbuf); + int (*is_unsigned)(struct st_mysql_value *); +}; + + +/************************************************************************* + Miscellaneous functions for plugin implementors +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +int thd_in_lock_tables(const MYSQL_THD thd); +int thd_tablespace_op(const MYSQL_THD thd); +long long thd_test_options(const MYSQL_THD thd, long long test_options); +int thd_sql_command(const MYSQL_THD thd); +const char *thd_proc_info(MYSQL_THD thd, const char *info); +void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton); +void thd_storage_lock_wait(MYSQL_THD thd, long long value); +int thd_tx_isolation(const MYSQL_THD thd); +char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, + unsigned int max_query_len); +/* Increments the row counter, see THD::row_count */ +void thd_inc_row_count(MYSQL_THD thd); + +/** + Create a temporary file. + + @details + The temporary file is created in a location specified by the mysql + server configuration (--tmpdir option). The caller does not need to + delete the file, it will be deleted automatically. + + @param prefix prefix for temporary file name + @retval -1 error + @retval >= 0 a file handle that can be passed to dup or my_close +*/ +int mysql_tmpfile(const char *prefix); + +/** + Check the killed state of a connection + + @details + In MySQL support for the KILL statement is cooperative. The KILL + statement only sets a "killed" flag. This function returns the value + of that flag. A thread should check it often, especially inside + time-consuming loops, and gracefully abort the operation if it is + non-zero. + + @param thd user thread connection handle + @retval 0 the connection is active + @retval 1 the connection has been killed +*/ +int thd_killed(const MYSQL_THD thd); + + +/** + Return the thread id of a user thread + + @param thd user thread connection handle + @return thread id +*/ +unsigned long thd_get_thread_id(const MYSQL_THD thd); + +/** + Get the XID for this connection's transaction + + @param thd user thread connection handle + @param xid location where identifier is stored +*/ +void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid); + +/** + Invalidate the query cache for a given table. + + @param thd user thread connection handle + @param key databasename\\0tablename\\0 + @param key_length length of key in bytes, including the NUL bytes + @param using_trx flag: TRUE if using transactions, FALSE otherwise +*/ +void mysql_query_cache_invalidate4(MYSQL_THD thd, + const char *key, unsigned int key_length, + int using_trx); + + +/** + Provide a handler data getter to simplify coding +*/ +void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton); + + +/** + Provide a handler data setter to simplify coding + + @details + Set ha_data pointer (storage engine per-connection information). + + To avoid unclean deactivation (uninstall) of storage engine plugin + in the middle of transaction, additional storage engine plugin + lock is acquired. + + If ha_data is not null and storage engine plugin was not locked + by thd_set_ha_data() in this connection before, storage engine + plugin gets locked. + + If ha_data is null and storage engine plugin was locked by + thd_set_ha_data() in this connection before, storage engine + plugin lock gets released. + + If handlerton::close_connection() didn't reset ha_data, server does + it immediately after calling handlerton::close_connection(). +*/ +void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, + const void *ha_data); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/code/meosdb/mysql55/mysql/plugin_audit.h b/code/meosdb/mysql55/mysql/plugin_audit.h new file mode 100644 index 0000000..f24913f --- /dev/null +++ b/code/meosdb/mysql55/mysql/plugin_audit.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2007 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_audit_h +#define _my_audit_h + +/************************************************************************* + API for Audit plugin. (MYSQL_AUDIT_PLUGIN) +*/ + +#include "plugin.h" + +#define MYSQL_AUDIT_CLASS_MASK_SIZE 1 + +#define MYSQL_AUDIT_INTERFACE_VERSION 0x0200 + +/* + The first word in every event class struct indicates the specific + class of the event. +*/ +struct mysql_event +{ + unsigned int event_class; +}; + + +/************************************************************************* + AUDIT CLASS : GENERAL + + LOG events occurs before emitting to the general query log. + ERROR events occur before transmitting errors to the user. + RESULT events occur after transmitting a resultset to the user. + STATUS events occur after transmitting a resultset or errors + to the user. +*/ + +#define MYSQL_AUDIT_GENERAL_CLASS 0 +#define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) +#define MYSQL_AUDIT_GENERAL_LOG 0 +#define MYSQL_AUDIT_GENERAL_ERROR 1 +#define MYSQL_AUDIT_GENERAL_RESULT 2 +#define MYSQL_AUDIT_GENERAL_STATUS 3 + +struct mysql_event_general +{ + unsigned int event_class; + unsigned int event_subclass; + int general_error_code; + unsigned long general_thread_id; + const char *general_user; + unsigned int general_user_length; + const char *general_command; + unsigned int general_command_length; + const char *general_query; + unsigned int general_query_length; + struct charset_info_st *general_charset; + unsigned long long general_time; + unsigned long long general_rows; +}; + + +/* + AUDIT CLASS : CONNECTION + + CONNECT occurs after authentication phase is completed. + DISCONNECT occurs after connection is terminated. + CHANGE_USER occurs after COM_CHANGE_USER RPC is completed. +*/ + +#define MYSQL_AUDIT_CONNECTION_CLASS 1 +#define MYSQL_AUDIT_CONNECTION_CLASSMASK (1 << MYSQL_AUDIT_CONNECTION_CLASS) +#define MYSQL_AUDIT_CONNECTION_CONNECT 0 +#define MYSQL_AUDIT_CONNECTION_DISCONNECT 1 +#define MYSQL_AUDIT_CONNECTION_CHANGE_USER 2 + +struct mysql_event_connection +{ + unsigned int event_class; + unsigned int event_subclass; + int status; + unsigned long thread_id; + const char *user; + unsigned int user_length; + const char *priv_user; + unsigned int priv_user_length; + const char *external_user; + unsigned int external_user_length; + const char *proxy_user; + unsigned int proxy_user_length; + const char *host; + unsigned int host_length; + const char *ip; + unsigned int ip_length; + const char *database; + unsigned int database_length; +}; + + +/************************************************************************* + Here we define the descriptor structure, that is referred from + st_mysql_plugin. + + release_thd() event occurs when the event class consumer is to be + disassociated from the specified THD. This would typically occur + before some operation which may require sleeping - such as when + waiting for the next query from the client. + + event_notify() is invoked whenever an event occurs which is of any + class for which the plugin has interest. The first word of the + mysql_event argument indicates the specific event class and the + remainder of the structure is as required for that class. + + class_mask is an array of bits used to indicate what event classes + that this plugin wants to receive. +*/ + +struct st_mysql_audit +{ + int interface_version; + void (*release_thd)(MYSQL_THD); + void (*event_notify)(MYSQL_THD, const struct mysql_event *); + unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; +}; + + +#endif diff --git a/code/meosdb/mysql55/mysql/plugin_auth.h b/code/meosdb/mysql55/mysql/plugin_auth.h new file mode 100644 index 0000000..aee16e9 --- /dev/null +++ b/code/meosdb/mysql55/mysql/plugin_auth.h @@ -0,0 +1,125 @@ +#ifndef MYSQL_PLUGIN_AUTH_INCLUDED +/* Copyright (C) 2010 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +/** + @file + + Authentication Plugin API. + + This file defines the API for server authentication plugins. +*/ + +#define MYSQL_PLUGIN_AUTH_INCLUDED + +#include + +#define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0100 + +#include + +/* defines for MYSQL_SERVER_AUTH_INFO.password_used */ + +#define PASSWORD_USED_NO 0 +#define PASSWORD_USED_YES 1 +#define PASSWORD_USED_NO_MENTION 2 + + +/** + Provides server plugin access to authentication information +*/ +typedef struct st_mysql_server_auth_info +{ + /** + User name as sent by the client and shown in USER(). + NULL if the client packet with the user name was not received yet. + */ + char *user_name; + + /** + Length of user_name + */ + unsigned int user_name_length; + + /** + A corresponding column value from the mysql.user table for the + matching account name + */ + const char *auth_string; + + /** + Length of auth_string + */ + unsigned long auth_string_length; + + /** + Matching account name as found in the mysql.user table. + A plugin can override it with another name that will be + used by MySQL for authorization, and shown in CURRENT_USER() + */ + char authenticated_as[MYSQL_USERNAME_LENGTH+1]; + + + /** + The unique user name that was used by the plugin to authenticate. + Plugins should put null-terminated UTF-8 here. + Available through the @@EXTERNAL_USER variable. + */ + char external_user[512]; + + /** + This only affects the "Authentication failed. Password used: %s" + error message. has the following values : + 0 : %s will be NO. + 1 : %s will be YES. + 2 : there will be no %s. + Set it as appropriate or ignore at will. + */ + int password_used; + + /** + Set to the name of the connected client host, if it can be resolved, + or to its IP address otherwise. + */ + const char *host_or_ip; + + /** + Length of host_or_ip + */ + unsigned int host_or_ip_length; + +} MYSQL_SERVER_AUTH_INFO; + +/** + Server authentication plugin descriptor +*/ +struct st_mysql_auth +{ + int interface_version; /** version plugin uses */ + /** + A plugin that a client must use for authentication with this server + plugin. Can be NULL to mean "any plugin". + */ + const char *client_auth_plugin; + /** + Function provided by the plugin which should perform authentication (using + the vio functions if necessary) and return 0 if successful. The plugin can + also fill the info.authenticated_as field if a different username should be + used for authorization. + */ + int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info); +}; +#endif + diff --git a/code/meosdb/mysql55/mysql/plugin_auth_common.h b/code/meosdb/mysql55/mysql/plugin_auth_common.h new file mode 100644 index 0000000..0447b03 --- /dev/null +++ b/code/meosdb/mysql55/mysql/plugin_auth_common.h @@ -0,0 +1,105 @@ +#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED +/* Copyright (C) 2010 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +/** + @file + + This file defines constants and data structures that are the same for + both client- and server-side authentication plugins. +*/ +#define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED + +/** the max allowed length for a user name */ +#define MYSQL_USERNAME_LENGTH 48 + +/** + return values of the plugin authenticate_user() method. +*/ + +/** + Authentication failed. Additionally, all other CR_xxx values + (libmysql error code) can be used too. + + The client plugin may set the error code and the error message directly + in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error + code was returned, an error message in the MYSQL structure will be + overwritten. If CR_ERROR is returned without setting the error in MYSQL, + CR_UNKNOWN_ERROR will be user. +*/ +#define CR_ERROR 0 +/** + Authentication (client part) was successful. It does not mean that the + authentication as a whole was successful, usually it only means + that the client was able to send the user name and the password to the + server. If CR_OK is returned, the libmysql reads the next packet expecting + it to be one of OK, ERROR, or CHANGE_PLUGIN packets. +*/ +#define CR_OK -1 +/** + Authentication was successful. + It means that the client has done its part successfully and also that + a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN). + In this case, libmysql will not read a packet from the server, + but it will use the data at mysql->net.read_pos. + + A plugin may return this value if the number of roundtrips in the + authentication protocol is not known in advance, and the client plugin + needs to read one packet more to determine if the authentication is finished + or not. +*/ +#define CR_OK_HANDSHAKE_COMPLETE -2 + +typedef struct st_plugin_vio_info +{ + enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, + MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; + int socket; /**< it's set, if the protocol is SOCKET or TCP */ +#ifdef _WIN32 + HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */ +#endif +} MYSQL_PLUGIN_VIO_INFO; + +/** + Provides plugin access to communication channel +*/ +typedef struct st_plugin_vio +{ + /** + Plugin provides a pointer reference and this function sets it to the + contents of any incoming packet. Returns the packet length, or -1 if + the plugin should terminate. + */ + int (*read_packet)(struct st_plugin_vio *vio, + unsigned char **buf); + + /** + Plugin provides a buffer with data and the length and this + function sends it as a packet. Returns 0 on success, 1 on failure. + */ + int (*write_packet)(struct st_plugin_vio *vio, + const unsigned char *packet, + int packet_len); + + /** + Fills in a st_plugin_vio_info structure, providing the information + about the connection. + */ + void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); + +} MYSQL_PLUGIN_VIO; + +#endif + diff --git a/code/meosdb/mysql55/mysql/plugin_ftparser.h b/code/meosdb/mysql55/mysql/plugin_ftparser.h new file mode 100644 index 0000000..9e3b7d1 --- /dev/null +++ b/code/meosdb/mysql55/mysql/plugin_ftparser.h @@ -0,0 +1,211 @@ +/* Copyright (C) 2005 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_plugin_ftparser_h +#define _my_plugin_ftparser_h +#include "plugin.h" + +/************************************************************************* + API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) +*/ + +#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100 + +/* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */ +enum enum_ftparser_mode +{ +/* + Fast and simple mode. This mode is used for indexing, and natural + language queries. + + The parser is expected to return only those words that go into the + index. Stopwords or too short/long words should not be returned. The + 'boolean_info' argument of mysql_add_word() does not have to be set. +*/ + MYSQL_FTPARSER_SIMPLE_MODE= 0, + +/* + Parse with stopwords mode. This mode is used in boolean searches for + "phrase matching." + + The parser is not allowed to ignore words in this mode. Every word + should be returned, including stopwords and words that are too short + or long. The 'boolean_info' argument of mysql_add_word() does not + have to be set. +*/ + MYSQL_FTPARSER_WITH_STOPWORDS= 1, + +/* + Parse in boolean mode. This mode is used to parse a boolean query string. + + The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO + structure in the 'boolean_info' argument to mysql_add_word(). + Usually that means that the parser should recognize boolean operators + in the parsing stream and set appropriate fields in + MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As for + MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored. + Instead, use FT_TOKEN_STOPWORD for the token type of such a word. +*/ + MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 +}; + +/* + Token types for boolean mode searching (used for the type member of + MYSQL_FTPARSER_BOOLEAN_INFO struct) + + FT_TOKEN_EOF: End of data. + FT_TOKEN_WORD: Regular word. + FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression). + FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression). + FT_TOKEN_STOPWORD: Stopword. +*/ + +enum enum_ft_token_type +{ + FT_TOKEN_EOF= 0, + FT_TOKEN_WORD= 1, + FT_TOKEN_LEFT_PAREN= 2, + FT_TOKEN_RIGHT_PAREN= 3, + FT_TOKEN_STOPWORD= 4 +}; + +/* + This structure is used in boolean search mode only. It conveys + boolean-mode metadata to the MySQL search engine for every word in + the search query. A valid instance of this structure must be filled + in by the plugin parser and passed as an argument in the call to + mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM + structure) when a query is parsed in boolean mode. + + type: The token type. Should be one of the enum_ft_token_type values. + + yesno: Whether the word must be present for a match to occur: + >0 Must be present + <0 Must not be present + 0 Neither; the word is optional but its presence increases the relevance + With the default settings of the ft_boolean_syntax system variable, + >0 corresponds to the '+' operator, <0 corrresponds to the '-' operator, + and 0 means neither operator was used. + + weight_adjust: A weighting factor that determines how much a match + for the word counts. Positive values increase, negative - decrease the + relative word's importance in the query. + + wasign: The sign of the word's weight in the query. If it's non-negative + the match for the word will increase document relevance, if it's + negative - decrease (the word becomes a "noise word", the less of it the + better). + + trunc: Corresponds to the '*' operator in the default setting of the + ft_boolean_syntax system variable. +*/ + +typedef struct st_mysql_ftparser_boolean_info +{ + enum enum_ft_token_type type; + int yesno; + int weight_adjust; + char wasign; + char trunc; + /* These are parser state and must be removed. */ + char prev; + char *quot; +} MYSQL_FTPARSER_BOOLEAN_INFO; + +/* + The following flag means that buffer with a string (document, word) + may be overwritten by the caller before the end of the parsing (that is + before st_mysql_ftparser::deinit() call). If one needs the string + to survive between two successive calls of the parsing function, she + needs to save a copy of it. The flag may be set by MySQL before calling + st_mysql_ftparser::parse(), or it may be set by a plugin before calling + st_mysql_ftparser_param::mysql_parse() or + st_mysql_ftparser_param::mysql_add_word(). +*/ +#define MYSQL_FTFLAGS_NEED_COPY 1 + +/* + An argument of the full-text parser plugin. This structure is + filled in by MySQL server and passed to the parsing function of the + plugin as an in/out parameter. + + mysql_parse: A pointer to the built-in parser implementation of the + server. It's set by the server and can be used by the parser plugin + to invoke the MySQL default parser. If plugin's role is to extract + textual data from .doc, .pdf or .xml content, it might extract + plaintext from the content, and then pass the text to the default + MySQL parser to be parsed. + + mysql_add_word: A server callback to add a new word. When parsing + a document, the server sets this to point at a function that adds + the word to MySQL full-text index. When parsing a search query, + this function will add the new word to the list of words to search + for. The boolean_info argument can be NULL for all cases except + when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO. + + ftparser_state: A generic pointer. The plugin can set it to point + to information to be used internally for its own purposes. + + mysql_ftparam: This is set by the server. It is used by MySQL functions + called via mysql_parse() and mysql_add_word() callback. The plugin + should not modify it. + + cs: Information about the character set of the document or query string. + + doc: A pointer to the document or query string to be parsed. + + length: Length of the document or query string, in bytes. + + flags: See MYSQL_FTFLAGS_* constants above. + + mode: The parsing mode. With boolean operators, with stopwords, or + nothing. See enum_ftparser_mode above. +*/ + +typedef struct st_mysql_ftparser_param +{ + int (*mysql_parse)(struct st_mysql_ftparser_param *, + char *doc, int doc_len); + int (*mysql_add_word)(struct st_mysql_ftparser_param *, + char *word, int word_len, + MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); + void *ftparser_state; + void *mysql_ftparam; + struct charset_info_st *cs; + char *doc; + int length; + int flags; + enum enum_ftparser_mode mode; +} MYSQL_FTPARSER_PARAM; + +/* + Full-text parser descriptor. + + interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION. + The parsing, initialization, and deinitialization functions are + invoked per SQL statement for which the parser is used. +*/ + +struct st_mysql_ftparser +{ + int interface_version; + int (*parse)(MYSQL_FTPARSER_PARAM *param); + int (*init)(MYSQL_FTPARSER_PARAM *param); + int (*deinit)(MYSQL_FTPARSER_PARAM *param); +}; + + +#endif + diff --git a/code/meosdb/mysql55/mysql/psi/mysql_file.h b/code/meosdb/mysql55/mysql/psi/mysql_file.h new file mode 100644 index 0000000..59bc8ed --- /dev/null +++ b/code/meosdb/mysql55/mysql/psi/mysql_file.h @@ -0,0 +1,1434 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef MYSQL_FILE_H +#define MYSQL_FILE_H + +#include + +/* For strlen() */ +#include +/* For MY_STAT */ +#include +/* For my_chsize */ +#include + +/** + @file mysql/psi/mysql_file.h + Instrumentation helpers for mysys file io. + This header file provides the necessary declarations + to use the mysys file API with the performance schema instrumentation. + In some compilers (SunStudio), 'static inline' functions, when declared + but not used, are not optimized away (because they are unused) by default, + so that including a static inline function from a header file does + create unwanted dependencies, causing unresolved symbols at link time. + Other compilers, like gcc, optimize these dependencies by default. + + Since the instrumented APIs declared here are wrapper on top + of mysys file io APIs, including mysql/psi/mysql_file.h assumes that + the dependency on my_sys already exists. +*/ + +#include "mysql/psi/psi.h" + +/** + @defgroup File_instrumentation File Instrumentation + @ingroup Instrumentation_interface + @{ +*/ + +/** + @def mysql_file_fgets(P1, P2, F) + Instrumented fgets. + @c mysql_file_fgets is a replacement for @c fgets. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fgets(P1, P2, F) \ + inline_mysql_file_fgets(__FILE__, __LINE__, P1, P2, F) +#else + #define mysql_file_fgets(P1, P2, F) \ + inline_mysql_file_fgets(P1, P2, F) +#endif + +/** + @def mysql_file_fgetc(F) + Instrumented fgetc. + @c mysql_file_fgetc is a replacement for @c fgetc. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fgetc(F) inline_mysql_file_fgetc(__FILE__, __LINE__, F) +#else + #define mysql_file_fgetc(F) inline_mysql_file_fgetc(F) +#endif + +/** + @def mysql_file_fputs(P1, F) + Instrumented fputs. + @c mysql_file_fputs is a replacement for @c fputs. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fputs(P1, F) \ + inline_mysql_file_fputs(__FILE__, __LINE__, P1, F) +#else + #define mysql_file_fputs(P1, F)\ + inline_mysql_file_fputs(P1, F) +#endif + +/** + @def mysql_file_fputc(P1, F) + Instrumented fputc. + @c mysql_file_fputc is a replacement for @c fputc. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fputc(P1, F) \ + inline_mysql_file_fputc(__FILE__, __LINE__, P1, F) +#else + #define mysql_file_fputc(P1, F) \ + inline_mysql_file_fputc(P1, F) +#endif + +/** + @def mysql_file_fprintf + Instrumented fprintf. + @c mysql_file_fprintf is a replacement for @c fprintf. +*/ +#define mysql_file_fprintf inline_mysql_file_fprintf + +/** + @def mysql_file_vfprintf(F, P1, P2) + Instrumented vfprintf. + @c mysql_file_vfprintf is a replacement for @c vfprintf. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_vfprintf(F, P1, P2) \ + inline_mysql_file_vfprintf(__FILE__, __LINE__, F, P1, P2) +#else + #define mysql_file_vfprintf(F, P1, P2) \ + inline_mysql_file_vfprintf(F, P1, P2) +#endif + +/** + @def mysql_file_fflush(F, P1, P2) + Instrumented fflush. + @c mysql_file_fflush is a replacement for @c fflush. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fflush(F) \ + inline_mysql_file_fflush(__FILE__, __LINE__, F) +#else + #define mysql_file_fflush(F) \ + inline_mysql_file_fflush(F) +#endif + +/** + @def mysql_file_feof(F) + Instrumented feof. + @c mysql_file_feof is a replacement for @c feof. +*/ +#define mysql_file_feof(F) inline_mysql_file_feof(F) + +/** + @def mysql_file_fstat(FN, S, FL) + Instrumented fstat. + @c mysql_file_fstat is a replacement for @c my_fstat. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fstat(FN, S, FL) \ + inline_mysql_file_fstat(__FILE__, __LINE__, FN, S, FL) +#else + #define mysql_file_fstat(FN, S, FL) \ + inline_mysql_file_fstat(FN, S, FL) +#endif + +/** + @def mysql_file_stat(K, FN, S, FL) + Instrumented stat. + @c mysql_file_stat is a replacement for @c my_stat. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_stat(K, FN, S, FL) \ + inline_mysql_file_stat(K, __FILE__, __LINE__, FN, S, FL) +#else + #define mysql_file_stat(K, FN, S, FL) \ + inline_mysql_file_stat(FN, S, FL) +#endif + +/** + @def mysql_file_chsize(F, P1, P2, P3) + Instrumented chsize. + @c mysql_file_chsize is a replacement for @c my_chsize. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_chsize(F, P1, P2, P3) \ + inline_mysql_file_chsize(__FILE__, __LINE__, F, P1, P2, P3) +#else + #define mysql_file_chsize(F, P1, P2, P3) \ + inline_mysql_file_chsize(F, P1, P2, P3) +#endif + +/** + @def mysql_file_fopen(K, N, F1, F2) + Instrumented fopen. + @c mysql_file_fopen is a replacement for @c my_fopen. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fopen(K, N, F1, F2) \ + inline_mysql_file_fopen(K, __FILE__, __LINE__, N, F1, F2) +#else + #define mysql_file_fopen(K, N, F1, F2) \ + inline_mysql_file_fopen(N, F1, F2) +#endif + +/** + @def mysql_file_fclose(FD, FL) + Instrumented fclose. + @c mysql_file_fclose is a replacement for @c my_fclose. + Without the instrumentation, this call will have the same behavior as the + undocumented and possibly platform specific my_fclose(NULL, ...) behavior. + With the instrumentation, mysql_fclose(NULL, ...) will safely return 0, + which is an extension compared to my_fclose and is therefore compliant. + mysql_fclose is on purpose *not* implementing + @code DBUG_ASSERT(file != NULL) @endcode, + since doing so could introduce regressions. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fclose(FD, FL) \ + inline_mysql_file_fclose(__FILE__, __LINE__, FD, FL) +#else + #define mysql_file_fclose(FD, FL) \ + inline_mysql_file_fclose(FD, FL) +#endif + +/** + @def mysql_file_fread(FD, P1, P2, P3) + Instrumented fread. + @c mysql_file_fread is a replacement for @c my_fread. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fread(FD, P1, P2, P3) \ + inline_mysql_file_fread(__FILE__, __LINE__, FD, P1, P2, P3) +#else + #define mysql_file_fread(FD, P1, P2, P3) \ + inline_mysql_file_fread(FD, P1, P2, P3) +#endif + +/** + @def mysql_file_fwrite(FD, P1, P2, P3) + Instrumented fwrite. + @c mysql_file_fwrite is a replacement for @c my_fwrite. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fwrite(FD, P1, P2, P3) \ + inline_mysql_file_fwrite(__FILE__, __LINE__, FD, P1, P2, P3) +#else + #define mysql_file_fwrite(FD, P1, P2, P3) \ + inline_mysql_file_fwrite(FD, P1, P2, P3) +#endif + +/** + @def mysql_file_fseek(FD, P, W, F) + Instrumented fseek. + @c mysql_file_fseek is a replacement for @c my_fseek. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fseek(FD, P, W, F) \ + inline_mysql_file_fseek(__FILE__, __LINE__, FD, P, W, F) +#else + #define mysql_file_fseek(FD, P, W, F) \ + inline_mysql_file_fseek(FD, P, W, F) +#endif + +/** + @def mysql_file_ftell(FD, F) + Instrumented ftell. + @c mysql_file_ftell is a replacement for @c my_ftell. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_ftell(FD, F) \ + inline_mysql_file_ftell(__FILE__, __LINE__, FD, F) +#else + #define mysql_file_ftell(FD, F) \ + inline_mysql_file_ftell(FD, F) +#endif + +/** + @def mysql_file_create(K, N, F1, F2, F3) + Instrumented create. + @c mysql_file_create is a replacement for @c my_create. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_create(K, N, F1, F2, F3) \ + inline_mysql_file_create(K, __FILE__, __LINE__, N, F1, F2, F3) +#else + #define mysql_file_create(K, N, F1, F2, F3) \ + inline_mysql_file_create(N, F1, F2, F3) +#endif + +/** + @def mysql_file_create_temp(K, T, D, P, M, F) + Instrumented create_temp_file. + @c mysql_file_create_temp is a replacement for @c create_temp_file. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_create_temp(K, T, D, P, M, F) \ + inline_mysql_file_create_temp(K, T, D, P, M, F) +#else + #define mysql_file_create_temp(K, T, D, P, M, F) \ + inline_mysql_file_create_temp(T, D, P, M, F) +#endif + +/** + @def mysql_file_open(K, N, F1, F2) + Instrumented open. + @c mysql_file_open is a replacement for @c my_open. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_open(K, N, F1, F2) \ + inline_mysql_file_open(K, __FILE__, __LINE__, N, F1, F2) +#else + #define mysql_file_open(K, N, F1, F2) \ + inline_mysql_file_open(N, F1, F2) +#endif + +/** + @def mysql_file_close(FD, F) + Instrumented close. + @c mysql_file_close is a replacement for @c my_close. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_close(FD, F) \ + inline_mysql_file_close(__FILE__, __LINE__, FD, F) +#else + #define mysql_file_close(FD, F) \ + inline_mysql_file_close(FD, F) +#endif + +/** + @def mysql_file_read(FD, B, S, F) + Instrumented read. + @c mysql_read is a replacement for @c my_read. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_read(FD, B, S, F) \ + inline_mysql_file_read(__FILE__, __LINE__, FD, B, S, F) +#else + #define mysql_file_read(FD, B, S, F) \ + inline_mysql_file_read(FD, B, S, F) +#endif + +/** + @def mysql_file_write(FD, B, S, F) + Instrumented write. + @c mysql_file_write is a replacement for @c my_write. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_write(FD, B, S, F) \ + inline_mysql_file_write(__FILE__, __LINE__, FD, B, S, F) +#else + #define mysql_file_write(FD, B, S, F) \ + inline_mysql_file_write(FD, B, S, F) +#endif + +/** + @def mysql_file_pread(FD, B, S, O, F) + Instrumented pread. + @c mysql_pread is a replacement for @c my_pread. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_pread(FD, B, S, O, F) \ + inline_mysql_file_pread(__FILE__, __LINE__, FD, B, S, O, F) +#else + #define mysql_file_pread(FD, B, S, O, F) \ + inline_mysql_file_pread(FD, B, S, O, F) +#endif + +/** + @def mysql_file_pwrite(FD, B, S, O, F) + Instrumented pwrite. + @c mysql_file_pwrite is a replacement for @c my_pwrite. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_pwrite(FD, B, S, O, F) \ + inline_mysql_file_pwrite(__FILE__, __LINE__, FD, B, S, O, F) +#else + #define mysql_file_pwrite(FD, B, S, O, F) \ + inline_mysql_file_pwrite(FD, B, S, O, F) +#endif + +/** + @def mysql_file_seek(FD, P, W, F) + Instrumented seek. + @c mysql_file_seek is a replacement for @c my_seek. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_seek(FD, P, W, F) \ + inline_mysql_file_seek(__FILE__, __LINE__, FD, P, W, F) +#else + #define mysql_file_seek(FD, P, W, F) \ + inline_mysql_file_seek(FD, P, W, F) +#endif + +/** + @def mysql_file_tell(FD, F) + Instrumented tell. + @c mysql_file_tell is a replacement for @c my_tell. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_tell(FD, F) \ + inline_mysql_file_tell(__FILE__, __LINE__, FD, F) +#else + #define mysql_file_tell(FD, F) \ + inline_mysql_file_tell(FD, F) +#endif + +/** + @def mysql_file_delete(K, P1, P2) + Instrumented delete. + @c mysql_file_delete is a replacement for @c my_delete. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_delete(K, P1, P2) \ + inline_mysql_file_delete(K, __FILE__, __LINE__, P1, P2) +#else + #define mysql_file_delete(K, P1, P2) \ + inline_mysql_file_delete(P1, P2) +#endif + +/** + @def mysql_file_rename(K, P1, P2, P3) + Instrumented rename. + @c mysql_file_rename is a replacement for @c my_rename. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_rename(K, P1, P2, P3) \ + inline_mysql_file_rename(K, __FILE__, __LINE__, P1, P2, P3) +#else + #define mysql_file_rename(K, P1, P2, P3) \ + inline_mysql_file_rename(P1, P2, P3) +#endif + +/** + @def mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) + Instrumented create with symbolic link. + @c mysql_file_create_with_symlink is a replacement + for @c my_create_with_symlink. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ + inline_mysql_file_create_with_symlink(K, __FILE__, __LINE__, \ + P1, P2, P3, P4, P5) +#else + #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ + inline_mysql_file_create_with_symlink(P1, P2, P3, P4, P5) +#endif + +/** + @def mysql_file_delete_with_symlink(K, P1, P2) + Instrumented delete with symbolic link. + @c mysql_file_delete_with_symlink is a replacement + for @c my_delete_with_symlink. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_delete_with_symlink(K, P1, P2) \ + inline_mysql_file_delete_with_symlink(K, __FILE__, __LINE__, P1, P2) +#else + #define mysql_file_delete_with_symlink(K, P1, P2) \ + inline_mysql_file_delete_with_symlink(P1, P2) +#endif + +/** + @def mysql_file_rename_with_symlink(K, P1, P2, P3) + Instrumented rename with symbolic link. + @c mysql_file_rename_with_symlink is a replacement + for @c my_rename_with_symlink. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ + inline_mysql_file_rename_with_symlink(K, __FILE__, __LINE__, P1, P2, P3) +#else + #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ + inline_mysql_file_rename_with_symlink(P1, P2, P3) +#endif + +/** + @def mysql_file_sync(P1, P2) + Instrumented file sync. + @c mysql_file_sync is a replacement for @c my_sync. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_sync(P1, P2) \ + inline_mysql_file_sync(__FILE__, __LINE__, P1, P2) +#else + #define mysql_file_sync(P1, P2) \ + inline_mysql_file_sync(P1, P2) +#endif + +/** + An instrumented FILE structure. + @sa MYSQL_FILE +*/ +struct st_mysql_file +{ + /** The real file. */ + FILE *m_file; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c MYSQL_FILE interface. + */ + struct PSI_file *m_psi; +}; + +/** + Type of an instrumented file. + @c MYSQL_FILE is a drop-in replacement for @c FILE. + @sa mysql_file_open +*/ +typedef struct st_mysql_file MYSQL_FILE; + +static inline char * +inline_mysql_file_fgets( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + char *str, int size, MYSQL_FILE *file) +{ + char *result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) size, src_file, src_line); + } +#endif + result= fgets(str, size, file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, result ? strlen(result) : 0); +#endif + return result; +} + +static inline int +inline_mysql_file_fgetc( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 1, src_file, src_line); + } +#endif + result= fgetc(file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 1); +#endif + return result; +} + +static inline int +inline_mysql_file_fputs( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + const char *str, MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + size_t bytes= 0; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + { + bytes= str ? strlen(str) : 0; + PSI_server->start_file_wait(locker, bytes, src_file, src_line); + } + } +#endif + result= fputs(str, file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, bytes); +#endif + return result; +} + +static inline int +inline_mysql_file_fputc( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + char c, MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 1, src_file, src_line); + } +#endif + result= fputc(c, file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 1); +#endif + return result; +} + +static inline int +inline_mysql_file_fprintf(MYSQL_FILE *file, const char *format, ...) +{ + /* + TODO: figure out how to pass src_file and src_line from the caller. + */ + int result; + va_list args; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, __FILE__, __LINE__); + } +#endif + va_start(args, format); + result= vfprintf(file->m_file, format, args); + va_end(args); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) result); +#endif + return result; +} + +static inline int +inline_mysql_file_vfprintf( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, const char *format, va_list args) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= vfprintf(file->m_file, format, args); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) result); +#endif + return result; +} + +static inline int +inline_mysql_file_fflush( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_FLUSH); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= fflush(file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int inline_mysql_file_feof(MYSQL_FILE *file) +{ + /* Not instrumented, there is no wait involved */ + return feof(file->m_file); +} + +static inline int +inline_mysql_file_fstat( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + int filenr, MY_STAT *stat_area, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, filenr, + PSI_FILE_FSTAT); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_fstat(filenr, stat_area, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline MY_STAT * +inline_mysql_file_stat( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *path, MY_STAT *stat_area, myf flags) +{ + MY_STAT *result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, + key, PSI_FILE_STAT, + path, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + result= my_stat(path, stat_area, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_chsize( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, my_off_t newlength, int filler, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_CHSIZE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) newlength, src_file, + src_line); + } +#endif + result= my_chsize(file, newlength, filler, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) newlength); +#endif + return result; +} + +static inline MYSQL_FILE* +inline_mysql_file_fopen( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *filename, int flags, myf myFlags) +{ + MYSQL_FILE *that; + that= (MYSQL_FILE*) my_malloc(sizeof(MYSQL_FILE), MYF(MY_WME)); + if (likely(that != NULL)) + { + that->m_psi= NULL; + { +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker + (&state, key, PSI_FILE_STREAM_OPEN, filename, that); + if (likely(locker != NULL)) + that->m_psi= PSI_server->start_file_open_wait(locker, src_file, + src_line); + } +#endif + that->m_file= my_fopen(filename, flags, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait(locker); +#endif + if (unlikely(that->m_file == NULL)) + { + my_free(that); + return NULL; + } + } + } + return that; +} + +static inline int +inline_mysql_file_fclose( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, myf flags) +{ + int result= 0; + if (likely(file != NULL)) + { +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + DBUG_ASSERT(file != NULL); + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_STREAM_CLOSE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_fclose(file->m_file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + my_free(file); + } + return result; +} + +static inline size_t +inline_mysql_file_fread( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, uchar *buffer, size_t count, myf flags) +{ + size_t result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_fread(file->m_file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_read; + if (flags & (MY_NABP | MY_FNABP)) + bytes_read= (result == 0) ? count : 0; + else + bytes_read= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_read); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_fwrite( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, const uchar *buffer, size_t count, myf flags) +{ + size_t result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_fwrite(file->m_file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_written; + if (flags & (MY_NABP | MY_FNABP)) + bytes_written= (result == 0) ? count : 0; + else + bytes_written= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_written); + } +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_fseek( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, my_off_t pos, int whence, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_SEEK); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_fseek(file->m_file, pos, whence, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_ftell( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_TELL); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_ftell(file->m_file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline File +inline_mysql_file_create( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *filename, int create_flags, int access_flags, myf myFlags) +{ + File file; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_CREATE, + filename, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + file= my_create(filename, create_flags, access_flags, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait_and_bind_to_descriptor(locker, file); +#endif + return file; +} + +static inline File +inline_mysql_file_create_temp( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, +#endif + char *to, const char *dir, const char *pfx, int mode, myf myFlags) +{ + File file; + /* + TODO: This event is instrumented, but not timed. + The problem is that the file name is now known + before the create_temp_file call. + */ + file= create_temp_file(to, dir, pfx, mode, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server != NULL)) + PSI_server->create_file(key, to, file); +#endif + return file; +} + +static inline File +inline_mysql_file_open( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *filename, int flags, myf myFlags) +{ + File file; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_OPEN, + filename, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + file= my_open(filename, flags, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait_and_bind_to_descriptor(locker, file); +#endif + return file; +} + +static inline int +inline_mysql_file_close( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_CLOSE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_close(file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline size_t +inline_mysql_file_read( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, uchar *buffer, size_t count, myf flags) +{ + size_t result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_read(file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_read; + if (flags & (MY_NABP | MY_FNABP)) + bytes_read= (result == 0) ? count : 0; + else + bytes_read= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_read); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_write( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, const uchar *buffer, size_t count, myf flags) +{ + size_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_write(file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_written; + if (flags & (MY_NABP | MY_FNABP)) + bytes_written= (result == 0) ? count : 0; + else + bytes_written= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_written); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_pread( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, uchar *buffer, size_t count, my_off_t offset, myf flags) +{ + size_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_pread(file, buffer, count, offset, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_read; + if (flags & (MY_NABP | MY_FNABP)) + bytes_read= (result == 0) ? count : 0; + else + bytes_read= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_read); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_pwrite( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, const uchar *buffer, size_t count, my_off_t offset, myf flags) +{ + size_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_pwrite(file, buffer, count, offset, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_written; + if (flags & (MY_NABP | MY_FNABP)) + bytes_written= (result == 0) ? count : 0; + else + bytes_written= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_written); + } +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_seek( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, my_off_t pos, int whence, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, PSI_FILE_SEEK); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_seek(file, pos, whence, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_tell( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, PSI_FILE_TELL); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_tell(file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_delete( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *name, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_DELETE, + name, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_delete(name, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_rename( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *from, const char *to, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_RENAME, + to, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_rename(from, to, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline File +inline_mysql_file_create_with_symlink( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *linkname, const char *filename, int create_flags, + int access_flags, myf flags) +{ + File file; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_CREATE, + filename, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + file= my_create_with_symlink(linkname, filename, create_flags, access_flags, + flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait_and_bind_to_descriptor(locker, file); +#endif + return file; +} + +static inline int +inline_mysql_file_delete_with_symlink( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *name, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_DELETE, + name, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_delete_with_symlink(name, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_rename_with_symlink( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *from, const char *to, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_RENAME, + to, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_rename_with_symlink(from, to, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_sync( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File fd, myf flags) +{ + int result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, fd, PSI_FILE_SYNC); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_sync(fd, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +/** @} (end of group File_instrumentation) */ + +#endif + diff --git a/code/meosdb/mysql55/mysql/psi/mysql_thread.h b/code/meosdb/mysql55/mysql/psi/mysql_thread.h new file mode 100644 index 0000000..5d105cc --- /dev/null +++ b/code/meosdb/mysql55/mysql/psi/mysql_thread.h @@ -0,0 +1,1071 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef MYSQL_THREAD_H +#define MYSQL_THREAD_H + +/** + @file mysql/psi/mysql_thread.h + Instrumentation helpers for mysys threads, mutexes, + read write locks and conditions. + This header file provides the necessary declarations + to use the mysys thread API with the performance schema instrumentation. + In some compilers (SunStudio), 'static inline' functions, when declared + but not used, are not optimized away (because they are unused) by default, + so that including a static inline function from a header file does + create unwanted dependencies, causing unresolved symbols at link time. + Other compilers, like gcc, optimize these dependencies by default. + + Since the instrumented APIs declared here are wrapper on top + of my_pthread / safemutex / etc APIs, + including mysql/psi/mysql_thread.h assumes that + the dependency on my_pthread and safemutex already exists. +*/ +/* + Note: there are several orthogonal dimensions here. + + Dimension 1: Instrumentation + HAVE_PSI_INTERFACE is defined when the instrumentation is compiled in. + This may happen both in debug or production builds. + + Dimension 2: Debug + SAFE_MUTEX is defined when debug is compiled in. + This may happen both with and without instrumentation. + + Dimension 3: Platform + Mutexes are implemented with one of: + - the pthread library + - fast mutexes + - window apis + This is implemented by various macro definitions in my_pthread.h + + This causes complexity with '#ifdef'-ery that can't be avoided. +*/ + +#include "mysql/psi/psi.h" + +/** + @defgroup Thread_instrumentation Thread Instrumentation + @ingroup Instrumentation_interface + @{ +*/ + +/** + An instrumented mutex structure. + @sa mysql_mutex_t +*/ +struct st_mysql_mutex +{ + /** The real mutex. */ + pthread_mutex_t m_mutex; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_mutex_t interface. + */ + struct PSI_mutex *m_psi; +}; + +/** + Type of an instrumented mutex. + @c mysql_mutex_t is a drop-in replacement for @c pthread_mutex_t. + @sa mysql_mutex_assert_owner + @sa mysql_mutex_assert_not_owner + @sa mysql_mutex_init + @sa mysql_mutex_lock + @sa mysql_mutex_unlock + @sa mysql_mutex_destroy +*/ +typedef struct st_mysql_mutex mysql_mutex_t; + +/** + An instrumented rwlock structure. + @sa mysql_rwlock_t +*/ +struct st_mysql_rwlock +{ + /** The real rwlock */ + rw_lock_t m_rwlock; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_rwlock_t interface. + */ + struct PSI_rwlock *m_psi; +}; + +/** + An instrumented prlock structure. + @sa mysql_prlock_t +*/ +struct st_mysql_prlock +{ + /** The real prlock */ + rw_pr_lock_t m_prlock; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_rwlock_t interface. + */ + struct PSI_rwlock *m_psi; +}; + +/** + Type of an instrumented rwlock. + @c mysql_rwlock_t is a drop-in replacement for @c pthread_rwlock_t. + @sa mysql_rwlock_init + @sa mysql_rwlock_rdlock + @sa mysql_rwlock_tryrdlock + @sa mysql_rwlock_wrlock + @sa mysql_rwlock_trywrlock + @sa mysql_rwlock_unlock + @sa mysql_rwlock_destroy +*/ +typedef struct st_mysql_rwlock mysql_rwlock_t; + +/** + Type of an instrumented prlock. + A prlock is a read write lock that 'prefers readers' (pr). + @c mysql_prlock_t is a drop-in replacement for @c rw_pr_lock_t. + @sa mysql_prlock_init + @sa mysql_prlock_rdlock + @sa mysql_prlock_wrlock + @sa mysql_prlock_unlock + @sa mysql_prlock_destroy +*/ +typedef struct st_mysql_prlock mysql_prlock_t; + +/** + An instrumented cond structure. + @sa mysql_cond_t +*/ +struct st_mysql_cond +{ + /** The real condition */ + pthread_cond_t m_cond; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_cond_t interface. + */ + struct PSI_cond *m_psi; +}; + +/** + Type of an instrumented condition. + @c mysql_cond_t is a drop-in replacement for @c pthread_cond_t. + @sa mysql_cond_init + @sa mysql_cond_wait + @sa mysql_cond_timedwait + @sa mysql_cond_signal + @sa mysql_cond_broadcast + @sa mysql_cond_destroy +*/ +typedef struct st_mysql_cond mysql_cond_t; + +/* + Consider the following code: + static inline void foo() { bar(); } + when foo() is never called. + + With gcc, foo() is a local static function, so the dependencies + are optimized away at compile time, and there is no dependency on bar(). + With other compilers (HP, Sun Studio), the function foo() implementation + is compiled, and bar() needs to be present to link. + + Due to the existing header dependencies in MySQL code, this header file + is sometime used when it is not needed, which in turn cause link failures + on some platforms. + The proper fix would be to cut these extra dependencies in the calling code. + DISABLE_MYSQL_THREAD_H is a work around to limit dependencies. + DISABLE_MYSQL_PRLOCK_H is similar, and is used to disable specifically + the prlock wrappers. +*/ +#ifndef DISABLE_MYSQL_THREAD_H + +/** + @def mysql_mutex_assert_owner(M) + Wrapper, to use safe_mutex_assert_owner with instrumented mutexes. + @c mysql_mutex_assert_owner is a drop-in replacement + for @c safe_mutex_assert_owner. +*/ +#define mysql_mutex_assert_owner(M) \ + safe_mutex_assert_owner(&(M)->m_mutex) + +/** + @def mysql_mutex_assert_not_owner(M) + Wrapper, to use safe_mutex_assert_not_owner with instrumented mutexes. + @c mysql_mutex_assert_not_owner is a drop-in replacement + for @c safe_mutex_assert_not_owner. +*/ +#define mysql_mutex_assert_not_owner(M) \ + safe_mutex_assert_not_owner(&(M)->m_mutex) + +/** Wrappers for instrumented prlock objects. */ + +#define mysql_prlock_assert_write_owner(M) \ + rw_pr_lock_assert_write_owner(&(M)->m_prlock) + +#define mysql_prlock_assert_not_write_owner(M) \ + rw_pr_lock_assert_not_write_owner(&(M)->m_prlock) + +/** + @def mysql_mutex_init(K, M, A) + Instrumented mutex_init. + @c mysql_mutex_init is a replacement for @c pthread_mutex_init. + @param K The PSI_mutex_key for this instrumented mutex + @param M The mutex to initialize + @param A Mutex attributes +*/ + +#ifdef HAVE_PSI_INTERFACE + #ifdef SAFE_MUTEX + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(K, M, A, __FILE__, __LINE__) + #else + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(K, M, A) + #endif +#else + #ifdef SAFE_MUTEX + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(M, A, __FILE__, __LINE__) + #else + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(M, A) + #endif +#endif + +/** + @def mysql_mutex_destroy(M) + Instrumented mutex_destroy. + @c mysql_mutex_destroy is a drop-in replacement + for @c pthread_mutex_destroy. +*/ +#ifdef SAFE_MUTEX + #define mysql_mutex_destroy(M) \ + inline_mysql_mutex_destroy(M, __FILE__, __LINE__) +#else + #define mysql_mutex_destroy(M) \ + inline_mysql_mutex_destroy(M) +#endif + +/** + @def mysql_mutex_lock(M) + Instrumented mutex_lock. + @c mysql_mutex_lock is a drop-in replacement for @c pthread_mutex_lock. + @param M The mutex to lock +*/ + +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + #define mysql_mutex_lock(M) \ + inline_mysql_mutex_lock(M, __FILE__, __LINE__) +#else + #define mysql_mutex_lock(M) \ + inline_mysql_mutex_lock(M) +#endif + +/** + @def mysql_mutex_trylock(M) + Instrumented mutex_lock. + @c mysql_mutex_trylock is a drop-in replacement + for @c pthread_mutex_trylock. +*/ + +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + #define mysql_mutex_trylock(M) \ + inline_mysql_mutex_trylock(M, __FILE__, __LINE__) +#else + #define mysql_mutex_trylock(M) \ + inline_mysql_mutex_trylock(M) +#endif + +/** + @def mysql_mutex_unlock(M) + Instrumented mutex_unlock. + @c mysql_mutex_unlock is a drop-in replacement for @c pthread_mutex_unlock. +*/ +#ifdef SAFE_MUTEX + #define mysql_mutex_unlock(M) \ + inline_mysql_mutex_unlock(M, __FILE__, __LINE__) +#else + #define mysql_mutex_unlock(M) \ + inline_mysql_mutex_unlock(M) +#endif + +/** + @def mysql_rwlock_init(K, RW) + Instrumented rwlock_init. + @c mysql_rwlock_init is a replacement for @c pthread_rwlock_init. + Note that pthread_rwlockattr_t is not supported in MySQL. + @param K The PSI_rwlock_key for this instrumented rwlock + @param RW The rwlock to initialize +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(K, RW) +#else + #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(RW) +#endif + +/** + @def mysql_prlock_init(K, RW) + Instrumented rw_pr_init. + @c mysql_prlock_init is a replacement for @c rw_pr_init. + @param K The PSI_rwlock_key for this instrumented prlock + @param RW The prlock to initialize +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(K, RW) +#else + #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(RW) +#endif + +/** + @def mysql_rwlock_destroy(RW) + Instrumented rwlock_destroy. + @c mysql_rwlock_destroy is a drop-in replacement + for @c pthread_rwlock_destroy. +*/ +#define mysql_rwlock_destroy(RW) inline_mysql_rwlock_destroy(RW) + +/** + @def mysql_prlock_destroy(RW) + Instrumented rw_pr_destroy. + @c mysql_prlock_destroy is a drop-in replacement + for @c rw_pr_destroy. +*/ +#define mysql_prlock_destroy(RW) inline_mysql_prlock_destroy(RW) + +/** + @def mysql_rwlock_rdlock(RW) + Instrumented rwlock_rdlock. + @c mysql_rwlock_rdlock is a drop-in replacement + for @c pthread_rwlock_rdlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_rdlock(RW) \ + inline_mysql_rwlock_rdlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_rdlock(RW) \ + inline_mysql_rwlock_rdlock(RW) +#endif + +/** + @def mysql_prlock_rdlock(RW) + Instrumented rw_pr_rdlock. + @c mysql_prlock_rdlock is a drop-in replacement + for @c rw_pr_rdlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_prlock_rdlock(RW) \ + inline_mysql_prlock_rdlock(RW, __FILE__, __LINE__) +#else + #define mysql_prlock_rdlock(RW) \ + inline_mysql_prlock_rdlock(RW) +#endif + +/** + @def mysql_rwlock_wrlock(RW) + Instrumented rwlock_wrlock. + @c mysql_rwlock_wrlock is a drop-in replacement + for @c pthread_rwlock_wrlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_wrlock(RW) \ + inline_mysql_rwlock_wrlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_wrlock(RW) \ + inline_mysql_rwlock_wrlock(RW) +#endif + +/** + @def mysql_prlock_wrlock(RW) + Instrumented rw_pr_wrlock. + @c mysql_prlock_wrlock is a drop-in replacement + for @c rw_pr_wrlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_prlock_wrlock(RW) \ + inline_mysql_prlock_wrlock(RW, __FILE__, __LINE__) +#else + #define mysql_prlock_wrlock(RW) \ + inline_mysql_prlock_wrlock(RW) +#endif + +/** + @def mysql_rwlock_tryrdlock(RW) + Instrumented rwlock_tryrdlock. + @c mysql_rwlock_tryrdlock is a drop-in replacement + for @c pthread_rwlock_tryrdlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_tryrdlock(RW) \ + inline_mysql_rwlock_tryrdlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_tryrdlock(RW) \ + inline_mysql_rwlock_tryrdlock(RW) +#endif + +/** + @def mysql_rwlock_trywrlock(RW) + Instrumented rwlock_trywrlock. + @c mysql_rwlock_trywrlock is a drop-in replacement + for @c pthread_rwlock_trywrlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_trywrlock(RW) \ + inline_mysql_rwlock_trywrlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_trywrlock(RW) \ + inline_mysql_rwlock_trywrlock(RW) +#endif + +/** + @def mysql_rwlock_unlock(RW) + Instrumented rwlock_unlock. + @c mysql_rwlock_unlock is a drop-in replacement + for @c pthread_rwlock_unlock. +*/ +#define mysql_rwlock_unlock(RW) inline_mysql_rwlock_unlock(RW) + +/** + @def mysql_prlock_unlock(RW) + Instrumented rw_pr_unlock. + @c mysql_prlock_unlock is a drop-in replacement + for @c rw_pr_unlock. +*/ +#define mysql_prlock_unlock(RW) inline_mysql_prlock_unlock(RW) + +/** + @def mysql_cond_init(K, C, A) + Instrumented cond_init. + @c mysql_cond_init is a replacement for @c pthread_cond_init. + @param C The cond to initialize + @param K The PSI_cond_key for this instrumented cond + @param A Condition attributes +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_cond_init(K, C, A) inline_mysql_cond_init(K, C, A) +#else + #define mysql_cond_init(K, C, A) inline_mysql_cond_init(C, A) +#endif + +/** + @def mysql_cond_destroy(C) + Instrumented cond_destroy. + @c mysql_cond_destroy is a drop-in replacement for @c pthread_cond_destroy. +*/ +#define mysql_cond_destroy(C) inline_mysql_cond_destroy(C) + +/** + @def mysql_cond_wait(C) + Instrumented cond_wait. + @c mysql_cond_wait is a drop-in replacement for @c pthread_cond_wait. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_cond_wait(C, M) \ + inline_mysql_cond_wait(C, M, __FILE__, __LINE__) +#else + #define mysql_cond_wait(C, M) \ + inline_mysql_cond_wait(C, M) +#endif + +/** + @def mysql_cond_timedwait(C, M, W) + Instrumented cond_timedwait. + @c mysql_cond_timedwait is a drop-in replacement + for @c pthread_cond_timedwait. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_cond_timedwait(C, M, W) \ + inline_mysql_cond_timedwait(C, M, W, __FILE__, __LINE__) +#else + #define mysql_cond_timedwait(C, M, W) \ + inline_mysql_cond_timedwait(C, M, W) +#endif + +/** + @def mysql_cond_signal(C) + Instrumented cond_signal. + @c mysql_cond_signal is a drop-in replacement for @c pthread_cond_signal. +*/ +#define mysql_cond_signal(C) inline_mysql_cond_signal(C) + +/** + @def mysql_cond_broadcast(C) + Instrumented cond_broadcast. + @c mysql_cond_broadcast is a drop-in replacement + for @c pthread_cond_broadcast. +*/ +#define mysql_cond_broadcast(C) inline_mysql_cond_broadcast(C) + + +/** + @def mysql_thread_create(K, P1, P2, P3, P4) + Instrumented pthread_create. + This function creates both the thread instrumentation and a thread. + @c mysql_thread_create is a replacement for @c pthread_create. + The parameter P4 (or, if it is NULL, P1) will be used as the + instrumented thread "indentity". + Providing a P1 / P4 parameter with a different value for each call + will on average improve performances, since this thread identity value + is used internally to randomize access to data and prevent contention. + This is optional, and the improvement is not guaranteed, only statistical. + @param K The PSI_thread_key for this instrumented thread + @param P1 pthread_create parameter 1 + @param P2 pthread_create parameter 2 + @param P3 pthread_create parameter 3 + @param P4 pthread_create parameter 4 +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_thread_create(K, P1, P2, P3, P4) \ + inline_mysql_thread_create(K, P1, P2, P3, P4) +#else + #define mysql_thread_create(K, P1, P2, P3, P4) \ + pthread_create(P1, P2, P3, P4) +#endif + +/** + @def mysql_thread_set_psi_id(I) + Set the thread indentifier for the instrumentation. + @param I The thread identifier +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_thread_set_psi_id(I) inline_mysql_thread_set_psi_id(I) +#else + #define mysql_thread_set_psi_id(I) do {} while (0) +#endif + +static inline int inline_mysql_mutex_init( +#ifdef HAVE_PSI_INTERFACE + PSI_mutex_key key, +#endif + mysql_mutex_t *that, + const pthread_mutexattr_t *attr +#ifdef SAFE_MUTEX + , const char *src_file, uint src_line +#endif + ) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= PSI_server ? PSI_server->init_mutex(key, &that->m_mutex) + : NULL; +#else + that->m_psi= NULL; +#endif +#ifdef SAFE_MUTEX + return safe_mutex_init(&that->m_mutex, attr, src_file, src_line); +#else + return pthread_mutex_init(&that->m_mutex, attr); +#endif +} + +static inline int inline_mysql_mutex_destroy( + mysql_mutex_t *that +#ifdef SAFE_MUTEX + , const char *src_file, uint src_line +#endif + ) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_mutex(that->m_psi); + that->m_psi= NULL; + } +#endif +#ifdef SAFE_MUTEX + return safe_mutex_destroy(&that->m_mutex, src_file, src_line); +#else + return pthread_mutex_destroy(&that->m_mutex); +#endif +} + +static inline int inline_mysql_mutex_lock( + mysql_mutex_t *that +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_mutex_locker *locker= NULL; + PSI_mutex_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_mutex_locker(&state, that->m_psi, PSI_MUTEX_LOCK); + if (likely(locker != NULL)) + PSI_server->start_mutex_wait(locker, src_file, src_line); + } +#endif +#ifdef SAFE_MUTEX + result= safe_mutex_lock(&that->m_mutex, FALSE, src_file, src_line); +#else + result= pthread_mutex_lock(&that->m_mutex); +#endif +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_mutex_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_mutex_trylock( + mysql_mutex_t *that +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_mutex_locker *locker= NULL; + PSI_mutex_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_mutex_locker(&state, that->m_psi, PSI_MUTEX_TRYLOCK); + if (likely(locker != NULL)) + PSI_server->start_mutex_wait(locker, src_file, src_line); + } +#endif +#ifdef SAFE_MUTEX + result= safe_mutex_lock(&that->m_mutex, TRUE, src_file, src_line); +#else + result= pthread_mutex_trylock(&that->m_mutex); +#endif +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_mutex_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_mutex_unlock( + mysql_mutex_t *that +#ifdef SAFE_MUTEX + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->unlock_mutex(that->m_psi); +#endif +#ifdef SAFE_MUTEX + result= safe_mutex_unlock(&that->m_mutex, src_file, src_line); +#else + result= pthread_mutex_unlock(&that->m_mutex); +#endif + return result; +} + +static inline int inline_mysql_rwlock_init( +#ifdef HAVE_PSI_INTERFACE + PSI_rwlock_key key, +#endif + mysql_rwlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= (PSI_server ? PSI_server->init_rwlock(key, &that->m_rwlock) + : NULL); +#else + that->m_psi= NULL; +#endif + /* + pthread_rwlockattr_t is not used in MySQL. + */ + return my_rwlock_init(&that->m_rwlock, NULL); +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_init( +#ifdef HAVE_PSI_INTERFACE + PSI_rwlock_key key, +#endif + mysql_prlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= (PSI_server ? PSI_server->init_rwlock(key, &that->m_prlock) + : NULL); +#else + that->m_psi= NULL; +#endif + return rw_pr_init(&that->m_prlock); +} +#endif + +static inline int inline_mysql_rwlock_destroy( + mysql_rwlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_rwlock(that->m_psi); + that->m_psi= NULL; + } +#endif + return rwlock_destroy(&that->m_rwlock); +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_destroy( + mysql_prlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_rwlock(that->m_psi); + that->m_psi= NULL; + } +#endif + return rw_pr_destroy(&that->m_prlock); +} +#endif + +static inline int inline_mysql_rwlock_rdlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_READLOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_rdwait(locker, src_file, src_line); + } +#endif + result= rw_rdlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_rdwait(locker, result); +#endif + return result; +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_rdlock( + mysql_prlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_READLOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_rdwait(locker, src_file, src_line); + } +#endif + result= rw_pr_rdlock(&that->m_prlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_rdwait(locker, result); +#endif + return result; +} +#endif + +static inline int inline_mysql_rwlock_wrlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_WRITELOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_wrwait(locker, src_file, src_line); + } +#endif + result= rw_wrlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_wrwait(locker, result); +#endif + return result; +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_wrlock( + mysql_prlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_WRITELOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_wrwait(locker, src_file, src_line); + } +#endif + result= rw_pr_wrlock(&that->m_prlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_wrwait(locker, result); +#endif + return result; +} +#endif + +static inline int inline_mysql_rwlock_tryrdlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_TRYREADLOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_rdwait(locker, src_file, src_line); + } +#endif + result= rw_tryrdlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_rdwait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_rwlock_trywrlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_TRYWRITELOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_wrwait(locker, src_file, src_line); + } +#endif + result= rw_trywrlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_wrwait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_rwlock_unlock( + mysql_rwlock_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->unlock_rwlock(that->m_psi); +#endif + result= rw_unlock(&that->m_rwlock); + return result; +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_unlock( + mysql_prlock_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->unlock_rwlock(that->m_psi); +#endif + result= rw_pr_unlock(&that->m_prlock); + return result; +} +#endif + +static inline int inline_mysql_cond_init( +#ifdef HAVE_PSI_INTERFACE + PSI_cond_key key, +#endif + mysql_cond_t *that, + const pthread_condattr_t *attr) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= (PSI_server ? PSI_server->init_cond(key, &that->m_cond) + : NULL); +#else + that->m_psi= NULL; +#endif + return pthread_cond_init(&that->m_cond, attr); +} + +static inline int inline_mysql_cond_destroy( + mysql_cond_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_cond(that->m_psi); + that->m_psi= NULL; + } +#endif + return pthread_cond_destroy(&that->m_cond); +} + +static inline int inline_mysql_cond_wait( + mysql_cond_t *that, + mysql_mutex_t *mutex +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_cond_locker *locker= NULL; + PSI_cond_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_cond_locker(&state, that->m_psi, mutex->m_psi, + PSI_COND_WAIT); + if (likely(locker != NULL)) + PSI_server->start_cond_wait(locker, src_file, src_line); + } +#endif + result= pthread_cond_wait(&that->m_cond, &mutex->m_mutex); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_cond_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_cond_timedwait( + mysql_cond_t *that, + mysql_mutex_t *mutex, + struct timespec *abstime +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_cond_locker *locker= NULL; + PSI_cond_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_cond_locker(&state, that->m_psi, mutex->m_psi, + PSI_COND_TIMEDWAIT); + if (likely(locker != NULL)) + PSI_server->start_cond_wait(locker, src_file, src_line); + } +#endif + result= pthread_cond_timedwait(&that->m_cond, &mutex->m_mutex, abstime); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_cond_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_cond_signal( + mysql_cond_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->signal_cond(that->m_psi); +#endif + result= pthread_cond_signal(&that->m_cond); + return result; +} + +static inline int inline_mysql_cond_broadcast( + mysql_cond_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->broadcast_cond(that->m_psi); +#endif + result= pthread_cond_broadcast(&that->m_cond); + return result; +} + +#ifdef HAVE_PSI_INTERFACE +static inline int inline_mysql_thread_create( + PSI_thread_key key, + pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void*), void *arg) +{ + int result; + if (likely(PSI_server != NULL)) + result= PSI_server->spawn_thread(key, thread, attr, start_routine, arg); + else + result= pthread_create(thread, attr, start_routine, arg); + return result; +} + +static inline void inline_mysql_thread_set_psi_id(ulong id) +{ + if (likely(PSI_server != NULL)) + { + struct PSI_thread *psi= PSI_server->get_thread(); + if (likely(psi != NULL)) + PSI_server->set_thread_id(psi, id); + } +} +#endif + +#endif /* DISABLE_MYSQL_THREAD_H */ + +/** @} (end of group Thread_instrumentation) */ + +#endif + diff --git a/code/meosdb/mysql55/mysql/psi/psi.h b/code/meosdb/mysql55/mysql/psi/psi.h new file mode 100644 index 0000000..afc5f26 --- /dev/null +++ b/code/meosdb/mysql55/mysql/psi/psi.h @@ -0,0 +1,1312 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H +#define MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H + +#ifndef _global_h +/* + Make sure a .c or .cc file contains an include to my_global.h first. + When this include is missing, all the #ifdef HAVE_XXX have no effect, + and the resulting binary won't build, or won't link, + or will crash at runtime + since various structures will have different binary definitions. +*/ +#error "You must include my_global.h in the code for the build to be correct." +#endif + +C_MODE_START + +/** + @file mysql/psi/psi.h + Performance schema instrumentation interface. + + @defgroup Instrumentation_interface Instrumentation Interface + @ingroup Performance_schema + @{ +*/ + +/** + Interface for an instrumented mutex. + This is an opaque structure. +*/ +struct PSI_mutex; + +/** + Interface for an instrumented rwlock. + This is an opaque structure. +*/ +struct PSI_rwlock; + +/** + Interface for an instrumented condition. + This is an opaque structure. +*/ +struct PSI_cond; + +/** + Interface for an instrumented table share. + This is an opaque structure. +*/ +struct PSI_table_share; + +/** + Interface for an instrumented table handle. + This is an opaque structure. +*/ +struct PSI_table; + +/** + Interface for an instrumented thread. + This is an opaque structure. +*/ +struct PSI_thread; + +/** + Interface for an instrumented file handle. + This is an opaque structure. +*/ +struct PSI_file; + +/** Entry point for the performance schema interface. */ +struct PSI_bootstrap +{ + /** + ABI interface finder. + Calling this method with an interface version number returns either + an instance of the ABI for this version, or NULL. + @param version the interface version number to find + @return a versioned interface (PSI_v1, PSI_v2 or PSI) + @sa PSI_VERSION_1 + @sa PSI_v1 + @sa PSI_VERSION_2 + @sa PSI_v2 + @sa PSI_CURRENT_VERSION + @sa PSI + */ + void* (*get_interface)(int version); +}; + +#ifdef HAVE_PSI_INTERFACE + +/** + @def PSI_VERSION_1 + Performance Schema Interface number for version 1. + This version is supported. +*/ +#define PSI_VERSION_1 1 + +/** + @def PSI_VERSION_2 + Performance Schema Interface number for version 2. + This version is not implemented, it's a placeholder. +*/ +#define PSI_VERSION_2 2 + +/** + @def PSI_CURRENT_VERSION + Performance Schema Interface number for the most recent version. + The most current version is @c PSI_VERSION_1 +*/ +#define PSI_CURRENT_VERSION 1 + +#ifndef USE_PSI_2 +#ifndef USE_PSI_1 +#define USE_PSI_1 +#endif +#endif + +/** + Interface for an instrumented mutex operation. + This is an opaque structure. +*/ +struct PSI_mutex_locker; + +/** + Interface for an instrumented rwlock operation. + This is an opaque structure. +*/ + +struct PSI_rwlock_locker; +/** + Interface for an instrumented condition operation. + This is an opaque structure. +*/ + +struct PSI_cond_locker; + +/** + Interface for an instrumented file operation. + This is an opaque structure. +*/ +struct PSI_file_locker; + +/** Operation performed on an instrumented mutex. */ +enum PSI_mutex_operation +{ + /** Lock. */ + PSI_MUTEX_LOCK= 0, + /** Lock attempt. */ + PSI_MUTEX_TRYLOCK= 1 +}; + +/** Operation performed on an instrumented rwlock. */ +enum PSI_rwlock_operation +{ + /** Read lock. */ + PSI_RWLOCK_READLOCK= 0, + /** Write lock. */ + PSI_RWLOCK_WRITELOCK= 1, + /** Read lock attempt. */ + PSI_RWLOCK_TRYREADLOCK= 2, + /** Write lock attempt. */ + PSI_RWLOCK_TRYWRITELOCK= 3 +}; + +/** Operation performed on an instrumented condition. */ +enum PSI_cond_operation +{ + /** Wait. */ + PSI_COND_WAIT= 0, + /** Wait, with timeout. */ + PSI_COND_TIMEDWAIT= 1 +}; + +/** Operation performed on an instrumented file. */ +enum PSI_file_operation +{ + /** File creation, as in @c create(). */ + PSI_FILE_CREATE= 0, + /** Temporary file creation, as in @c create_temp_file(). */ + PSI_FILE_CREATE_TMP= 1, + /** File open, as in @c open(). */ + PSI_FILE_OPEN= 2, + /** File open, as in @c fopen(). */ + PSI_FILE_STREAM_OPEN= 3, + /** File close, as in @c close(). */ + PSI_FILE_CLOSE= 4, + /** File close, as in @c fclose(). */ + PSI_FILE_STREAM_CLOSE= 5, + /** + Generic file read, such as @c fgets(), @c fgetc(), @c fread(), @c read(), + @c pread(). + */ + PSI_FILE_READ= 6, + /** + Generic file write, such as @c fputs(), @c fputc(), @c fprintf(), + @c vfprintf(), @c fwrite(), @c write(), @c pwrite(). + */ + PSI_FILE_WRITE= 7, + /** Generic file seek, such as @c fseek() or @c seek(). */ + PSI_FILE_SEEK= 8, + /** Generic file tell, such as @c ftell() or @c tell(). */ + PSI_FILE_TELL= 9, + /** File flush, as in @c fflush(). */ + PSI_FILE_FLUSH= 10, + /** File stat, as in @c stat(). */ + PSI_FILE_STAT= 11, + /** File stat, as in @c fstat(). */ + PSI_FILE_FSTAT= 12, + /** File chsize, as in @c my_chsize(). */ + PSI_FILE_CHSIZE= 13, + /** File delete, such as @c my_delete() or @c my_delete_with_symlink(). */ + PSI_FILE_DELETE= 14, + /** File rename, such as @c my_rename() or @c my_rename_with_symlink(). */ + PSI_FILE_RENAME= 15, + /** File sync, as in @c fsync() or @c my_sync(). */ + PSI_FILE_SYNC= 16 +}; + +/** + Interface for an instrumented table operation. + This is an opaque structure. +*/ +struct PSI_table_locker; + +/** + Instrumented mutex key. + To instrument a mutex, a mutex key must be obtained using @c register_mutex. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_mutex_key; + +/** + Instrumented rwlock key. + To instrument a rwlock, a rwlock key must be obtained + using @c register_rwlock. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_rwlock_key; + +/** + Instrumented cond key. + To instrument a condition, a condition key must be obtained + using @c register_cond. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_cond_key; + +/** + Instrumented thread key. + To instrument a thread, a thread key must be obtained + using @c register_thread. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_thread_key; + +/** + Instrumented file key. + To instrument a file, a file key must be obtained using @c register_file. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_file_key; + +/** + @def USE_PSI_1 + Define USE_PSI_1 to use the interface version 1. +*/ + +/** + @def USE_PSI_2 + Define USE_PSI_2 to use the interface version 2. +*/ + +/** + @def HAVE_PSI_1 + Define HAVE_PSI_1 if the interface version 1 needs to be compiled in. +*/ + +/** + @def HAVE_PSI_2 + Define HAVE_PSI_2 if the interface version 2 needs to be compiled in. +*/ + +/** + Global flag. + This flag indicate that an instrumentation point is a global variable, + or a singleton. +*/ +#define PSI_FLAG_GLOBAL (1 << 0) + +#ifdef USE_PSI_1 +#define HAVE_PSI_1 +#endif + +#ifdef HAVE_PSI_1 + +/** + @defgroup Group_PSI_v1 Application Binary Interface, version 1 + @ingroup Instrumentation_interface + @{ +*/ + +/** + Mutex information. + @since PSI_VERSION_1 + This structure is used to register an instrumented mutex. +*/ +struct PSI_mutex_info_v1 +{ + /** + Pointer to the key assigned to the registered mutex. + */ + PSI_mutex_key *m_key; + /** + The name of the mutex to register. + */ + const char *m_name; + /** + The flags of the mutex to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + Rwlock information. + @since PSI_VERSION_1 + This structure is used to register an instrumented rwlock. +*/ +struct PSI_rwlock_info_v1 +{ + /** + Pointer to the key assigned to the registered rwlock. + */ + PSI_rwlock_key *m_key; + /** + The name of the rwlock to register. + */ + const char *m_name; + /** + The flags of the rwlock to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + Condition information. + @since PSI_VERSION_1 + This structure is used to register an instrumented cond. +*/ +struct PSI_cond_info_v1 +{ + /** + Pointer to the key assigned to the registered cond. + */ + PSI_cond_key *m_key; + /** + The name of the cond to register. + */ + const char *m_name; + /** + The flags of the cond to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + Thread instrument information. + @since PSI_VERSION_1 + This structure is used to register an instrumented thread. +*/ +struct PSI_thread_info_v1 +{ + /** + Pointer to the key assigned to the registered thread. + */ + PSI_thread_key *m_key; + /** + The name of the thread instrument to register. + */ + const char *m_name; + /** + The flags of the thread to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + File instrument information. + @since PSI_VERSION_1 + This structure is used to register an instrumented file. +*/ +struct PSI_file_info_v1 +{ + /** + Pointer to the key assigned to the registered file. + */ + PSI_file_key *m_key; + /** + The name of the file instrument to register. + */ + const char *m_name; + /** + The flags of the file instrument to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + State data storage for @c get_thread_mutex_locker_v1_t. + This structure provide temporary storage to a mutex locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_mutex_locker_v1_t +*/ +struct PSI_mutex_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current mutex. */ + struct PSI_mutex *m_mutex; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_mutex_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_rwlock_locker_v1_t. + This structure provide temporary storage to a rwlock locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_rwlock_locker_v1_t +*/ +struct PSI_rwlock_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current rwlock. */ + struct PSI_rwlock *m_rwlock; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_rwlock_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_cond_locker_v1_t. + This structure provide temporary storage to a condition locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_cond_locker_v1_t +*/ +struct PSI_cond_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current condition. */ + struct PSI_cond *m_cond; + /** Current mutex. */ + struct PSI_mutex *m_mutex; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_cond_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_file_name_locker_v1_t. + This structure provide temporary storage to a file locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_file_name_locker_v1_t + @sa get_thread_file_stream_locker_v1_t + @sa get_thread_file_descriptor_locker_v1_t +*/ +struct PSI_file_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current file. */ + struct PSI_file *m_file; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Operation number of bytes. */ + size_t m_number_of_bytes; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_file_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_table_locker_v1_t. + This structure provide temporary storage to a table locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_table_locker_v1_t +*/ +struct PSI_table_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current table handle. */ + struct PSI_table *m_table; + /** Current table share. */ + struct PSI_table_share *m_table_share; + /** Instrumentation class. */ + void *m_class; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /* Current operation (waiting for WL#4895). */ + /* enum PSI_table_operation m_operation; */ + /** Current table io index. */ + uint m_index; + /** Current table lock index. */ + uint m_lock_index; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/* Using typedef to make reuse between PSI_v1 and PSI_v2 easier later. */ + +/** + Mutex registration API. + @param category a category name (typically a plugin name) + @param info an array of mutex info to register + @param count the size of the info array +*/ +typedef void (*register_mutex_v1_t) + (const char *category, struct PSI_mutex_info_v1 *info, int count); + +/** + Rwlock registration API. + @param category a category name (typically a plugin name) + @param info an array of rwlock info to register + @param count the size of the info array +*/ +typedef void (*register_rwlock_v1_t) + (const char *category, struct PSI_rwlock_info_v1 *info, int count); + +/** + Cond registration API. + @param category a category name (typically a plugin name) + @param info an array of cond info to register + @param count the size of the info array +*/ +typedef void (*register_cond_v1_t) + (const char *category, struct PSI_cond_info_v1 *info, int count); + +/** + Thread registration API. + @param category a category name (typically a plugin name) + @param info an array of thread info to register + @param count the size of the info array +*/ +typedef void (*register_thread_v1_t) + (const char *category, struct PSI_thread_info_v1 *info, int count); + +/** + File registration API. + @param category a category name (typically a plugin name) + @param info an array of file info to register + @param count the size of the info array +*/ +typedef void (*register_file_v1_t) + (const char *category, struct PSI_file_info_v1 *info, int count); + +/** + Mutex instrumentation initialisation API. + @param key the registered mutex key + @param identity the address of the mutex itself + @return an instrumented mutex +*/ +typedef struct PSI_mutex* (*init_mutex_v1_t) + (PSI_mutex_key key, const void *identity); + +/** + Mutex instrumentation destruction API. + @param mutex the mutex to destroy +*/ +typedef void (*destroy_mutex_v1_t)(struct PSI_mutex *mutex); + +/** + Rwlock instrumentation initialisation API. + @param key the registered rwlock key + @param identity the address of the rwlock itself + @return an instrumented rwlock +*/ +typedef struct PSI_rwlock* (*init_rwlock_v1_t) + (PSI_rwlock_key key, const void *identity); + +/** + Rwlock instrumentation destruction API. + @param rwlock the rwlock to destroy +*/ +typedef void (*destroy_rwlock_v1_t)(struct PSI_rwlock *rwlock); + +/** + Cond instrumentation initialisation API. + @param key the registered key + @param identity the address of the rwlock itself + @return an instrumented cond +*/ +typedef struct PSI_cond* (*init_cond_v1_t) + (PSI_cond_key key, const void *identity); + +/** + Cond instrumentation destruction API. + @param cond the rcond to destroy +*/ +typedef void (*destroy_cond_v1_t)(struct PSI_cond *cond); + +/** + Acquire a table info by name. + @param schema_name name of the table schema + @param schema_name_length length of schema_name + @param table_name name of the table + @param table_name_length length of table_name + @param identity table identity pointer, typically the table share + @return a table info, or NULL if the table is not instrumented +*/ +typedef struct PSI_table_share* (*get_table_share_v1_t) + (const char *schema_name, int schema_name_length, const char *table_name, + int table_name_length, const void *identity); + +/** + Release a table share. + @param info the table share to release +*/ +typedef void (*release_table_share_v1_t)(struct PSI_table_share *share); + +/** + Open an instrumentation table handle. + @param share the table to open + @param identity table handle identity + @return a table handle, or NULL +*/ +typedef struct PSI_table* (*open_table_v1_t) + (struct PSI_table_share *share, const void *identity); + +/** + Close an instrumentation table handle. + Note that the table handle is invalid after this call. + @param table the table handle to close +*/ +typedef void (*close_table_v1_t)(struct PSI_table *table); + +/** + Create a file instrumentation for a created file. + This method does not create the file itself, but is used to notify the + instrumentation interface that a file was just created. + @param key the file instrumentation key for this file + @param name the file name + @param file the file handle +*/ +typedef void (*create_file_v1_t)(PSI_file_key key, const char *name, + File file); + +/** + Spawn a thread. + This method creates a new thread, with instrumentation. + @param key the instrumentation key for this thread + @param thread the resulting thread + @param attr the thread attributes + @param start_routine the thread start routine + @param arg the thread start routine argument +*/ +typedef int (*spawn_thread_v1_t)(PSI_thread_key key, + pthread_t *thread, + const pthread_attr_t *attr, + void *(*start_routine)(void*), void *arg); + +/** + Create instrumentation for a thread. + @param key the registered key + @param identity an address typical of the thread + @return an instrumented thread +*/ +typedef struct PSI_thread* (*new_thread_v1_t) + (PSI_thread_key key, const void *identity, ulong thread_id); + +/** + Assign an id to an instrumented thread. + @param thread the instrumented thread + @param id the id to assign +*/ +typedef void (*set_thread_id_v1_t)(struct PSI_thread *thread, + unsigned long id); + +/** + Get the instrumentation for the running thread. + For this function to return a result, + the thread instrumentation must have been attached to the + running thread using @c set_thread() + @return the instrumentation for the running thread +*/ +typedef struct PSI_thread* (*get_thread_v1_t)(void); + +/** + Attach a thread instrumentation to the running thread. + In case of thread pools, this method should be called when + a worker thread picks a work item and runs it. + Also, this method should be called if the instrumented code does not + keep the pointer returned by @c new_thread() and relies on @c get_thread() + instead. + @param thread the thread instrumentation +*/ +typedef void (*set_thread_v1_t)(struct PSI_thread *thread); + +/** Delete the current thread instrumentation. */ +typedef void (*delete_current_thread_v1_t)(void); + +/** Delete a thread instrumentation. */ +typedef void (*delete_thread_v1_t)(struct PSI_thread *thread); + +/** + Get a mutex instrumentation locker. + @param state data storage for the locker + @param mutex the instrumented mutex to lock + @return a mutex locker, or NULL +*/ +typedef struct PSI_mutex_locker* (*get_thread_mutex_locker_v1_t) + (struct PSI_mutex_locker_state_v1 *state, + struct PSI_mutex *mutex, + enum PSI_mutex_operation op); + +/** + Get a rwlock instrumentation locker. + @param state data storage for the locker + @param rwlock the instrumented rwlock to lock + @return a rwlock locker, or NULL +*/ +typedef struct PSI_rwlock_locker* (*get_thread_rwlock_locker_v1_t) + (struct PSI_rwlock_locker_state_v1 *state, + struct PSI_rwlock *rwlock, + enum PSI_rwlock_operation op); + +/** + Get a cond instrumentation locker. + @param state data storage for the locker + @param cond the instrumented condition to wait on + @param mutex the instrumented mutex associated with the condition + @return a condition locker, or NULL +*/ +typedef struct PSI_cond_locker* (*get_thread_cond_locker_v1_t) + (struct PSI_cond_locker_state_v1 *state, + struct PSI_cond *cond, struct PSI_mutex *mutex, + enum PSI_cond_operation op); + +/** + Get a table instrumentation locker. + @param state data storage for the locker + @param table the instrumented table to lock + @return a table locker, or NULL +*/ +typedef struct PSI_table_locker* (*get_thread_table_locker_v1_t) + (struct PSI_table_locker_state_v1 *state, + struct PSI_table *table); + +/** + Get a file instrumentation locker, for opening or creating a file. + @param state data storage for the locker + @param key the file instrumentation key + @param op the operation to perform + @param name the file name + @param identity a pointer representative of this file. + @return a file locker, or NULL +*/ +typedef struct PSI_file_locker* (*get_thread_file_name_locker_v1_t) + (struct PSI_file_locker_state_v1 *state, + PSI_file_key key, enum PSI_file_operation op, const char *name, + const void *identity); + +/** + Get a file stream instrumentation locker. + @param state data storage for the locker + @param file the file stream to access + @param op the operation to perform + @return a file locker, or NULL +*/ +typedef struct PSI_file_locker* (*get_thread_file_stream_locker_v1_t) + (struct PSI_file_locker_state_v1 *state, + struct PSI_file *file, enum PSI_file_operation op); + +/** + Get a file instrumentation locker. + @param state data storage for the locker + @param file the file descriptor to access + @param op the operation to perform + @return a file locker, or NULL +*/ +typedef struct PSI_file_locker* (*get_thread_file_descriptor_locker_v1_t) + (struct PSI_file_locker_state_v1 *state, + File file, enum PSI_file_operation op); + +/** + Record a mutex instrumentation unlock event. + @param mutex the mutex instrumentation +*/ +typedef void (*unlock_mutex_v1_t) + (struct PSI_mutex *mutex); + +/** + Record a rwlock instrumentation unlock event. + @param rwlock the rwlock instrumentation +*/ +typedef void (*unlock_rwlock_v1_t) + (struct PSI_rwlock *rwlock); + +/** + Record a condition instrumentation signal event. + @param cond the cond instrumentation +*/ +typedef void (*signal_cond_v1_t) + (struct PSI_cond *cond); + +/** + Record a condition instrumentation broadcast event. + @param cond the cond instrumentation +*/ +typedef void (*broadcast_cond_v1_t) + (struct PSI_cond *cond); + +/** + Record a mutex instrumentation wait start event. + @param locker a thread locker for the running thread +*/ +typedef void (*start_mutex_wait_v1_t) + (struct PSI_mutex_locker *locker, const char *src_file, uint src_line); + +/** + Record a mutex instrumentation wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_mutex_wait_v1_t) + (struct PSI_mutex_locker *locker, int rc); + +/** + Record a rwlock instrumentation read wait start event. + @param locker a thread locker for the running thread + @param must must block: 1 for lock, 0 for trylock +*/ +typedef void (*start_rwlock_rdwait_v1_t) + (struct PSI_rwlock_locker *locker, const char *src_file, uint src_line); + +/** + Record a rwlock instrumentation read wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_rwlock_rdwait_v1_t) + (struct PSI_rwlock_locker *locker, int rc); + +/** + Record a rwlock instrumentation write wait start event. + @param locker a thread locker for the running thread + @param must must block: 1 for lock, 0 for trylock +*/ +typedef void (*start_rwlock_wrwait_v1_t) + (struct PSI_rwlock_locker *locker, const char *src_file, uint src_line); + +/** + Record a rwlock instrumentation write wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_rwlock_wrwait_v1_t) + (struct PSI_rwlock_locker *locker, int rc); + +/** + Record a condition instrumentation wait start event. + @param locker a thread locker for the running thread + @param must must block: 1 for wait, 0 for timedwait +*/ +typedef void (*start_cond_wait_v1_t) + (struct PSI_cond_locker *locker, const char *src_file, uint src_line); + +/** + Record a condition instrumentation wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_cond_wait_v1_t) + (struct PSI_cond_locker *locker, int rc); + +/** + Record a table instrumentation wait start event. + @param locker a table locker for the running thread + @param file the source file name + @param line the source line number +*/ +typedef void (*start_table_wait_v1_t) + (struct PSI_table_locker *locker, const char *src_file, uint src_line); + +/** + Record a table instrumentation wait end event. + @param locker a table locker for the running thread +*/ +typedef void (*end_table_wait_v1_t)(struct PSI_table_locker *locker); + +/** + Start a file instrumentation open operation. + @param locker the file locker + @param op the operation to perform + @param src_file the source file name + @param src_line the source line number + @return an instrumented file handle +*/ +typedef struct PSI_file* (*start_file_open_wait_v1_t) + (struct PSI_file_locker *locker, const char *src_file, uint src_line); + +/** + End a file instrumentation open operation, for file streams. + @param locker the file locker. +*/ +typedef void (*end_file_open_wait_v1_t)(struct PSI_file_locker *locker); + +/** + End a file instrumentation open operation, for non stream files. + @param locker the file locker. + @param file the file number assigned by open() or create() for this file. +*/ +typedef void (*end_file_open_wait_and_bind_to_descriptor_v1_t) + (struct PSI_file_locker *locker, File file); + +/** + Record a file instrumentation start event. + @param locker a file locker for the running thread + @param op file operation to be performed + @param count the number of bytes requested, or 0 if not applicable + @param src_file the source file name + @param src_line the source line number +*/ +typedef void (*start_file_wait_v1_t) + (struct PSI_file_locker *locker, size_t count, + const char *src_file, uint src_line); + +/** + Record a file instrumentation end event. + Note that for file close operations, the instrumented file handle + associated with the file (which was provided to obtain a locker) + is invalid after this call. + @param locker a file locker for the running thread + @param count the number of bytes actually used in the operation, + or 0 if not applicable, or -1 if the operation failed + @sa get_thread_file_name_locker + @sa get_thread_file_stream_locker + @sa get_thread_file_descriptor_locker +*/ +typedef void (*end_file_wait_v1_t) + (struct PSI_file_locker *locker, size_t count); + +/** + Performance Schema Interface, version 1. + @since PSI_VERSION_1 +*/ +struct PSI_v1 +{ + /** @sa register_mutex_v1_t. */ + register_mutex_v1_t register_mutex; + /** @sa register_rwlock_v1_t. */ + register_rwlock_v1_t register_rwlock; + /** @sa register_cond_v1_t. */ + register_cond_v1_t register_cond; + /** @sa register_thread_v1_t. */ + register_thread_v1_t register_thread; + /** @sa register_file_v1_t. */ + register_file_v1_t register_file; + /** @sa init_mutex_v1_t. */ + init_mutex_v1_t init_mutex; + /** @sa destroy_mutex_v1_t. */ + destroy_mutex_v1_t destroy_mutex; + /** @sa init_rwlock_v1_t. */ + init_rwlock_v1_t init_rwlock; + /** @sa destroy_rwlock_v1_t. */ + destroy_rwlock_v1_t destroy_rwlock; + /** @sa init_cond_v1_t. */ + init_cond_v1_t init_cond; + /** @sa destroy_cond_v1_t. */ + destroy_cond_v1_t destroy_cond; + /** @sa get_table_share_v1_t. */ + get_table_share_v1_t get_table_share; + /** @sa release_table_share_v1_t. */ + release_table_share_v1_t release_table_share; + /** @sa open_table_v1_t. */ + open_table_v1_t open_table; + /** @sa close_table_v1_t. */ + close_table_v1_t close_table; + /** @sa create_file_v1_t. */ + create_file_v1_t create_file; + /** @sa spawn_thread_v1_t. */ + spawn_thread_v1_t spawn_thread; + /** @sa new_thread_v1_t. */ + new_thread_v1_t new_thread; + /** @sa set_thread_id_v1_t. */ + set_thread_id_v1_t set_thread_id; + /** @sa get_thread_v1_t. */ + get_thread_v1_t get_thread; + /** @sa set_thread_v1_t. */ + set_thread_v1_t set_thread; + /** @sa delete_current_thread_v1_t. */ + delete_current_thread_v1_t delete_current_thread; + /** @sa delete_thread_v1_t. */ + delete_thread_v1_t delete_thread; + /** @sa get_thread_mutex_locker_v1_t. */ + get_thread_mutex_locker_v1_t get_thread_mutex_locker; + /** @sa get_thread_rwlock_locker_v1_t. */ + get_thread_rwlock_locker_v1_t get_thread_rwlock_locker; + /** @sa get_thread_cond_locker_v1_t. */ + get_thread_cond_locker_v1_t get_thread_cond_locker; + /** @sa get_thread_table_locker_v1_t. */ + get_thread_table_locker_v1_t get_thread_table_locker; + /** @sa get_thread_file_name_locker_v1_t. */ + get_thread_file_name_locker_v1_t get_thread_file_name_locker; + /** @sa get_thread_file_stream_locker_v1_t. */ + get_thread_file_stream_locker_v1_t get_thread_file_stream_locker; + /** @sa get_thread_file_descriptor_locker_v1_t. */ + get_thread_file_descriptor_locker_v1_t get_thread_file_descriptor_locker; + /** @sa unlock_mutex_v1_t. */ + unlock_mutex_v1_t unlock_mutex; + /** @sa unlock_rwlock_v1_t. */ + unlock_rwlock_v1_t unlock_rwlock; + /** @sa signal_cond_v1_t. */ + signal_cond_v1_t signal_cond; + /** @sa broadcast_cond_v1_t. */ + broadcast_cond_v1_t broadcast_cond; + /** @sa start_mutex_wait_v1_t. */ + start_mutex_wait_v1_t start_mutex_wait; + /** @sa end_mutex_wait_v1_t. */ + end_mutex_wait_v1_t end_mutex_wait; + /** @sa start_rwlock_rdwait_v1_t. */ + start_rwlock_rdwait_v1_t start_rwlock_rdwait; + /** @sa end_rwlock_rdwait_v1_t. */ + end_rwlock_rdwait_v1_t end_rwlock_rdwait; + /** @sa start_rwlock_wrwait_v1_t. */ + start_rwlock_wrwait_v1_t start_rwlock_wrwait; + /** @sa end_rwlock_wrwait_v1_t. */ + end_rwlock_wrwait_v1_t end_rwlock_wrwait; + /** @sa start_cond_wait_v1_t. */ + start_cond_wait_v1_t start_cond_wait; + /** @sa end_cond_wait_v1_t. */ + end_cond_wait_v1_t end_cond_wait; + /** @sa start_table_wait_v1_t. */ + start_table_wait_v1_t start_table_wait; + /** @sa end_table_wait_v1_t. */ + end_table_wait_v1_t end_table_wait; + /** @sa start_file_open_wait_v1_t. */ + start_file_open_wait_v1_t start_file_open_wait; + /** @sa end_file_open_wait_v1_t. */ + end_file_open_wait_v1_t end_file_open_wait; + /** @sa end_file_open_wait_and_bind_to_descriptor_v1_t. */ + end_file_open_wait_and_bind_to_descriptor_v1_t + end_file_open_wait_and_bind_to_descriptor; + /** @sa start_file_wait_v1_t. */ + start_file_wait_v1_t start_file_wait; + /** @sa end_file_wait_v1_t. */ + end_file_wait_v1_t end_file_wait; +}; + +/** @} (end of group Group_PSI_v1) */ + +#endif /* HAVE_PSI_1 */ + +#ifdef USE_PSI_2 +#define HAVE_PSI_2 +#endif + +#ifdef HAVE_PSI_2 + +/** + @defgroup Group_PSI_v2 Application Binary Interface, version 2 + @ingroup Instrumentation_interface + @{ +*/ + +/** + Performance Schema Interface, version 2. + This is a placeholder, this interface is not defined yet. + @since PSI_VERSION_2 +*/ +struct PSI_v2 +{ + /** Placeholder */ + int placeholder; + /* ... extended interface ... */ +}; + +/** Placeholder */ +struct PSI_mutex_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_rwlock_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_cond_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_thread_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_file_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_mutex_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_rwlock_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_cond_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_file_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_table_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** @} (end of group Group_PSI_v2) */ + +#endif /* HAVE_PSI_2 */ + +/** + @typedef PSI + The instrumentation interface for the current version. + @sa PSI_CURRENT_VERSION +*/ + +/** + @typedef PSI_mutex_info + The mutex information structure for the current version. +*/ + +/** + @typedef PSI_rwlock_info + The rwlock information structure for the current version. +*/ + +/** + @typedef PSI_cond_info + The cond information structure for the current version. +*/ + +/** + @typedef PSI_thread_info + The thread information structure for the current version. +*/ + +/** + @typedef PSI_file_info + The file information structure for the current version. +*/ + +/* Export the required version */ +#ifdef USE_PSI_1 +typedef struct PSI_v1 PSI; +typedef struct PSI_mutex_info_v1 PSI_mutex_info; +typedef struct PSI_rwlock_info_v1 PSI_rwlock_info; +typedef struct PSI_cond_info_v1 PSI_cond_info; +typedef struct PSI_thread_info_v1 PSI_thread_info; +typedef struct PSI_file_info_v1 PSI_file_info; +typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state; +typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state; +typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state; +typedef struct PSI_file_locker_state_v1 PSI_file_locker_state; +typedef struct PSI_table_locker_state_v1 PSI_table_locker_state; +#endif + +#ifdef USE_PSI_2 +typedef struct PSI_v2 PSI; +typedef struct PSI_mutex_info_v2 PSI_mutex_info; +typedef struct PSI_rwlock_info_v2 PSI_rwlock_info; +typedef struct PSI_cond_info_v2 PSI_cond_info; +typedef struct PSI_thread_info_v2 PSI_thread_info; +typedef struct PSI_file_info_v2 PSI_file_info; +typedef struct PSI_mutex_locker_state_v2 PSI_mutex_locker_state; +typedef struct PSI_rwlock_locker_state_v2 PSI_rwlock_locker_state; +typedef struct PSI_cond_locker_state_v2 PSI_cond_locker_state; +typedef struct PSI_file_locker_state_v2 PSI_file_locker_state; +typedef struct PSI_table_locker_state_v2 PSI_table_locker_state; +#endif + +#else /* HAVE_PSI_INTERFACE */ + +/** + Dummy structure, used to declare PSI_server when no instrumentation + is available. + The content does not matter, since PSI_server will be NULL. +*/ +struct PSI_none +{ + int opaque; +}; +typedef struct PSI_none PSI; + +#endif /* HAVE_PSI_INTERFACE */ + +extern MYSQL_PLUGIN_IMPORT PSI *PSI_server; + +/** @} */ + +C_MODE_END +#endif /* MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H */ + diff --git a/code/meosdb/mysql55/mysql/psi/psi_abi_v1.h b/code/meosdb/mysql55/mysql/psi/psi_abi_v1.h new file mode 100644 index 0000000..245e2b6 --- /dev/null +++ b/code/meosdb/mysql55/mysql/psi/psi_abi_v1.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file mysql/psi/psi_abi_v1.h + ABI check for mysql/psi/psi.h, when using PSI_VERSION_1. + This file is only used to automate detection of changes between versions. + Do not include this file, include mysql/psi/psi.h instead. +*/ +#define USE_PSI_1 +#define HAVE_PSI_INTERFACE +#define _global_h +#include "mysql/psi/psi.h" + diff --git a/code/meosdb/mysql55/mysql/psi/psi_abi_v2.h b/code/meosdb/mysql55/mysql/psi/psi_abi_v2.h new file mode 100644 index 0000000..416294d --- /dev/null +++ b/code/meosdb/mysql55/mysql/psi/psi_abi_v2.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file mysql/psi/psi_abi_v1.h + ABI check for mysql/psi/psi.h, when using PSI_VERSION_2. + This file is only used to automate detection of changes between versions. + Do not include this file, include mysql/psi/psi.h instead. +*/ +#define USE_PSI_2 +#define HAVE_PSI_INTERFACE +#define _global_h +#include "mysql/psi/psi.h" + diff --git a/code/meosdb/mysql55/mysql/service_my_snprintf.h b/code/meosdb/mysql55/mysql/service_my_snprintf.h new file mode 100644 index 0000000..a59a317 --- /dev/null +++ b/code/meosdb/mysql55/mysql/service_my_snprintf.h @@ -0,0 +1,101 @@ +#ifndef MYSQL_SERVICE_MY_SNPRINTF_INCLUDED +/* Copyright (C) 2009 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +/** + @file + my_snprintf service + + Portable and limited vsnprintf() implementation. + + This is a portable, limited vsnprintf() implementation, with some + extra features. "Portable" means that it'll produce identical result + on all platforms (for example, on Windows and Linux system printf %e + formats the exponent differently, on different systems %p either + prints leading 0x or not, %s may accept null pointer or crash on + it). "Limited" means that it does not support all the C89 features. + But it supports few extensions, not in any standard. + + my_vsnprintf(to, n, fmt, ap) + + @param[out] to A buffer to store the result in + @param[in] n Store up to n-1 characters, followed by an end 0 + @param[in] fmt printf-like format string + @param[in] ap Arguments + + @return a number of bytes written to a buffer *excluding* terminating '\0' + + @post + The syntax of a format string is generally the same: + % + where everithing but the format is optional. + + Three one-character flags are recognized: + '0' has the standard zero-padding semantics; + '-' is parsed, but silently ignored; + '`' (backtick) is only supported for strings (%s) and means that the + string will be quoted according to MySQL identifier quoting rules. + + Both and can be specified as numbers or '*'. + + can be 'l', 'll', or 'z'. + + Supported formats are 's' (null pointer is accepted, printed as + "(null)"), 'b' (extension, see below), 'c', 'd', 'i', 'u', 'x', 'o', + 'X', 'p' (works as 0x%x). + + Standard syntax for positional arguments $n is supported. + + Extensions: + + Flag '`' (backtick): see above. + + Format 'b': binary buffer, prints exactly bytes from the + argument, without stopping at '\0'. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MYSQL_ABI_CHECK +#include +#include +#endif + +extern struct my_snprintf_service_st { + size_t (*my_snprintf_type)(char*, size_t, const char*, ...); + size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list); +} *my_snprintf_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define my_vsnprintf my_snprintf_service->my_vsnprintf_type +#define my_snprintf my_snprintf_service->my_snprintf_type + +#else + +size_t my_snprintf(char* to, size_t n, const char* fmt, ...); +size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap); + +#endif + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_MY_SNPRINTF_INCLUDED +#endif + diff --git a/code/meosdb/mysql55/mysql/service_thd_alloc.h b/code/meosdb/mysql55/mysql/service_thd_alloc.h new file mode 100644 index 0000000..d737e5e --- /dev/null +++ b/code/meosdb/mysql55/mysql/service_thd_alloc.h @@ -0,0 +1,130 @@ +#ifndef MYSQL_SERVICE_THD_ALLOC_INCLUDED +/* Copyright (C) 2009 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +/** + @file + This service provdes functions to allocate memory in a connection local + memory pool. The memory allocated there will be automatically freed at the + end of the statement, don't use it for allocations that should live longer + than that. For short living allocations this is more efficient than + using my_malloc and friends, and automatic "garbage collection" allows not + to think about memory leaks. + + The pool is best for small to medium objects, don't use it for large + allocations - they are better served with my_malloc. +*/ + +#ifndef MYSQL_ABI_CHECK +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct st_mysql_lex_string +{ + char *str; + size_t length; +}; +typedef struct st_mysql_lex_string MYSQL_LEX_STRING; + +extern struct thd_alloc_service_st { + void *(*thd_alloc_func)(MYSQL_THD, unsigned int); + void *(*thd_calloc_func)(MYSQL_THD, unsigned int); + char *(*thd_strdup_func)(MYSQL_THD, const char *); + char *(*thd_strmake_func)(MYSQL_THD, const char *, unsigned int); + void *(*thd_memdup_func)(MYSQL_THD, const void*, unsigned int); + MYSQL_LEX_STRING *(*thd_make_lex_string_func)(MYSQL_THD, MYSQL_LEX_STRING *, + const char *, unsigned int, int); +} *thd_alloc_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define thd_alloc(thd,size) (thd_alloc_service->thd_alloc_func((thd), (size))) + +#define thd_calloc(thd,size) (thd_alloc_service->thd_calloc_func((thd), (size))) + +#define thd_strdup(thd,str) (thd_alloc_service->thd_strdup_func((thd), (str))) + +#define thd_strmake(thd,str,size) \ + (thd_alloc_service->thd_strmake_func((thd), (str), (size))) + +#define thd_memdup(thd,str,size) \ + (thd_alloc_service->thd_memdup_func((thd), (str), (size))) + +#define thd_make_lex_string(thd, lex_str, str, size, allocate_lex_string) \ + (thd_alloc_service->thd_make_lex_string_func((thd), (lex_str), (str), \ + (size), (allocate_lex_string))) + +#else + +/** + Allocate memory in the connection's local memory pool + + @details + When properly used in place of @c my_malloc(), this can significantly + improve concurrency. Don't use this or related functions to allocate + large chunks of memory. Use for temporary storage only. The memory + will be freed automatically at the end of the statement; no explicit + code is required to prevent memory leaks. + + @see alloc_root() +*/ +void *thd_alloc(MYSQL_THD thd, unsigned int size); +/** + @see thd_alloc() +*/ +void *thd_calloc(MYSQL_THD thd, unsigned int size); +/** + @see thd_alloc() +*/ +char *thd_strdup(MYSQL_THD thd, const char *str); +/** + @see thd_alloc() +*/ +char *thd_strmake(MYSQL_THD thd, const char *str, unsigned int size); +/** + @see thd_alloc() +*/ +void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size); + +/** + Create a LEX_STRING in this connection's local memory pool + + @param thd user thread connection handle + @param lex_str pointer to LEX_STRING object to be initialized + @param str initializer to be copied into lex_str + @param size length of str, in bytes + @param allocate_lex_string flag: if TRUE, allocate new LEX_STRING object, + instead of using lex_str value + @return NULL on failure, or pointer to the LEX_STRING object + + @see thd_alloc() +*/ +MYSQL_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_LEX_STRING *lex_str, + const char *str, unsigned int size, + int allocate_lex_string); + +#endif + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_THD_ALLOC_INCLUDED +#endif + diff --git a/code/meosdb/mysql55/mysql/service_thd_wait.h b/code/meosdb/mysql55/mysql/service_thd_wait.h new file mode 100644 index 0000000..61566fb --- /dev/null +++ b/code/meosdb/mysql55/mysql/service_thd_wait.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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 */ + +#ifndef MYSQL_SERVICE_THD_WAIT_INCLUDED +#define MYSQL_SERVICE_THD_WAIT_INCLUDED + +/** + @file include/mysql/service_thd_wait.h + This service provides functions for plugins and storage engines to report + when they are going to sleep/stall. + + SYNOPSIS + thd_wait_begin() - call just before a wait begins + thd Thread object + Use NULL if the thd is NOT known. + wait_type Type of wait + 1 -- short wait (e.g. for mutex) + 2 -- medium wait (e.g. for disk io) + 3 -- large wait (e.g. for locked row/table) + NOTES + This is used by the threadpool to have better knowledge of which + threads that currently are actively running on CPUs. When a thread + reports that it's going to sleep/stall, the threadpool scheduler is + free to start another thread in the pool most likely. The expected wait + time is simply an indication of how long the wait is expected to + become, the real wait time could be very different. + + thd_wait_end() called immediately after the wait is complete + + thd_wait_end() MUST be called if thd_wait_begin() was called. + + Using thd_wait_...() service is optional but recommended. Using it will + improve performance as the thread pool will be more active at managing the + thread workload. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _thd_wait_type_e { + THD_WAIT_MUTEX= 1, + THD_WAIT_DISKIO= 2, + THD_WAIT_ROW_TABLE_LOCK= 3, + THD_WAIT_GLOBAL_LOCK= 4 +} thd_wait_type; + +extern struct thd_wait_service_st { + void (*thd_wait_begin_func)(MYSQL_THD, thd_wait_type); + void (*thd_wait_end_func)(MYSQL_THD); +} *thd_wait_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define thd_wait_begin(_THD, _WAIT_TYPE) \ + thd_wait_service->thd_wait_begin_func(_THD, _WAIT_TYPE) +#define thd_wait_end(_THD) thd_wait_service->thd_wait_end_func(_THD) + +#else + +void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type); +void thd_wait_end(MYSQL_THD thd); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/code/meosdb/mysql55/mysql/service_thread_scheduler.h b/code/meosdb/mysql55/mysql/service_thread_scheduler.h new file mode 100644 index 0000000..d956e45 --- /dev/null +++ b/code/meosdb/mysql55/mysql/service_thread_scheduler.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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 +*/ + +#ifndef SERVICE_THREAD_SCHEDULER_INCLUDED +#define SERVICE_THREAD_SCHEDULER_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +struct scheduler_functions; + +extern struct my_thread_scheduler_service { + int (*set)(struct scheduler_functions *scheduler); + int (*reset)(); +} *my_thread_scheduler_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define my_thread_scheduler_set(F) my_thread_scheduler_service->set((F)) +#define my_thread_scheduler_reset() my_thread_scheduler_service->reset() + +#else + +/** + Set the thread scheduler to use for the server. + + @param scheduler Pointer to scheduler callbacks to use. + @retval 0 Scheduler installed correctly. + @retval 1 Invalid value (NULL) used for scheduler. +*/ +int my_thread_scheduler_set(struct scheduler_functions *scheduler); + +/** + Restore the previous thread scheduler. + + @note If no thread scheduler was installed previously with + thd_set_thread_scheduler, this function will report an error. + + @retval 0 Scheduler installed correctly. + @retval 1 No scheduler installed. +*/ +int my_thread_scheduler_reset(); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SERVICE_THREAD_SCHEDULER_INCLUDED */ diff --git a/code/meosdb/mysql55/mysql/services.h b/code/meosdb/mysql55/mysql/services.h new file mode 100644 index 0000000..d2cea75 --- /dev/null +++ b/code/meosdb/mysql55/mysql/services.h @@ -0,0 +1,32 @@ +#ifndef MYSQL_SERVICES_INCLUDED +/* Copyright (C) 2009 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICES_INCLUDED +#endif + diff --git a/code/meosdb/mysql55/mysql_com.h b/code/meosdb/mysql55/mysql_com.h new file mode 100644 index 0000000..288f310 --- /dev/null +++ b/code/meosdb/mysql55/mysql_com.h @@ -0,0 +1,572 @@ +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + + 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; version 2 of the License. + + 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 */ + +/* +** Common definition between mysql server & client +*/ + +#ifndef _mysql_com_h +#define _mysql_com_h + +#define HOSTNAME_LENGTH 60 +#define SYSTEM_CHARSET_MBMAXLEN 3 +#define NAME_CHAR_LEN 64 /* Field/table name length */ +#define USERNAME_CHAR_LENGTH 16 +#define NAME_LEN (NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN) +#define USERNAME_LENGTH (USERNAME_CHAR_LENGTH*SYSTEM_CHARSET_MBMAXLEN) + +#define MYSQL_AUTODETECT_CHARSET_NAME "auto" + +#define SERVER_VERSION_LENGTH 60 +#define SQLSTATE_LENGTH 5 + +/* + Maximum length of comments +*/ +#define TABLE_COMMENT_INLINE_MAXLEN 180 /* pre 6.0: 60 characters */ +#define TABLE_COMMENT_MAXLEN 2048 +#define COLUMN_COMMENT_MAXLEN 1024 +#define INDEX_COMMENT_MAXLEN 1024 + +/* + USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain + username and hostname parts of the user identifier with trailing zero in + MySQL standard format: + user_name_part@host_name_part\0 +*/ +#define USER_HOST_BUFF_SIZE HOSTNAME_LENGTH + USERNAME_LENGTH + 2 + +#define LOCAL_HOST "localhost" +#define LOCAL_HOST_NAMEDPIPE "." + + +#if defined(__WIN__) && !defined( _CUSTOMCONFIG_) +#define MYSQL_NAMEDPIPE "MySQL" +#define MYSQL_SERVICENAME "MySQL" +#endif /* __WIN__ */ + +/* + You should add new commands to the end of this list, otherwise old + servers won't be able to handle them as 'unsupported'. +*/ + +enum enum_server_command +{ + COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, + COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, + COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, + COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, + COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, + COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, + COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON, + /* don't forget to update const char *command_name[] in sql_parse.cc */ + + /* Must be last */ + COM_END +}; + + +/* + Length of random string sent by server on handshake; this is also length of + obfuscated password, recieved from client +*/ +#define SCRAMBLE_LENGTH 20 +#define SCRAMBLE_LENGTH_323 8 +/* length of password stored in the db: new passwords are preceeded with '*' */ +#define SCRAMBLED_PASSWORD_CHAR_LENGTH (SCRAMBLE_LENGTH*2+1) +#define SCRAMBLED_PASSWORD_CHAR_LENGTH_323 (SCRAMBLE_LENGTH_323*2) + + +#define NOT_NULL_FLAG 1 /* Field can't be NULL */ +#define PRI_KEY_FLAG 2 /* Field is part of a primary key */ +#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */ +#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */ +#define BLOB_FLAG 16 /* Field is a blob */ +#define UNSIGNED_FLAG 32 /* Field is unsigned */ +#define ZEROFILL_FLAG 64 /* Field is zerofill */ +#define BINARY_FLAG 128 /* Field is binary */ + +/* The following are only sent to new clients */ +#define ENUM_FLAG 256 /* field is an enum */ +#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ +#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */ +#define SET_FLAG 2048 /* field is a set */ +#define NO_DEFAULT_VALUE_FLAG 4096 /* Field doesn't have default value */ +#define ON_UPDATE_NOW_FLAG 8192 /* Field is set to NOW on UPDATE */ +#define NUM_FLAG 32768 /* Field is num (for clients) */ +#define PART_KEY_FLAG 16384 /* Intern; Part of some key */ +#define GROUP_FLAG 32768 /* Intern: Group field */ +#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ +#define BINCMP_FLAG 131072 /* Intern: Used by sql_yacc */ +#define GET_FIXED_FIELDS_FLAG (1 << 18) /* Used to get fields in item tree */ +#define FIELD_IN_PART_FUNC_FLAG (1 << 19)/* Field part of partition func */ +#define FIELD_IN_ADD_INDEX (1<< 20) /* Intern: Field used in ADD INDEX */ +#define FIELD_IS_RENAMED (1<< 21) /* Intern: Field is being renamed */ + +#define REFRESH_GRANT 1 /* Refresh grant tables */ +#define REFRESH_LOG 2 /* Start on new log file */ +#define REFRESH_TABLES 4 /* close all tables */ +#define REFRESH_HOSTS 8 /* Flush host cache */ +#define REFRESH_STATUS 16 /* Flush status variables */ +#define REFRESH_THREADS 32 /* Flush thread cache */ +#define REFRESH_SLAVE 64 /* Reset master info and restart slave + thread */ +#define REFRESH_MASTER 128 /* Remove all bin logs in the index + and truncate the index */ +#define REFRESH_ERROR_LOG 256 /* Rotate only the erorr log */ +#define REFRESH_ENGINE_LOG 512 /* Flush all storage engine logs */ +#define REFRESH_BINARY_LOG 1024 /* Flush the binary log */ +#define REFRESH_RELAY_LOG 2048 /* Flush the relay log */ +#define REFRESH_GENERAL_LOG 4096 /* Flush the general log */ +#define REFRESH_SLOW_LOG 8192 /* Flush the slow query log */ + +/* The following can't be set with mysql_refresh() */ +#define REFRESH_READ_LOCK 16384 /* Lock tables for read */ +#define REFRESH_FAST 32768 /* Intern flag */ + +/* RESET (remove all queries) from query cache */ +#define REFRESH_QUERY_CACHE 65536 +#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */ +#define REFRESH_DES_KEY_FILE 0x40000L +#define REFRESH_USER_RESOURCES 0x80000L + +#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ +#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ +#define CLIENT_LONG_FLAG 4 /* Get all column flags */ +#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ +#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ +#define CLIENT_COMPRESS 32 /* Can use compression protocol */ +#define CLIENT_ODBC 64 /* Odbc client */ +#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ +#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ +#define CLIENT_PROTOCOL_41 512 /* New 4.1 protocol */ +#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ +#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ +#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ +#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ +#define CLIENT_RESERVED 16384 /* Old flag for 4.1 protocol */ +#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */ +#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */ +#define CLIENT_MULTI_RESULTS (1UL << 17) /* Enable/disable multi-results */ +#define CLIENT_PS_MULTI_RESULTS (1UL << 18) /* Multi-results in PS-protocol */ + +#define CLIENT_PLUGIN_AUTH (1UL << 19) /* Client supports plugin authentication */ + +#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) +#define CLIENT_REMEMBER_OPTIONS (1UL << 31) + +#ifdef HAVE_COMPRESS +#define CAN_CLIENT_COMPRESS CLIENT_COMPRESS +#else +#define CAN_CLIENT_COMPRESS 0 +#endif + +/* Gather all possible capabilites (flags) supported by the server */ +#define CLIENT_ALL_FLAGS (CLIENT_LONG_PASSWORD | \ + CLIENT_FOUND_ROWS | \ + CLIENT_LONG_FLAG | \ + CLIENT_CONNECT_WITH_DB | \ + CLIENT_NO_SCHEMA | \ + CLIENT_COMPRESS | \ + CLIENT_ODBC | \ + CLIENT_LOCAL_FILES | \ + CLIENT_IGNORE_SPACE | \ + CLIENT_PROTOCOL_41 | \ + CLIENT_INTERACTIVE | \ + CLIENT_SSL | \ + CLIENT_IGNORE_SIGPIPE | \ + CLIENT_TRANSACTIONS | \ + CLIENT_RESERVED | \ + CLIENT_SECURE_CONNECTION | \ + CLIENT_MULTI_STATEMENTS | \ + CLIENT_MULTI_RESULTS | \ + CLIENT_PS_MULTI_RESULTS | \ + CLIENT_SSL_VERIFY_SERVER_CERT | \ + CLIENT_REMEMBER_OPTIONS | \ + CLIENT_PLUGIN_AUTH) + +/* + Switch off the flags that are optional and depending on build flags + If any of the optional flags is supported by the build it will be switched + on before sending to the client during the connection handshake. +*/ +#define CLIENT_BASIC_FLAGS (((CLIENT_ALL_FLAGS & ~CLIENT_SSL) \ + & ~CLIENT_COMPRESS) \ + & ~CLIENT_SSL_VERIFY_SERVER_CERT) + +/** + Is raised when a multi-statement transaction + has been started, either explicitly, by means + of BEGIN or COMMIT AND CHAIN, or + implicitly, by the first transactional + statement, when autocommit=off. +*/ +#define SERVER_STATUS_IN_TRANS 1 +#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ +#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */ +#define SERVER_QUERY_NO_GOOD_INDEX_USED 16 +#define SERVER_QUERY_NO_INDEX_USED 32 +/** + The server was able to fulfill the clients request and opened a + read-only non-scrollable cursor for a query. This flag comes + in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. +*/ +#define SERVER_STATUS_CURSOR_EXISTS 64 +/** + This flag is sent when a read-only cursor is exhausted, in reply to + COM_STMT_FETCH command. +*/ +#define SERVER_STATUS_LAST_ROW_SENT 128 +#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */ +#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 +/** + Sent to the client if after a prepared statement reprepare + we discovered that the new statement returns a different + number of result set columns. +*/ +#define SERVER_STATUS_METADATA_CHANGED 1024 +#define SERVER_QUERY_WAS_SLOW 2048 + +/** + To mark ResultSet containing output parameter values. +*/ +#define SERVER_PS_OUT_PARAMS 4096 + +/** + Server status flags that must be cleared when starting + execution of a new SQL statement. + Flags from this set are only added to the + current server status by the execution engine, but + never removed -- the execution engine expects them + to disappear automagically by the next command. +*/ +#define SERVER_STATUS_CLEAR_SET (SERVER_QUERY_NO_GOOD_INDEX_USED| \ + SERVER_QUERY_NO_INDEX_USED|\ + SERVER_MORE_RESULTS_EXISTS|\ + SERVER_STATUS_METADATA_CHANGED |\ + SERVER_QUERY_WAS_SLOW |\ + SERVER_STATUS_DB_DROPPED |\ + SERVER_STATUS_CURSOR_EXISTS|\ + SERVER_STATUS_LAST_ROW_SENT) + +#define MYSQL_ERRMSG_SIZE 512 +#define NET_READ_TIMEOUT 30 /* Timeout on read */ +#define NET_WRITE_TIMEOUT 60 /* Timeout on write */ +#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ + +#define ONLY_KILL_QUERY 1 + + +struct st_vio; /* Only C */ +typedef struct st_vio Vio; + +#define MAX_TINYINT_WIDTH 3 /* Max width for a TINY w.o. sign */ +#define MAX_SMALLINT_WIDTH 5 /* Max width for a SHORT w.o. sign */ +#define MAX_MEDIUMINT_WIDTH 8 /* Max width for a INT24 w.o. sign */ +#define MAX_INT_WIDTH 10 /* Max width for a LONG w.o. sign */ +#define MAX_BIGINT_WIDTH 20 /* Max width for a LONGLONG */ +#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */ +#define MAX_BLOB_WIDTH 16777216 /* Default width for blob */ + +typedef struct st_net { +#if !defined(CHECK_EMBEDDED_DIFFERENCES) || !defined(EMBEDDED_LIBRARY) + Vio *vio; + unsigned char *buff,*buff_end,*write_pos,*read_pos; + my_socket fd; /* For Perl DBI/dbd */ + /* + The following variable is set if we are doing several queries in one + command ( as in LOAD TABLE ... FROM MASTER ), + and do not want to confuse the client with OK at the wrong time + */ + unsigned long remain_in_buf,length, buf_length, where_b; + unsigned long max_packet,max_packet_size; + unsigned int pkt_nr,compress_pkt_nr; + unsigned int write_timeout, read_timeout, retry_count; + int fcntl; + unsigned int *return_status; + unsigned char reading_or_writing; + char save_char; + my_bool unused1; /* Please remove with the next incompatible ABI change. */ + my_bool unused2; /* Please remove with the next incompatible ABI change */ + my_bool compress; + my_bool unused3; /* Please remove with the next incompatible ABI change. */ + /* + Pointer to query object in query cache, do not equal NULL (0) for + queries in cache that have not stored its results yet + */ +#endif + /* + Unused, please remove with the next incompatible ABI change. + */ + unsigned char *unused; + unsigned int last_errno; + unsigned char error; + my_bool unused4; /* Please remove with the next incompatible ABI change. */ + my_bool unused5; /* Please remove with the next incompatible ABI change. */ + /** Client library error message buffer. Actually belongs to struct MYSQL. */ + char last_error[MYSQL_ERRMSG_SIZE]; + /** Client library sqlstate buffer. Set along with the error message. */ + char sqlstate[SQLSTATE_LENGTH+1]; + void *extension; +#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) + /* + Controls whether a big packet should be skipped. + + Initially set to FALSE by default. Unauthenticated sessions must have + this set to FALSE so that the server can't be tricked to read packets + indefinitely. + */ + my_bool skip_big_packet; +#endif +} NET; + + +#define packet_error (~(unsigned long) 0) + +enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, + MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, + MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, + MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, + MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, + MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, + MYSQL_TYPE_BIT, + MYSQL_TYPE_NEWDECIMAL=246, + MYSQL_TYPE_ENUM=247, + MYSQL_TYPE_SET=248, + MYSQL_TYPE_TINY_BLOB=249, + MYSQL_TYPE_MEDIUM_BLOB=250, + MYSQL_TYPE_LONG_BLOB=251, + MYSQL_TYPE_BLOB=252, + MYSQL_TYPE_VAR_STRING=253, + MYSQL_TYPE_STRING=254, + MYSQL_TYPE_GEOMETRY=255 + +}; + +/* For backward compatibility */ +#define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS +#define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL +#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL +#define FIELD_TYPE_TINY MYSQL_TYPE_TINY +#define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT +#define FIELD_TYPE_LONG MYSQL_TYPE_LONG +#define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT +#define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE +#define FIELD_TYPE_NULL MYSQL_TYPE_NULL +#define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP +#define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG +#define FIELD_TYPE_INT24 MYSQL_TYPE_INT24 +#define FIELD_TYPE_DATE MYSQL_TYPE_DATE +#define FIELD_TYPE_TIME MYSQL_TYPE_TIME +#define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME +#define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR +#define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE +#define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM +#define FIELD_TYPE_SET MYSQL_TYPE_SET +#define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB +#define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB +#define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB +#define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB +#define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING +#define FIELD_TYPE_STRING MYSQL_TYPE_STRING +#define FIELD_TYPE_CHAR MYSQL_TYPE_TINY +#define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM +#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY +#define FIELD_TYPE_BIT MYSQL_TYPE_BIT + + +/* Shutdown/kill enums and constants */ + +/* Bits for THD::killable. */ +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) + +enum mysql_enum_shutdown_level { + /* + We want levels to be in growing order of hardness (because we use number + comparisons). Note that DEFAULT does not respect the growing property, but + it's ok. + */ + SHUTDOWN_DEFAULT = 0, + /* wait for existing connections to finish */ + SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, + /* wait for existing trans to finish */ + SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, + /* wait for existing updates to finish (=> no partial MyISAM update) */ + SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, + /* flush InnoDB buffers and other storage engines' buffers*/ + SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + /* don't flush InnoDB buffers, flush other storage engines' buffers*/ + SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + /* Now the 2 levels of the KILL command */ +#if MYSQL_VERSION_ID >= 50000 + KILL_QUERY= 254, +#endif + KILL_CONNECTION= 255 +}; + + +enum enum_cursor_type +{ + CURSOR_TYPE_NO_CURSOR= 0, + CURSOR_TYPE_READ_ONLY= 1, + CURSOR_TYPE_FOR_UPDATE= 2, + CURSOR_TYPE_SCROLLABLE= 4 +}; + + +/* options for mysql_set_option */ +enum enum_mysql_set_option +{ + MYSQL_OPTION_MULTI_STATEMENTS_ON, + MYSQL_OPTION_MULTI_STATEMENTS_OFF +}; + +#define net_new_transaction(net) ((net)->pkt_nr=0) + +#ifdef __cplusplus +extern "C" { +#endif + +my_bool my_net_init(NET *net, Vio* vio); +void my_net_local_init(NET *net); +void net_end(NET *net); + void net_clear(NET *net, my_bool clear_buffer); +my_bool net_realloc(NET *net, size_t length); +my_bool net_flush(NET *net); +my_bool my_net_write(NET *net,const unsigned char *packet, size_t len); +my_bool net_write_command(NET *net,unsigned char command, + const unsigned char *header, size_t head_len, + const unsigned char *packet, size_t len); +int net_real_write(NET *net,const unsigned char *packet, size_t len); +unsigned long my_net_read(NET *net); + +#ifdef _global_h +void my_net_set_write_timeout(NET *net, uint timeout); +void my_net_set_read_timeout(NET *net, uint timeout); +#endif + +struct sockaddr; +int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen, + unsigned int timeout); + +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + +#ifdef __cplusplus +} +#endif + + /* The following is for user defined functions */ + +enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, + DECIMAL_RESULT}; + +typedef struct st_udf_args +{ + unsigned int arg_count; /* Number of arguments */ + enum Item_result *arg_type; /* Pointer to item_results */ + char **args; /* Pointer to argument */ + unsigned long *lengths; /* Length of string arguments */ + char *maybe_null; /* Set to 1 for all maybe_null args */ + char **attributes; /* Pointer to attribute name */ + unsigned long *attribute_lengths; /* Length of attribute arguments */ + void *extension; +} UDF_ARGS; + + /* This holds information about the result */ + +typedef struct st_udf_init +{ + my_bool maybe_null; /* 1 if function can return NULL */ + unsigned int decimals; /* for real functions */ + unsigned long max_length; /* For string functions */ + char *ptr; /* free pointer for function data */ + my_bool const_item; /* 1 if function always returns the same value */ + void *extension; +} UDF_INIT; +/* + TODO: add a notion for determinism of the UDF. + See Item_udf_func::update_used_tables () +*/ + + /* Constants when using compression */ +#define NET_HEADER_SIZE 4 /* standard header size */ +#define COMP_HEADER_SIZE 3 /* compression header extra size */ + + /* Prototypes to password functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + These functions are used for authentication by client and server and + implemented in sql/password.c +*/ + +void randominit(struct rand_struct *, unsigned long seed1, + unsigned long seed2); +double my_rnd(struct rand_struct *); +void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st); + +void hash_password(unsigned long *to, const char *password, unsigned int password_len); +void make_scrambled_password_323(char *to, const char *password); +void scramble_323(char *to, const char *message, const char *password); +my_bool check_scramble_323(const unsigned char *reply, const char *message, + unsigned long *salt); +void get_salt_from_password_323(unsigned long *res, const char *password); +void make_password_from_salt_323(char *to, const unsigned long *salt); + +void make_scrambled_password(char *to, const char *password); +void scramble(char *to, const char *message, const char *password); +my_bool check_scramble(const unsigned char *reply, const char *message, + const unsigned char *hash_stage2); +void get_salt_from_password(unsigned char *res, const char *password); +void make_password_from_salt(char *to, const unsigned char *hash_stage2); +char *octet2hex(char *to, const char *str, unsigned int len); + +/* end of password.c */ + +char *get_tty_password(const char *opt_message); +const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); + +/* Some other useful functions */ + +my_bool my_thread_init(void); +void my_thread_end(void); + +#ifdef _global_h +ulong STDCALL net_field_length(uchar **packet); +my_ulonglong net_field_length_ll(uchar **packet); +uchar *net_store_length(uchar *pkg, ulonglong length); +#endif + +#ifdef __cplusplus +} +#endif + +#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */ +#define MYSQL_STMT_HEADER 4 +#define MYSQL_LONG_DATA_HEADER 6 + +#define NOT_FIXED_DEC 31 +#endif diff --git a/code/meosdb/mysql55/mysql_embed.h b/code/meosdb/mysql55/mysql_embed.h new file mode 100644 index 0000000..a648aa9 --- /dev/null +++ b/code/meosdb/mysql55/mysql_embed.h @@ -0,0 +1,31 @@ +#ifndef MYSQL_EMBED_INCLUDED +#define MYSQL_EMBED_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + +/* Defines that are unique to the embedded version of MySQL */ + +#ifdef EMBEDDED_LIBRARY + +/* Things we don't need in the embedded version of MySQL */ +/* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ + +#undef HAVE_DLOPEN /* No udf functions */ +#undef HAVE_SMEM /* No shared memory */ +#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ + +#endif /* EMBEDDED_LIBRARY */ +#endif /* MYSQL_EMBED_INCLUDED */ diff --git a/code/meosdb/mysql55/mysql_time.h b/code/meosdb/mysql55/mysql_time.h new file mode 100644 index 0000000..33c3636 --- /dev/null +++ b/code/meosdb/mysql55/mysql_time.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2004 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _mysql_time_h_ +#define _mysql_time_h_ + +/* + Time declarations shared between the server and client API: + you should not add anything to this header unless it's used + (and hence should be visible) in mysql.h. + If you're looking for a place to add new time-related declaration, + it's most likely my_time.h. See also "C API Handling of Date + and Time Values" chapter in documentation. +*/ + +enum enum_mysql_timestamp_type +{ + MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, + MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 +}; + + +/* + Structure which is used to represent datetime values inside MySQL. + + We assume that values in this structure are normalized, i.e. year <= 9999, + month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions + in server such as my_system_gmt_sec() or make_time() family of functions + rely on this (actually now usage of make_*() family relies on a bit weaker + restriction). Also functions that produce MYSQL_TIME as result ensure this. + There is one exception to this rule though if this structure holds time + value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold + bigger values. +*/ +typedef struct st_mysql_time +{ + unsigned int year, month, day, hour, minute, second; + unsigned long second_part; + my_bool neg; + enum enum_mysql_timestamp_type time_type; +} MYSQL_TIME; + +#endif /* _mysql_time_h_ */ diff --git a/code/meosdb/mysql55/mysql_version.h b/code/meosdb/mysql55/mysql_version.h new file mode 100644 index 0000000..4bfb8e1 --- /dev/null +++ b/code/meosdb/mysql55/mysql_version.h @@ -0,0 +1,30 @@ +/* Copyright Abandoned 1996, 1999, 2001 MySQL AB + This file is public domain and comes with NO WARRANTY of any kind */ + +/* Version numbers for protocol & mysqld */ + +#ifndef _mysql_version_h +#define _mysql_version_h +#ifdef _CUSTOMCONFIG_ +#include +#else +#define PROTOCOL_VERSION 10 +#define MYSQL_SERVER_VERSION "5.5.9" +#define MYSQL_BASE_VERSION "mysqld-5.5" +#define MYSQL_SERVER_SUFFIX_DEF "" +#define FRM_VER 6 +#define MYSQL_VERSION_ID 50509 +#define MYSQL_PORT 3306 +#define MYSQL_PORT_DEFAULT 0 +#define MYSQL_UNIX_ADDR "/tmp/mysql.sock" +#define MYSQL_CONFIG_NAME "my" +#define MYSQL_COMPILATION_COMMENT "MySQL Community Server (GPL)" + +/* mysqld compile time options */ +#endif /* _CUSTOMCONFIG_ */ + +#ifndef LICENSE +#define LICENSE GPL +#endif /* LICENSE */ + +#endif /* _mysql_version_h */ diff --git a/code/meosdb/mysql55/mysqld_ername.h b/code/meosdb/mysql55/mysqld_ername.h new file mode 100644 index 0000000..1cb6a23 --- /dev/null +++ b/code/meosdb/mysql55/mysqld_ername.h @@ -0,0 +1,708 @@ +/* Autogenerated file, please don't edit */ + +{ "ER_HASHCHK", 1000, "hashchk" }, +{ "ER_NISAMCHK", 1001, "isamchk" }, +{ "ER_NO", 1002, "NO" }, +{ "ER_YES", 1003, "YES" }, +{ "ER_CANT_CREATE_FILE", 1004, "Can\'t create file \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_CREATE_TABLE", 1005, "Can\'t create table \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_CREATE_DB", 1006, "Can\'t create database \'%-.192s\' (errno: %d)" }, +{ "ER_DB_CREATE_EXISTS", 1007, "Can\'t create database \'%-.192s\'; database exists" }, +{ "ER_DB_DROP_EXISTS", 1008, "Can\'t drop database \'%-.192s\'; database doesn\'t exist" }, +{ "ER_DB_DROP_DELETE", 1009, "Error dropping database (can\'t delete \'%-.192s\', errno: %d)" }, +{ "ER_DB_DROP_RMDIR", 1010, "Error dropping database (can\'t rmdir \'%-.192s\', errno: %d)" }, +{ "ER_CANT_DELETE_FILE", 1011, "Error on delete of \'%-.192s\' (errno: %d)" }, +{ "ER_CANT_FIND_SYSTEM_REC", 1012, "Can\'t read record in system table" }, +{ "ER_CANT_GET_STAT", 1013, "Can\'t get status of \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_GET_WD", 1014, "Can\'t get working directory (errno: %d)" }, +{ "ER_CANT_LOCK", 1015, "Can\'t lock file (errno: %d)" }, +{ "ER_CANT_OPEN_FILE", 1016, "Can\'t open file: \'%-.200s\' (errno: %d)" }, +{ "ER_FILE_NOT_FOUND", 1017, "Can\'t find file: \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_READ_DIR", 1018, "Can\'t read dir of \'%-.192s\' (errno: %d)" }, +{ "ER_CANT_SET_WD", 1019, "Can\'t change dir to \'%-.192s\' (errno: %d)" }, +{ "ER_CHECKREAD", 1020, "Record has changed since last read in table \'%-.192s\'" }, +{ "ER_DISK_FULL", 1021, "Disk full (%s); waiting for someone to free some space..." }, +{ "ER_DUP_KEY", 1022, "Can\'t write; duplicate key in table \'%-.192s\'" }, +{ "ER_ERROR_ON_CLOSE", 1023, "Error on close of \'%-.192s\' (errno: %d)" }, +{ "ER_ERROR_ON_READ", 1024, "Error reading file \'%-.200s\' (errno: %d)" }, +{ "ER_ERROR_ON_RENAME", 1025, "Error on rename of \'%-.210s\' to \'%-.210s\' (errno: %d)" }, +{ "ER_ERROR_ON_WRITE", 1026, "Error writing file \'%-.200s\' (errno: %d)" }, +{ "ER_FILE_USED", 1027, "\'%-.192s\' is locked against change" }, +{ "ER_FILSORT_ABORT", 1028, "Sort aborted" }, +{ "ER_FORM_NOT_FOUND", 1029, "View \'%-.192s\' doesn\'t exist for \'%-.192s\'" }, +{ "ER_GET_ERRNO", 1030, "Got error %d from storage engine" }, +{ "ER_ILLEGAL_HA", 1031, "Table storage engine for \'%-.192s\' doesn\'t have this option" }, +{ "ER_KEY_NOT_FOUND", 1032, "Can\'t find record in \'%-.192s\'" }, +{ "ER_NOT_FORM_FILE", 1033, "Incorrect information in file: \'%-.200s\'" }, +{ "ER_NOT_KEYFILE", 1034, "Incorrect key file for table \'%-.200s\'; try to repair it" }, +{ "ER_OLD_KEYFILE", 1035, "Old key file for table \'%-.192s\'; repair it!" }, +{ "ER_OPEN_AS_READONLY", 1036, "Table \'%-.192s\' is read only" }, +{ "ER_OUTOFMEMORY", 1037, "Out of memory; restart server and try again (needed %d bytes)" }, +{ "ER_OUT_OF_SORTMEMORY", 1038, "Out of sort memory; increase server sort buffer size" }, +{ "ER_UNEXPECTED_EOF", 1039, "Unexpected EOF found when reading file \'%-.192s\' (errno: %d)" }, +{ "ER_CON_COUNT_ERROR", 1040, "Too many connections" }, +{ "ER_OUT_OF_RESOURCES", 1041, "Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use \'ulimit\' to allow mysqld to use more memory or you can add more swap space" }, +{ "ER_BAD_HOST_ERROR", 1042, "Can\'t get hostname for your address" }, +{ "ER_HANDSHAKE_ERROR", 1043, "Bad handshake" }, +{ "ER_DBACCESS_DENIED_ERROR", 1044, "Access denied for user \'%-.48s\'@\'%-.64s\' to database \'%-.192s\'" }, +{ "ER_ACCESS_DENIED_ERROR", 1045, "Access denied for user \'%-.48s\'@\'%-.64s\' (using password: %s)" }, +{ "ER_NO_DB_ERROR", 1046, "No database selected" }, +{ "ER_UNKNOWN_COM_ERROR", 1047, "Unknown command" }, +{ "ER_BAD_NULL_ERROR", 1048, "Column \'%-.192s\' cannot be null" }, +{ "ER_BAD_DB_ERROR", 1049, "Unknown database \'%-.192s\'" }, +{ "ER_TABLE_EXISTS_ERROR", 1050, "Table \'%-.192s\' already exists" }, +{ "ER_BAD_TABLE_ERROR", 1051, "Unknown table \'%-.100s\'" }, +{ "ER_NON_UNIQ_ERROR", 1052, "Column \'%-.192s\' in %-.192s is ambiguous" }, +{ "ER_SERVER_SHUTDOWN", 1053, "Server shutdown in progress" }, +{ "ER_BAD_FIELD_ERROR", 1054, "Unknown column \'%-.192s\' in \'%-.192s\'" }, +{ "ER_WRONG_FIELD_WITH_GROUP", 1055, "\'%-.192s\' isn\'t in GROUP BY" }, +{ "ER_WRONG_GROUP_FIELD", 1056, "Can\'t group on \'%-.192s\'" }, +{ "ER_WRONG_SUM_SELECT", 1057, "Statement has sum functions and columns in same statement" }, +{ "ER_WRONG_VALUE_COUNT", 1058, "Column count doesn\'t match value count" }, +{ "ER_TOO_LONG_IDENT", 1059, "Identifier name \'%-.100s\' is too long" }, +{ "ER_DUP_FIELDNAME", 1060, "Duplicate column name \'%-.192s\'" }, +{ "ER_DUP_KEYNAME", 1061, "Duplicate key name \'%-.192s\'" }, +{ "ER_DUP_ENTRY", 1062, "Duplicate entry \'%-.192s\' for key %d" }, +{ "ER_WRONG_FIELD_SPEC", 1063, "Incorrect column specifier for column \'%-.192s\'" }, +{ "ER_PARSE_ERROR", 1064, "%s near \'%-.80s\' at line %d" }, +{ "ER_EMPTY_QUERY", 1065, "Query was empty" }, +{ "ER_NONUNIQ_TABLE", 1066, "Not unique table/alias: \'%-.192s\'" }, +{ "ER_INVALID_DEFAULT", 1067, "Invalid default value for \'%-.192s\'" }, +{ "ER_MULTIPLE_PRI_KEY", 1068, "Multiple primary key defined" }, +{ "ER_TOO_MANY_KEYS", 1069, "Too many keys specified; max %d keys allowed" }, +{ "ER_TOO_MANY_KEY_PARTS", 1070, "Too many key parts specified; max %d parts allowed" }, +{ "ER_TOO_LONG_KEY", 1071, "Specified key was too long; max key length is %d bytes" }, +{ "ER_KEY_COLUMN_DOES_NOT_EXITS", 1072, "Key column \'%-.192s\' doesn\'t exist in table" }, +{ "ER_BLOB_USED_AS_KEY", 1073, "BLOB column \'%-.192s\' can\'t be used in key specification with the used table type" }, +{ "ER_TOO_BIG_FIELDLENGTH", 1074, "Column length too big for column \'%-.192s\' (max = %lu); use BLOB or TEXT instead" }, +{ "ER_WRONG_AUTO_KEY", 1075, "Incorrect table definition; there can be only one auto column and it must be defined as a key" }, +{ "ER_READY", 1076, "%s: ready for connections.\nVersion: \'%s\' socket: \'%s\' port: %d" }, +{ "ER_NORMAL_SHUTDOWN", 1077, "%s: Normal shutdown\n" }, +{ "ER_GOT_SIGNAL", 1078, "%s: Got signal %d. Aborting!\n" }, +{ "ER_SHUTDOWN_COMPLETE", 1079, "%s: Shutdown complete\n" }, +{ "ER_FORCING_CLOSE", 1080, "%s: Forcing close of thread %ld user: \'%-.48s\'\n" }, +{ "ER_IPSOCK_ERROR", 1081, "Can\'t create IP socket" }, +{ "ER_NO_SUCH_INDEX", 1082, "Table \'%-.192s\' has no index like the one used in CREATE INDEX; recreate the table" }, +{ "ER_WRONG_FIELD_TERMINATORS", 1083, "Field separator argument is not what is expected; check the manual" }, +{ "ER_BLOBS_AND_NO_TERMINATED", 1084, "You can\'t use fixed rowlength with BLOBs; please use \'fields terminated by\'" }, +{ "ER_TEXTFILE_NOT_READABLE", 1085, "The file \'%-.128s\' must be in the database directory or be readable by all" }, +{ "ER_FILE_EXISTS_ERROR", 1086, "File \'%-.200s\' already exists" }, +{ "ER_LOAD_INFO", 1087, "Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld" }, +{ "ER_ALTER_INFO", 1088, "Records: %ld Duplicates: %ld" }, +{ "ER_WRONG_SUB_KEY", 1089, "Incorrect prefix key; the used key part isn\'t a string, the used length is longer than the key part, or the storage engine doesn\'t support unique prefix keys" }, +{ "ER_CANT_REMOVE_ALL_FIELDS", 1090, "You can\'t delete all columns with ALTER TABLE; use DROP TABLE instead" }, +{ "ER_CANT_DROP_FIELD_OR_KEY", 1091, "Can\'t DROP \'%-.192s\'; check that column/key exists" }, +{ "ER_INSERT_INFO", 1092, "Records: %ld Duplicates: %ld Warnings: %ld" }, +{ "ER_UPDATE_TABLE_USED", 1093, "You can\'t specify target table \'%-.192s\' for update in FROM clause" }, +{ "ER_NO_SUCH_THREAD", 1094, "Unknown thread id: %lu" }, +{ "ER_KILL_DENIED_ERROR", 1095, "You are not owner of thread %lu" }, +{ "ER_NO_TABLES_USED", 1096, "No tables used" }, +{ "ER_TOO_BIG_SET", 1097, "Too many strings for column %-.192s and SET" }, +{ "ER_NO_UNIQUE_LOGFILE", 1098, "Can\'t generate a unique log-filename %-.200s.(1-999)\n" }, +{ "ER_TABLE_NOT_LOCKED_FOR_WRITE", 1099, "Table \'%-.192s\' was locked with a READ lock and can\'t be updated" }, +{ "ER_TABLE_NOT_LOCKED", 1100, "Table \'%-.192s\' was not locked with LOCK TABLES" }, +{ "ER_BLOB_CANT_HAVE_DEFAULT", 1101, "BLOB/TEXT column \'%-.192s\' can\'t have a default value" }, +{ "ER_WRONG_DB_NAME", 1102, "Incorrect database name \'%-.100s\'" }, +{ "ER_WRONG_TABLE_NAME", 1103, "Incorrect table name \'%-.100s\'" }, +{ "ER_TOO_BIG_SELECT", 1104, "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay" }, +{ "ER_UNKNOWN_ERROR", 1105, "Unknown error" }, +{ "ER_UNKNOWN_PROCEDURE", 1106, "Unknown procedure \'%-.192s\'" }, +{ "ER_WRONG_PARAMCOUNT_TO_PROCEDURE", 1107, "Incorrect parameter count to procedure \'%-.192s\'" }, +{ "ER_WRONG_PARAMETERS_TO_PROCEDURE", 1108, "Incorrect parameters to procedure \'%-.192s\'" }, +{ "ER_UNKNOWN_TABLE", 1109, "Unknown table \'%-.192s\' in %-.32s" }, +{ "ER_FIELD_SPECIFIED_TWICE", 1110, "Column \'%-.192s\' specified twice" }, +{ "ER_INVALID_GROUP_FUNC_USE", 1111, "Invalid use of group function" }, +{ "ER_UNSUPPORTED_EXTENSION", 1112, "Table \'%-.192s\' uses an extension that doesn\'t exist in this MySQL version" }, +{ "ER_TABLE_MUST_HAVE_COLUMNS", 1113, "A table must have at least 1 column" }, +{ "ER_RECORD_FILE_FULL", 1114, "The table \'%-.192s\' is full" }, +{ "ER_UNKNOWN_CHARACTER_SET", 1115, "Unknown character set: \'%-.64s\'" }, +{ "ER_TOO_MANY_TABLES", 1116, "Too many tables; MySQL can only use %d tables in a join" }, +{ "ER_TOO_MANY_FIELDS", 1117, "Too many columns" }, +{ "ER_TOO_BIG_ROWSIZE", 1118, "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs" }, +{ "ER_STACK_OVERRUN", 1119, "Thread stack overrun: Used: %ld of a %ld stack. Use \'mysqld --thread_stack=#\' to specify a bigger stack if needed" }, +{ "ER_WRONG_OUTER_JOIN", 1120, "Cross dependency found in OUTER JOIN; examine your ON conditions" }, +{ "ER_NULL_COLUMN_IN_INDEX", 1121, "Table handler doesn\'t support NULL in given index. Please change column \'%-.192s\' to be NOT NULL or use another handler" }, +{ "ER_CANT_FIND_UDF", 1122, "Can\'t load function \'%-.192s\'" }, +{ "ER_CANT_INITIALIZE_UDF", 1123, "Can\'t initialize function \'%-.192s\'; %-.80s" }, +{ "ER_UDF_NO_PATHS", 1124, "No paths allowed for shared library" }, +{ "ER_UDF_EXISTS", 1125, "Function \'%-.192s\' already exists" }, +{ "ER_CANT_OPEN_LIBRARY", 1126, "Can\'t open shared library \'%-.192s\' (errno: %d %-.128s)" }, +{ "ER_CANT_FIND_DL_ENTRY", 1127, "Can\'t find symbol \'%-.128s\' in library" }, +{ "ER_FUNCTION_NOT_DEFINED", 1128, "Function \'%-.192s\' is not defined" }, +{ "ER_HOST_IS_BLOCKED", 1129, "Host \'%-.64s\' is blocked because of many connection errors; unblock with \'mysqladmin flush-hosts\'" }, +{ "ER_HOST_NOT_PRIVILEGED", 1130, "Host \'%-.64s\' is not allowed to connect to this MySQL server" }, +{ "ER_PASSWORD_ANONYMOUS_USER", 1131, "You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords" }, +{ "ER_PASSWORD_NOT_ALLOWED", 1132, "You must have privileges to update tables in the mysql database to be able to change passwords for others" }, +{ "ER_PASSWORD_NO_MATCH", 1133, "Can\'t find any matching row in the user table" }, +{ "ER_UPDATE_INFO", 1134, "Rows matched: %ld Changed: %ld Warnings: %ld" }, +{ "ER_CANT_CREATE_THREAD", 1135, "Can\'t create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug" }, +{ "ER_WRONG_VALUE_COUNT_ON_ROW", 1136, "Column count doesn\'t match value count at row %ld" }, +{ "ER_CANT_REOPEN_TABLE", 1137, "Can\'t reopen table: \'%-.192s\'" }, +{ "ER_INVALID_USE_OF_NULL", 1138, "Invalid use of NULL value" }, +{ "ER_REGEXP_ERROR", 1139, "Got error \'%-.64s\' from regexp" }, +{ "ER_MIX_OF_GROUP_FUNC_AND_FIELDS", 1140, "Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause" }, +{ "ER_NONEXISTING_GRANT", 1141, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\'" }, +{ "ER_TABLEACCESS_DENIED_ERROR", 1142, "%-.16s command denied to user \'%-.48s\'@\'%-.64s\' for table \'%-.192s\'" }, +{ "ER_COLUMNACCESS_DENIED_ERROR", 1143, "%-.16s command denied to user \'%-.48s\'@\'%-.64s\' for column \'%-.192s\' in table \'%-.192s\'" }, +{ "ER_ILLEGAL_GRANT_FOR_TABLE", 1144, "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used" }, +{ "ER_GRANT_WRONG_HOST_OR_USER", 1145, "The host or user argument to GRANT is too long" }, +{ "ER_NO_SUCH_TABLE", 1146, "Table \'%-.192s.%-.192s\' doesn\'t exist" }, +{ "ER_NONEXISTING_TABLE_GRANT", 1147, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\' on table \'%-.192s\'" }, +{ "ER_NOT_ALLOWED_COMMAND", 1148, "The used command is not allowed with this MySQL version" }, +{ "ER_SYNTAX_ERROR", 1149, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use" }, +{ "ER_DELAYED_CANT_CHANGE_LOCK", 1150, "Delayed insert thread couldn\'t get requested lock for table %-.192s" }, +{ "ER_TOO_MANY_DELAYED_THREADS", 1151, "Too many delayed threads in use" }, +{ "ER_ABORTING_CONNECTION", 1152, "Aborted connection %ld to db: \'%-.192s\' user: \'%-.48s\' (%-.64s)" }, +{ "ER_NET_PACKET_TOO_LARGE", 1153, "Got a packet bigger than \'max_allowed_packet\' bytes" }, +{ "ER_NET_READ_ERROR_FROM_PIPE", 1154, "Got a read error from the connection pipe" }, +{ "ER_NET_FCNTL_ERROR", 1155, "Got an error from fcntl()" }, +{ "ER_NET_PACKETS_OUT_OF_ORDER", 1156, "Got packets out of order" }, +{ "ER_NET_UNCOMPRESS_ERROR", 1157, "Couldn\'t uncompress communication packet" }, +{ "ER_NET_READ_ERROR", 1158, "Got an error reading communication packets" }, +{ "ER_NET_READ_INTERRUPTED", 1159, "Got timeout reading communication packets" }, +{ "ER_NET_ERROR_ON_WRITE", 1160, "Got an error writing communication packets" }, +{ "ER_NET_WRITE_INTERRUPTED", 1161, "Got timeout writing communication packets" }, +{ "ER_TOO_LONG_STRING", 1162, "Result string is longer than \'max_allowed_packet\' bytes" }, +{ "ER_TABLE_CANT_HANDLE_BLOB", 1163, "The used table type doesn\'t support BLOB/TEXT columns" }, +{ "ER_TABLE_CANT_HANDLE_AUTO_INCREMENT", 1164, "The used table type doesn\'t support AUTO_INCREMENT columns" }, +{ "ER_DELAYED_INSERT_TABLE_LOCKED", 1165, "INSERT DELAYED can\'t be used with table \'%-.192s\' because it is locked with LOCK TABLES" }, +{ "ER_WRONG_COLUMN_NAME", 1166, "Incorrect column name \'%-.100s\'" }, +{ "ER_WRONG_KEY_COLUMN", 1167, "The used storage engine can\'t index column \'%-.192s\'" }, +{ "ER_WRONG_MRG_TABLE", 1168, "Unable to open underlying table which is differently defined or of non-MyISAM type or doesn\'t exist" }, +{ "ER_DUP_UNIQUE", 1169, "Can\'t write, because of unique constraint, to table \'%-.192s\'" }, +{ "ER_BLOB_KEY_WITHOUT_LENGTH", 1170, "BLOB/TEXT column \'%-.192s\' used in key specification without a key length" }, +{ "ER_PRIMARY_CANT_HAVE_NULL", 1171, "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead" }, +{ "ER_TOO_MANY_ROWS", 1172, "Result consisted of more than one row" }, +{ "ER_REQUIRES_PRIMARY_KEY", 1173, "This table type requires a primary key" }, +{ "ER_NO_RAID_COMPILED", 1174, "This version of MySQL is not compiled with RAID support" }, +{ "ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE", 1175, "You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column" }, +{ "ER_KEY_DOES_NOT_EXITS", 1176, "Key \'%-.192s\' doesn\'t exist in table \'%-.192s\'" }, +{ "ER_CHECK_NO_SUCH_TABLE", 1177, "Can\'t open table" }, +{ "ER_CHECK_NOT_IMPLEMENTED", 1178, "The storage engine for the table doesn\'t support %s" }, +{ "ER_CANT_DO_THIS_DURING_AN_TRANSACTION", 1179, "You are not allowed to execute this command in a transaction" }, +{ "ER_ERROR_DURING_COMMIT", 1180, "Got error %d during COMMIT" }, +{ "ER_ERROR_DURING_ROLLBACK", 1181, "Got error %d during ROLLBACK" }, +{ "ER_ERROR_DURING_FLUSH_LOGS", 1182, "Got error %d during FLUSH_LOGS" }, +{ "ER_ERROR_DURING_CHECKPOINT", 1183, "Got error %d during CHECKPOINT" }, +{ "ER_NEW_ABORTING_CONNECTION", 1184, "Aborted connection %ld to db: \'%-.192s\' user: \'%-.48s\' host: \'%-.64s\' (%-.64s)" }, +{ "ER_DUMP_NOT_IMPLEMENTED", 1185, "The storage engine for the table does not support binary table dump" }, +{ "ER_FLUSH_MASTER_BINLOG_CLOSED", 1186, "Binlog closed, cannot RESET MASTER" }, +{ "ER_INDEX_REBUILD", 1187, "Failed rebuilding the index of dumped table \'%-.192s\'" }, +{ "ER_MASTER", 1188, "Error from master: \'%-.64s\'" }, +{ "ER_MASTER_NET_READ", 1189, "Net error reading from master" }, +{ "ER_MASTER_NET_WRITE", 1190, "Net error writing to master" }, +{ "ER_FT_MATCHING_KEY_NOT_FOUND", 1191, "Can\'t find FULLTEXT index matching the column list" }, +{ "ER_LOCK_OR_ACTIVE_TRANSACTION", 1192, "Can\'t execute the given command because you have active locked tables or an active transaction" }, +{ "ER_UNKNOWN_SYSTEM_VARIABLE", 1193, "Unknown system variable \'%-.64s\'" }, +{ "ER_CRASHED_ON_USAGE", 1194, "Table \'%-.192s\' is marked as crashed and should be repaired" }, +{ "ER_CRASHED_ON_REPAIR", 1195, "Table \'%-.192s\' is marked as crashed and last (automatic?) repair failed" }, +{ "ER_WARNING_NOT_COMPLETE_ROLLBACK", 1196, "Some non-transactional changed tables couldn\'t be rolled back" }, +{ "ER_TRANS_CACHE_FULL", 1197, "Multi-statement transaction required more than \'max_binlog_cache_size\' bytes of storage; increase this mysqld variable and try again" }, +{ "ER_SLAVE_MUST_STOP", 1198, "This operation cannot be performed with a running slave; run STOP SLAVE first" }, +{ "ER_SLAVE_NOT_RUNNING", 1199, "This operation requires a running slave; configure slave and do START SLAVE" }, +{ "ER_BAD_SLAVE", 1200, "The server is not configured as slave; fix in config file or with CHANGE MASTER TO" }, +{ "ER_MASTER_INFO", 1201, "Could not initialize master info structure; more error messages can be found in the MySQL error log" }, +{ "ER_SLAVE_THREAD", 1202, "Could not create slave thread; check system resources" }, +{ "ER_TOO_MANY_USER_CONNECTIONS", 1203, "User %-.64s already has more than \'max_user_connections\' active connections" }, +{ "ER_SET_CONSTANTS_ONLY", 1204, "You may only use constant expressions with SET" }, +{ "ER_LOCK_WAIT_TIMEOUT", 1205, "Lock wait timeout exceeded; try restarting transaction" }, +{ "ER_LOCK_TABLE_FULL", 1206, "The total number of locks exceeds the lock table size" }, +{ "ER_READ_ONLY_TRANSACTION", 1207, "Update locks cannot be acquired during a READ UNCOMMITTED transaction" }, +{ "ER_DROP_DB_WITH_READ_LOCK", 1208, "DROP DATABASE not allowed while thread is holding global read lock" }, +{ "ER_CREATE_DB_WITH_READ_LOCK", 1209, "CREATE DATABASE not allowed while thread is holding global read lock" }, +{ "ER_WRONG_ARGUMENTS", 1210, "Incorrect arguments to %s" }, +{ "ER_NO_PERMISSION_TO_CREATE_USER", 1211, "\'%-.48s\'@\'%-.64s\' is not allowed to create new users" }, +{ "ER_UNION_TABLES_IN_DIFFERENT_DIR", 1212, "Incorrect table definition; all MERGE tables must be in the same database" }, +{ "ER_LOCK_DEADLOCK", 1213, "Deadlock found when trying to get lock; try restarting transaction" }, +{ "ER_TABLE_CANT_HANDLE_FT", 1214, "The used table type doesn\'t support FULLTEXT indexes" }, +{ "ER_CANNOT_ADD_FOREIGN", 1215, "Cannot add foreign key constraint" }, +{ "ER_NO_REFERENCED_ROW", 1216, "Cannot add or update a child row: a foreign key constraint fails" }, +{ "ER_ROW_IS_REFERENCED", 1217, "Cannot delete or update a parent row: a foreign key constraint fails" }, +{ "ER_CONNECT_TO_MASTER", 1218, "Error connecting to master: %-.128s" }, +{ "ER_QUERY_ON_MASTER", 1219, "Error running query on master: %-.128s" }, +{ "ER_ERROR_WHEN_EXECUTING_COMMAND", 1220, "Error when executing command %s: %-.128s" }, +{ "ER_WRONG_USAGE", 1221, "Incorrect usage of %s and %s" }, +{ "ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT", 1222, "The used SELECT statements have a different number of columns" }, +{ "ER_CANT_UPDATE_WITH_READLOCK", 1223, "Can\'t execute the query because you have a conflicting read lock" }, +{ "ER_MIXING_NOT_ALLOWED", 1224, "Mixing of transactional and non-transactional tables is disabled" }, +{ "ER_DUP_ARGUMENT", 1225, "Option \'%s\' used twice in statement" }, +{ "ER_USER_LIMIT_REACHED", 1226, "User \'%-.64s\' has exceeded the \'%s\' resource (current value: %ld)" }, +{ "ER_SPECIFIC_ACCESS_DENIED_ERROR", 1227, "Access denied; you need (at least one of) the %-.128s privilege(s) for this operation" }, +{ "ER_LOCAL_VARIABLE", 1228, "Variable \'%-.64s\' is a SESSION variable and can\'t be used with SET GLOBAL" }, +{ "ER_GLOBAL_VARIABLE", 1229, "Variable \'%-.64s\' is a GLOBAL variable and should be set with SET GLOBAL" }, +{ "ER_NO_DEFAULT", 1230, "Variable \'%-.64s\' doesn\'t have a default value" }, +{ "ER_WRONG_VALUE_FOR_VAR", 1231, "Variable \'%-.64s\' can\'t be set to the value of \'%-.200s\'" }, +{ "ER_WRONG_TYPE_FOR_VAR", 1232, "Incorrect argument type to variable \'%-.64s\'" }, +{ "ER_VAR_CANT_BE_READ", 1233, "Variable \'%-.64s\' can only be set, not read" }, +{ "ER_CANT_USE_OPTION_HERE", 1234, "Incorrect usage/placement of \'%s\'" }, +{ "ER_NOT_SUPPORTED_YET", 1235, "This version of MySQL doesn\'t yet support \'%s\'" }, +{ "ER_MASTER_FATAL_ERROR_READING_BINLOG", 1236, "Got fatal error %d from master when reading data from binary log: \'%-.128s\'" }, +{ "ER_SLAVE_IGNORED_TABLE", 1237, "Slave SQL thread ignored the query because of replicate-*-table rules" }, +{ "ER_INCORRECT_GLOBAL_LOCAL_VAR", 1238, "Variable \'%-.192s\' is a %s variable" }, +{ "ER_WRONG_FK_DEF", 1239, "Incorrect foreign key definition for \'%-.192s\': %s" }, +{ "ER_KEY_REF_DO_NOT_MATCH_TABLE_REF", 1240, "Key reference and table reference don\'t match" }, +{ "ER_OPERAND_COLUMNS", 1241, "Operand should contain %d column(s)" }, +{ "ER_SUBQUERY_NO_1_ROW", 1242, "Subquery returns more than 1 row" }, +{ "ER_UNKNOWN_STMT_HANDLER", 1243, "Unknown prepared statement handler (%.*s) given to %s" }, +{ "ER_CORRUPT_HELP_DB", 1244, "Help database is corrupt or does not exist" }, +{ "ER_CYCLIC_REFERENCE", 1245, "Cyclic reference on subqueries" }, +{ "ER_AUTO_CONVERT", 1246, "Converting column \'%s\' from %s to %s" }, +{ "ER_ILLEGAL_REFERENCE", 1247, "Reference \'%-.64s\' not supported (%s)" }, +{ "ER_DERIVED_MUST_HAVE_ALIAS", 1248, "Every derived table must have its own alias" }, +{ "ER_SELECT_REDUCED", 1249, "Select %u was reduced during optimization" }, +{ "ER_TABLENAME_NOT_ALLOWED_HERE", 1250, "Table \'%-.192s\' from one of the SELECTs cannot be used in %-.32s" }, +{ "ER_NOT_SUPPORTED_AUTH_MODE", 1251, "Client does not support authentication protocol requested by server; consider upgrading MySQL client" }, +{ "ER_SPATIAL_CANT_HAVE_NULL", 1252, "All parts of a SPATIAL index must be NOT NULL" }, +{ "ER_COLLATION_CHARSET_MISMATCH", 1253, "COLLATION \'%s\' is not valid for CHARACTER SET \'%s\'" }, +{ "ER_SLAVE_WAS_RUNNING", 1254, "Slave is already running" }, +{ "ER_SLAVE_WAS_NOT_RUNNING", 1255, "Slave already has been stopped" }, +{ "ER_TOO_BIG_FOR_UNCOMPRESS", 1256, "Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)" }, +{ "ER_ZLIB_Z_MEM_ERROR", 1257, "ZLIB: Not enough memory" }, +{ "ER_ZLIB_Z_BUF_ERROR", 1258, "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)" }, +{ "ER_ZLIB_Z_DATA_ERROR", 1259, "ZLIB: Input data corrupted" }, +{ "ER_CUT_VALUE_GROUP_CONCAT", 1260, "Row %u was cut by GROUP_CONCAT()" }, +{ "ER_WARN_TOO_FEW_RECORDS", 1261, "Row %ld doesn\'t contain data for all columns" }, +{ "ER_WARN_TOO_MANY_RECORDS", 1262, "Row %ld was truncated; it contained more data than there were input columns" }, +{ "ER_WARN_NULL_TO_NOTNULL", 1263, "Column set to default value; NULL supplied to NOT NULL column \'%s\' at row %ld" }, +{ "ER_WARN_DATA_OUT_OF_RANGE", 1264, "Out of range value for column \'%s\' at row %ld" }, +{ "WARN_DATA_TRUNCATED", 1265, "Data truncated for column \'%s\' at row %ld" }, +{ "ER_WARN_USING_OTHER_HANDLER", 1266, "Using storage engine %s for table \'%s\'" }, +{ "ER_CANT_AGGREGATE_2COLLATIONS", 1267, "Illegal mix of collations (%s,%s) and (%s,%s) for operation \'%s\'" }, +{ "ER_DROP_USER", 1268, "Cannot drop one or more of the requested users" }, +{ "ER_REVOKE_GRANTS", 1269, "Can\'t revoke all privileges for one or more of the requested users" }, +{ "ER_CANT_AGGREGATE_3COLLATIONS", 1270, "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation \'%s\'" }, +{ "ER_CANT_AGGREGATE_NCOLLATIONS", 1271, "Illegal mix of collations for operation \'%s\'" }, +{ "ER_VARIABLE_IS_NOT_STRUCT", 1272, "Variable \'%-.64s\' is not a variable component (can\'t be used as XXXX.variable_name)" }, +{ "ER_UNKNOWN_COLLATION", 1273, "Unknown collation: \'%-.64s\'" }, +{ "ER_SLAVE_IGNORED_SSL_PARAMS", 1274, "SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started" }, +{ "ER_SERVER_IS_IN_SECURE_AUTH_MODE", 1275, "Server is running in --secure-auth mode, but \'%s\'@\'%s\' has a password in the old format; please change the password to the new format" }, +{ "ER_WARN_FIELD_RESOLVED", 1276, "Field or reference \'%-.192s%s%-.192s%s%-.192s\' of SELECT #%d was resolved in SELECT #%d" }, +{ "ER_BAD_SLAVE_UNTIL_COND", 1277, "Incorrect parameter or combination of parameters for START SLAVE UNTIL" }, +{ "ER_MISSING_SKIP_SLAVE", 1278, "It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave\'s mysqld restart" }, +{ "ER_UNTIL_COND_IGNORED", 1279, "SQL thread is not to be started so UNTIL options are ignored" }, +{ "ER_WRONG_NAME_FOR_INDEX", 1280, "Incorrect index name \'%-.100s\'" }, +{ "ER_WRONG_NAME_FOR_CATALOG", 1281, "Incorrect catalog name \'%-.100s\'" }, +{ "ER_WARN_QC_RESIZE", 1282, "Query cache failed to set size %lu; new query cache size is %lu" }, +{ "ER_BAD_FT_COLUMN", 1283, "Column \'%-.192s\' cannot be part of FULLTEXT index" }, +{ "ER_UNKNOWN_KEY_CACHE", 1284, "Unknown key cache \'%-.100s\'" }, +{ "ER_WARN_HOSTNAME_WONT_WORK", 1285, "MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work" }, +{ "ER_UNKNOWN_STORAGE_ENGINE", 1286, "Unknown storage engine \'%s\'" }, +{ "ER_WARN_DEPRECATED_SYNTAX", 1287, "\'%s\' is deprecated and will be removed in a future release. Please use %s instead" }, +{ "ER_NON_UPDATABLE_TABLE", 1288, "The target table %-.100s of the %s is not updatable" }, +{ "ER_FEATURE_DISABLED", 1289, "The \'%s\' feature is disabled; you need MySQL built with \'%s\' to have it working" }, +{ "ER_OPTION_PREVENTS_STATEMENT", 1290, "The MySQL server is running with the %s option so it cannot execute this statement" }, +{ "ER_DUPLICATED_VALUE_IN_TYPE", 1291, "Column \'%-.100s\' has duplicated value \'%-.64s\' in %s" }, +{ "ER_TRUNCATED_WRONG_VALUE", 1292, "Truncated incorrect %-.32s value: \'%-.128s\'" }, +{ "ER_TOO_MUCH_AUTO_TIMESTAMP_COLS", 1293, "Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" }, +{ "ER_INVALID_ON_UPDATE", 1294, "Invalid ON UPDATE clause for \'%-.192s\' column" }, +{ "ER_UNSUPPORTED_PS", 1295, "This command is not supported in the prepared statement protocol yet" }, +{ "ER_GET_ERRMSG", 1296, "Got error %d \'%-.100s\' from %s" }, +{ "ER_GET_TEMPORARY_ERRMSG", 1297, "Got temporary error %d \'%-.100s\' from %s" }, +{ "ER_UNKNOWN_TIME_ZONE", 1298, "Unknown or incorrect time zone: \'%-.64s\'" }, +{ "ER_WARN_INVALID_TIMESTAMP", 1299, "Invalid TIMESTAMP value in column \'%s\' at row %ld" }, +{ "ER_INVALID_CHARACTER_STRING", 1300, "Invalid %s character string: \'%.64s\'" }, +{ "ER_WARN_ALLOWED_PACKET_OVERFLOWED", 1301, "Result of %s() was larger than max_allowed_packet (%ld) - truncated" }, +{ "ER_CONFLICTING_DECLARATIONS", 1302, "Conflicting declarations: \'%s%s\' and \'%s%s\'" }, +{ "ER_SP_NO_RECURSIVE_CREATE", 1303, "Can\'t create a %s from within another stored routine" }, +{ "ER_SP_ALREADY_EXISTS", 1304, "%s %s already exists" }, +{ "ER_SP_DOES_NOT_EXIST", 1305, "%s %s does not exist" }, +{ "ER_SP_DROP_FAILED", 1306, "Failed to DROP %s %s" }, +{ "ER_SP_STORE_FAILED", 1307, "Failed to CREATE %s %s" }, +{ "ER_SP_LILABEL_MISMATCH", 1308, "%s with no matching label: %s" }, +{ "ER_SP_LABEL_REDEFINE", 1309, "Redefining label %s" }, +{ "ER_SP_LABEL_MISMATCH", 1310, "End-label %s without match" }, +{ "ER_SP_UNINIT_VAR", 1311, "Referring to uninitialized variable %s" }, +{ "ER_SP_BADSELECT", 1312, "PROCEDURE %s can\'t return a result set in the given context" }, +{ "ER_SP_BADRETURN", 1313, "RETURN is only allowed in a FUNCTION" }, +{ "ER_SP_BADSTATEMENT", 1314, "%s is not allowed in stored procedures" }, +{ "ER_UPDATE_LOG_DEPRECATED_IGNORED", 1315, "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MySQL 5.6." }, +{ "ER_UPDATE_LOG_DEPRECATED_TRANSLATED", 1316, "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MySQL 5.6." }, +{ "ER_QUERY_INTERRUPTED", 1317, "Query execution was interrupted" }, +{ "ER_SP_WRONG_NO_OF_ARGS", 1318, "Incorrect number of arguments for %s %s; expected %u, got %u" }, +{ "ER_SP_COND_MISMATCH", 1319, "Undefined CONDITION: %s" }, +{ "ER_SP_NORETURN", 1320, "No RETURN found in FUNCTION %s" }, +{ "ER_SP_NORETURNEND", 1321, "FUNCTION %s ended without RETURN" }, +{ "ER_SP_BAD_CURSOR_QUERY", 1322, "Cursor statement must be a SELECT" }, +{ "ER_SP_BAD_CURSOR_SELECT", 1323, "Cursor SELECT must not have INTO" }, +{ "ER_SP_CURSOR_MISMATCH", 1324, "Undefined CURSOR: %s" }, +{ "ER_SP_CURSOR_ALREADY_OPEN", 1325, "Cursor is already open" }, +{ "ER_SP_CURSOR_NOT_OPEN", 1326, "Cursor is not open" }, +{ "ER_SP_UNDECLARED_VAR", 1327, "Undeclared variable: %s" }, +{ "ER_SP_WRONG_NO_OF_FETCH_ARGS", 1328, "Incorrect number of FETCH variables" }, +{ "ER_SP_FETCH_NO_DATA", 1329, "No data - zero rows fetched, selected, or processed" }, +{ "ER_SP_DUP_PARAM", 1330, "Duplicate parameter: %s" }, +{ "ER_SP_DUP_VAR", 1331, "Duplicate variable: %s" }, +{ "ER_SP_DUP_COND", 1332, "Duplicate condition: %s" }, +{ "ER_SP_DUP_CURS", 1333, "Duplicate cursor: %s" }, +{ "ER_SP_CANT_ALTER", 1334, "Failed to ALTER %s %s" }, +{ "ER_SP_SUBSELECT_NYI", 1335, "Subquery value not supported" }, +{ "ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG", 1336, "%s is not allowed in stored function or trigger" }, +{ "ER_SP_VARCOND_AFTER_CURSHNDLR", 1337, "Variable or condition declaration after cursor or handler declaration" }, +{ "ER_SP_CURSOR_AFTER_HANDLER", 1338, "Cursor declaration after handler declaration" }, +{ "ER_SP_CASE_NOT_FOUND", 1339, "Case not found for CASE statement" }, +{ "ER_FPARSER_TOO_BIG_FILE", 1340, "Configuration file \'%-.192s\' is too big" }, +{ "ER_FPARSER_BAD_HEADER", 1341, "Malformed file type header in file \'%-.192s\'" }, +{ "ER_FPARSER_EOF_IN_COMMENT", 1342, "Unexpected end of file while parsing comment \'%-.200s\'" }, +{ "ER_FPARSER_ERROR_IN_PARAMETER", 1343, "Error while parsing parameter \'%-.192s\' (line: \'%-.192s\')" }, +{ "ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER", 1344, "Unexpected end of file while skipping unknown parameter \'%-.192s\'" }, +{ "ER_VIEW_NO_EXPLAIN", 1345, "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table" }, +{ "ER_FRM_UNKNOWN_TYPE", 1346, "File \'%-.192s\' has unknown type \'%-.64s\' in its header" }, +{ "ER_WRONG_OBJECT", 1347, "\'%-.192s.%-.192s\' is not %s" }, +{ "ER_NONUPDATEABLE_COLUMN", 1348, "Column \'%-.192s\' is not updatable" }, +{ "ER_VIEW_SELECT_DERIVED", 1349, "View\'s SELECT contains a subquery in the FROM clause" }, +{ "ER_VIEW_SELECT_CLAUSE", 1350, "View\'s SELECT contains a \'%s\' clause" }, +{ "ER_VIEW_SELECT_VARIABLE", 1351, "View\'s SELECT contains a variable or parameter" }, +{ "ER_VIEW_SELECT_TMPTABLE", 1352, "View\'s SELECT refers to a temporary table \'%-.192s\'" }, +{ "ER_VIEW_WRONG_LIST", 1353, "View\'s SELECT and view\'s field list have different column counts" }, +{ "ER_WARN_VIEW_MERGE", 1354, "View merge algorithm can\'t be used here for now (assumed undefined algorithm)" }, +{ "ER_WARN_VIEW_WITHOUT_KEY", 1355, "View being updated does not have complete key of underlying table in it" }, +{ "ER_VIEW_INVALID", 1356, "View \'%-.192s.%-.192s\' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them" }, +{ "ER_SP_NO_DROP_SP", 1357, "Can\'t drop or alter a %s from within another stored routine" }, +{ "ER_SP_GOTO_IN_HNDLR", 1358, "GOTO is not allowed in a stored procedure handler" }, +{ "ER_TRG_ALREADY_EXISTS", 1359, "Trigger already exists" }, +{ "ER_TRG_DOES_NOT_EXIST", 1360, "Trigger does not exist" }, +{ "ER_TRG_ON_VIEW_OR_TEMP_TABLE", 1361, "Trigger\'s \'%-.192s\' is view or temporary table" }, +{ "ER_TRG_CANT_CHANGE_ROW", 1362, "Updating of %s row is not allowed in %strigger" }, +{ "ER_TRG_NO_SUCH_ROW_IN_TRG", 1363, "There is no %s row in %s trigger" }, +{ "ER_NO_DEFAULT_FOR_FIELD", 1364, "Field \'%-.192s\' doesn\'t have a default value" }, +{ "ER_DIVISION_BY_ZERO", 1365, "Division by 0" }, +{ "ER_TRUNCATED_WRONG_VALUE_FOR_FIELD", 1366, "Incorrect %-.32s value: \'%-.128s\' for column \'%.192s\' at row %ld" }, +{ "ER_ILLEGAL_VALUE_FOR_TYPE", 1367, "Illegal %s \'%-.192s\' value found during parsing" }, +{ "ER_VIEW_NONUPD_CHECK", 1368, "CHECK OPTION on non-updatable view \'%-.192s.%-.192s\'" }, +{ "ER_VIEW_CHECK_FAILED", 1369, "CHECK OPTION failed \'%-.192s.%-.192s\'" }, +{ "ER_PROCACCESS_DENIED_ERROR", 1370, "%-.16s command denied to user \'%-.48s\'@\'%-.64s\' for routine \'%-.192s\'" }, +{ "ER_RELAY_LOG_FAIL", 1371, "Failed purging old relay logs: %s" }, +{ "ER_PASSWD_LENGTH", 1372, "Password hash should be a %d-digit hexadecimal number" }, +{ "ER_UNKNOWN_TARGET_BINLOG", 1373, "Target log not found in binlog index" }, +{ "ER_IO_ERR_LOG_INDEX_READ", 1374, "I/O error reading log index file" }, +{ "ER_BINLOG_PURGE_PROHIBITED", 1375, "Server configuration does not permit binlog purge" }, +{ "ER_FSEEK_FAIL", 1376, "Failed on fseek()" }, +{ "ER_BINLOG_PURGE_FATAL_ERR", 1377, "Fatal error during log purge" }, +{ "ER_LOG_IN_USE", 1378, "A purgeable log is in use, will not purge" }, +{ "ER_LOG_PURGE_UNKNOWN_ERR", 1379, "Unknown error during log purge" }, +{ "ER_RELAY_LOG_INIT", 1380, "Failed initializing relay log position: %s" }, +{ "ER_NO_BINARY_LOGGING", 1381, "You are not using binary logging" }, +{ "ER_RESERVED_SYNTAX", 1382, "The \'%-.64s\' syntax is reserved for purposes internal to the MySQL server" }, +{ "ER_WSAS_FAILED", 1383, "WSAStartup Failed" }, +{ "ER_DIFF_GROUPS_PROC", 1384, "Can\'t handle procedures with different groups yet" }, +{ "ER_NO_GROUP_FOR_PROC", 1385, "Select must have a group with this procedure" }, +{ "ER_ORDER_WITH_PROC", 1386, "Can\'t use ORDER clause with this procedure" }, +{ "ER_LOGGING_PROHIBIT_CHANGING_OF", 1387, "Binary logging and replication forbid changing the global server %s" }, +{ "ER_NO_FILE_MAPPING", 1388, "Can\'t map file: %-.200s, errno: %d" }, +{ "ER_WRONG_MAGIC", 1389, "Wrong magic in %-.64s" }, +{ "ER_PS_MANY_PARAM", 1390, "Prepared statement contains too many placeholders" }, +{ "ER_KEY_PART_0", 1391, "Key part \'%-.192s\' length cannot be 0" }, +{ "ER_VIEW_CHECKSUM", 1392, "View text checksum failed" }, +{ "ER_VIEW_MULTIUPDATE", 1393, "Can not modify more than one base table through a join view \'%-.192s.%-.192s\'" }, +{ "ER_VIEW_NO_INSERT_FIELD_LIST", 1394, "Can not insert into join view \'%-.192s.%-.192s\' without fields list" }, +{ "ER_VIEW_DELETE_MERGE_VIEW", 1395, "Can not delete from join view \'%-.192s.%-.192s\'" }, +{ "ER_CANNOT_USER", 1396, "Operation %s failed for %.256s" }, +{ "ER_XAER_NOTA", 1397, "XAER_NOTA: Unknown XID" }, +{ "ER_XAER_INVAL", 1398, "XAER_INVAL: Invalid arguments (or unsupported command)" }, +{ "ER_XAER_RMFAIL", 1399, "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state" }, +{ "ER_XAER_OUTSIDE", 1400, "XAER_OUTSIDE: Some work is done outside global transaction" }, +{ "ER_XAER_RMERR", 1401, "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency" }, +{ "ER_XA_RBROLLBACK", 1402, "XA_RBROLLBACK: Transaction branch was rolled back" }, +{ "ER_NONEXISTING_PROC_GRANT", 1403, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\' on routine \'%-.192s\'" }, +{ "ER_PROC_AUTO_GRANT_FAIL", 1404, "Failed to grant EXECUTE and ALTER ROUTINE privileges" }, +{ "ER_PROC_AUTO_REVOKE_FAIL", 1405, "Failed to revoke all privileges to dropped routine" }, +{ "ER_DATA_TOO_LONG", 1406, "Data too long for column \'%s\' at row %ld" }, +{ "ER_SP_BAD_SQLSTATE", 1407, "Bad SQLSTATE: \'%s\'" }, +{ "ER_STARTUP", 1408, "%s: ready for connections.\nVersion: \'%s\' socket: \'%s\' port: %d %s" }, +{ "ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR", 1409, "Can\'t load value from file with fixed size rows to variable" }, +{ "ER_CANT_CREATE_USER_WITH_GRANT", 1410, "You are not allowed to create a user with GRANT" }, +{ "ER_WRONG_VALUE_FOR_TYPE", 1411, "Incorrect %-.32s value: \'%-.128s\' for function %-.32s" }, +{ "ER_TABLE_DEF_CHANGED", 1412, "Table definition has changed, please retry transaction" }, +{ "ER_SP_DUP_HANDLER", 1413, "Duplicate handler declared in the same block" }, +{ "ER_SP_NOT_VAR_ARG", 1414, "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger" }, +{ "ER_SP_NO_RETSET", 1415, "Not allowed to return a result set from a %s" }, +{ "ER_CANT_CREATE_GEOMETRY_OBJECT", 1416, "Cannot get geometry object from data you send to the GEOMETRY field" }, +{ "ER_FAILED_ROUTINE_BREAK_BINLOG", 1417, "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes" }, +{ "ER_BINLOG_UNSAFE_ROUTINE", 1418, "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" }, +{ "ER_BINLOG_CREATE_ROUTINE_NEED_SUPER", 1419, "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" }, +{ "ER_EXEC_STMT_WITH_OPEN_CURSOR", 1420, "You can\'t execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it." }, +{ "ER_STMT_HAS_NO_OPEN_CURSOR", 1421, "The statement (%lu) has no open cursor." }, +{ "ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG", 1422, "Explicit or implicit commit is not allowed in stored function or trigger." }, +{ "ER_NO_DEFAULT_FOR_VIEW_FIELD", 1423, "Field of view \'%-.192s.%-.192s\' underlying table doesn\'t have a default value" }, +{ "ER_SP_NO_RECURSION", 1424, "Recursive stored functions and triggers are not allowed." }, +{ "ER_TOO_BIG_SCALE", 1425, "Too big scale %d specified for column \'%-.192s\'. Maximum is %lu." }, +{ "ER_TOO_BIG_PRECISION", 1426, "Too big precision %d specified for column \'%-.192s\'. Maximum is %lu." }, +{ "ER_M_BIGGER_THAN_D", 1427, "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column \'%-.192s\')." }, +{ "ER_WRONG_LOCK_OF_SYSTEM_TABLE", 1428, "You can\'t combine write-locking of system tables with other tables or lock types" }, +{ "ER_CONNECT_TO_FOREIGN_DATA_SOURCE", 1429, "Unable to connect to foreign data source: %.64s" }, +{ "ER_QUERY_ON_FOREIGN_DATA_SOURCE", 1430, "There was a problem processing the query on the foreign data source. Data source error: %-.64s" }, +{ "ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST", 1431, "The foreign data source you are trying to reference does not exist. Data source error: %-.64s" }, +{ "ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE", 1432, "Can\'t create federated table. The data source connection string \'%-.64s\' is not in the correct format" }, +{ "ER_FOREIGN_DATA_STRING_INVALID", 1433, "The data source connection string \'%-.64s\' is not in the correct format" }, +{ "ER_CANT_CREATE_FEDERATED_TABLE", 1434, "Can\'t create federated table. Foreign data src error: %-.64s" }, +{ "ER_TRG_IN_WRONG_SCHEMA", 1435, "Trigger in wrong schema" }, +{ "ER_STACK_OVERRUN_NEED_MORE", 1436, "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use \'mysqld --thread_stack=#\' to specify a bigger stack." }, +{ "ER_TOO_LONG_BODY", 1437, "Routine body for \'%-.100s\' is too long" }, +{ "ER_WARN_CANT_DROP_DEFAULT_KEYCACHE", 1438, "Cannot drop default keycache" }, +{ "ER_TOO_BIG_DISPLAYWIDTH", 1439, "Display width out of range for column \'%-.192s\' (max = %lu)" }, +{ "ER_XAER_DUPID", 1440, "XAER_DUPID: The XID already exists" }, +{ "ER_DATETIME_FUNCTION_OVERFLOW", 1441, "Datetime function: %-.32s field overflow" }, +{ "ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG", 1442, "Can\'t update table \'%-.192s\' in stored function/trigger because it is already used by statement which invoked this stored function/trigger." }, +{ "ER_VIEW_PREVENT_UPDATE", 1443, "The definition of table \'%-.192s\' prevents operation %.192s on table \'%-.192s\'." }, +{ "ER_PS_NO_RECURSION", 1444, "The prepared statement contains a stored routine call that refers to that same statement. It\'s not allowed to execute a prepared statement in such a recursive manner" }, +{ "ER_SP_CANT_SET_AUTOCOMMIT", 1445, "Not allowed to set autocommit from a stored function or trigger" }, +{ "ER_MALFORMED_DEFINER", 1446, "Definer is not fully qualified" }, +{ "ER_VIEW_FRM_NO_USER", 1447, "View \'%-.192s\'.\'%-.192s\' has no definer information (old table format). Current user is used as definer. Please recreate the view!" }, +{ "ER_VIEW_OTHER_USER", 1448, "You need the SUPER privilege for creation view with \'%-.192s\'@\'%-.192s\' definer" }, +{ "ER_NO_SUCH_USER", 1449, "The user specified as a definer (\'%-.64s\'@\'%-.64s\') does not exist" }, +{ "ER_FORBID_SCHEMA_CHANGE", 1450, "Changing schema from \'%-.192s\' to \'%-.192s\' is not allowed." }, +{ "ER_ROW_IS_REFERENCED_2", 1451, "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)" }, +{ "ER_NO_REFERENCED_ROW_2", 1452, "Cannot add or update a child row: a foreign key constraint fails (%.192s)" }, +{ "ER_SP_BAD_VAR_SHADOW", 1453, "Variable \'%-.64s\' must be quoted with `...`, or renamed" }, +{ "ER_TRG_NO_DEFINER", 1454, "No definer attribute for trigger \'%-.192s\'.\'%-.192s\'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger." }, +{ "ER_OLD_FILE_FORMAT", 1455, "\'%-.192s\' has an old format, you should re-create the \'%s\' object(s)" }, +{ "ER_SP_RECURSION_LIMIT", 1456, "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s" }, +{ "ER_SP_PROC_TABLE_CORRUPT", 1457, "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)" }, +{ "ER_SP_WRONG_NAME", 1458, "Incorrect routine name \'%-.192s\'" }, +{ "ER_TABLE_NEEDS_UPGRADE", 1459, "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" or dump/reload to fix it!" }, +{ "ER_SP_NO_AGGREGATE", 1460, "AGGREGATE is not supported for stored functions" }, +{ "ER_MAX_PREPARED_STMT_COUNT_REACHED", 1461, "Can\'t create more than max_prepared_stmt_count statements (current value: %lu)" }, +{ "ER_VIEW_RECURSIVE", 1462, "`%-.192s`.`%-.192s` contains view recursion" }, +{ "ER_NON_GROUPING_FIELD_USED", 1463, "non-grouping field \'%-.192s\' is used in %-.64s clause" }, +{ "ER_TABLE_CANT_HANDLE_SPKEYS", 1464, "The used table type doesn\'t support SPATIAL indexes" }, +{ "ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA", 1465, "Triggers can not be created on system tables" }, +{ "ER_REMOVED_SPACES", 1466, "Leading spaces are removed from name \'%s\'" }, +{ "ER_AUTOINC_READ_FAILED", 1467, "Failed to read auto-increment value from storage engine" }, +{ "ER_USERNAME", 1468, "user name" }, +{ "ER_HOSTNAME", 1469, "host name" }, +{ "ER_WRONG_STRING_LENGTH", 1470, "String \'%-.70s\' is too long for %s (should be no longer than %d)" }, +{ "ER_NON_INSERTABLE_TABLE", 1471, "The target table %-.100s of the %s is not insertable-into" }, +{ "ER_ADMIN_WRONG_MRG_TABLE", 1472, "Table \'%-.64s\' is differently defined or of non-MyISAM type or doesn\'t exist" }, +{ "ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT", 1473, "Too high level of nesting for select" }, +{ "ER_NAME_BECOMES_EMPTY", 1474, "Name \'%-.64s\' has become \'\'" }, +{ "ER_AMBIGUOUS_FIELD_TERM", 1475, "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" }, +{ "ER_FOREIGN_SERVER_EXISTS", 1476, "The foreign server, %s, you are trying to create already exists." }, +{ "ER_FOREIGN_SERVER_DOESNT_EXIST", 1477, "The foreign server name you are trying to reference does not exist. Data source error: %-.64s" }, +{ "ER_ILLEGAL_HA_CREATE_OPTION", 1478, "Table storage engine \'%-.64s\' does not support the create option \'%.64s\'" }, +{ "ER_PARTITION_REQUIRES_VALUES_ERROR", 1479, "Syntax error: %-.64s PARTITIONING requires definition of VALUES %-.64s for each partition" }, +{ "ER_PARTITION_WRONG_VALUES_ERROR", 1480, "Only %-.64s PARTITIONING can use VALUES %-.64s in partition definition" }, +{ "ER_PARTITION_MAXVALUE_ERROR", 1481, "MAXVALUE can only be used in last partition definition" }, +{ "ER_PARTITION_SUBPARTITION_ERROR", 1482, "Subpartitions can only be hash partitions and by key" }, +{ "ER_PARTITION_SUBPART_MIX_ERROR", 1483, "Must define subpartitions on all partitions if on one partition" }, +{ "ER_PARTITION_WRONG_NO_PART_ERROR", 1484, "Wrong number of partitions defined, mismatch with previous setting" }, +{ "ER_PARTITION_WRONG_NO_SUBPART_ERROR", 1485, "Wrong number of subpartitions defined, mismatch with previous setting" }, +{ "ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR", 1486, "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed" }, +{ "ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR", 1487, "Expression in RANGE/LIST VALUES must be constant" }, +{ "ER_FIELD_NOT_FOUND_PART_ERROR", 1488, "Field in list of fields for partition function not found in table" }, +{ "ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR", 1489, "List of fields is only allowed in KEY partitions" }, +{ "ER_INCONSISTENT_PARTITION_INFO_ERROR", 1490, "The partition info in the frm file is not consistent with what can be written into the frm file" }, +{ "ER_PARTITION_FUNC_NOT_ALLOWED_ERROR", 1491, "The %-.192s function returns the wrong type" }, +{ "ER_PARTITIONS_MUST_BE_DEFINED_ERROR", 1492, "For %-.64s partitions each partition must be defined" }, +{ "ER_RANGE_NOT_INCREASING_ERROR", 1493, "VALUES LESS THAN value must be strictly increasing for each partition" }, +{ "ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR", 1494, "VALUES value must be of same type as partition function" }, +{ "ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR", 1495, "Multiple definition of same constant in list partitioning" }, +{ "ER_PARTITION_ENTRY_ERROR", 1496, "Partitioning can not be used stand-alone in query" }, +{ "ER_MIX_HANDLER_ERROR", 1497, "The mix of handlers in the partitions is not allowed in this version of MySQL" }, +{ "ER_PARTITION_NOT_DEFINED_ERROR", 1498, "For the partitioned engine it is necessary to define all %-.64s" }, +{ "ER_TOO_MANY_PARTITIONS_ERROR", 1499, "Too many partitions (including subpartitions) were defined" }, +{ "ER_SUBPARTITION_ERROR", 1500, "It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning" }, +{ "ER_CANT_CREATE_HANDLER_FILE", 1501, "Failed to create specific handler file" }, +{ "ER_BLOB_FIELD_IN_PART_FUNC_ERROR", 1502, "A BLOB field is not allowed in partition function" }, +{ "ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF", 1503, "A %-.192s must include all columns in the table\'s partitioning function" }, +{ "ER_NO_PARTS_ERROR", 1504, "Number of %-.64s = 0 is not an allowed value" }, +{ "ER_PARTITION_MGMT_ON_NONPARTITIONED", 1505, "Partition management on a not partitioned table is not possible" }, +{ "ER_FOREIGN_KEY_ON_PARTITIONED", 1506, "Foreign key clause is not yet supported in conjunction with partitioning" }, +{ "ER_DROP_PARTITION_NON_EXISTENT", 1507, "Error in list of partitions to %-.64s" }, +{ "ER_DROP_LAST_PARTITION", 1508, "Cannot remove all partitions, use DROP TABLE instead" }, +{ "ER_COALESCE_ONLY_ON_HASH_PARTITION", 1509, "COALESCE PARTITION can only be used on HASH/KEY partitions" }, +{ "ER_REORG_HASH_ONLY_ON_SAME_NO", 1510, "REORGANIZE PARTITION can only be used to reorganize partitions not to change their numbers" }, +{ "ER_REORG_NO_PARAM_ERROR", 1511, "REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH PARTITIONs" }, +{ "ER_ONLY_ON_RANGE_LIST_PARTITION", 1512, "%-.64s PARTITION can only be used on RANGE/LIST partitions" }, +{ "ER_ADD_PARTITION_SUBPART_ERROR", 1513, "Trying to Add partition(s) with wrong number of subpartitions" }, +{ "ER_ADD_PARTITION_NO_NEW_PARTITION", 1514, "At least one partition must be added" }, +{ "ER_COALESCE_PARTITION_NO_PARTITION", 1515, "At least one partition must be coalesced" }, +{ "ER_REORG_PARTITION_NOT_EXIST", 1516, "More partitions to reorganize than there are partitions" }, +{ "ER_SAME_NAME_PARTITION", 1517, "Duplicate partition name %-.192s" }, +{ "ER_NO_BINLOG_ERROR", 1518, "It is not allowed to shut off binlog on this command" }, +{ "ER_CONSECUTIVE_REORG_PARTITIONS", 1519, "When reorganizing a set of partitions they must be in consecutive order" }, +{ "ER_REORG_OUTSIDE_RANGE", 1520, "Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range" }, +{ "ER_PARTITION_FUNCTION_FAILURE", 1521, "Partition function not supported in this version for this handler" }, +{ "ER_PART_STATE_ERROR", 1522, "Partition state cannot be defined from CREATE/ALTER TABLE" }, +{ "ER_LIMITED_PART_RANGE", 1523, "The %-.64s handler only supports 32 bit integers in VALUES" }, +{ "ER_PLUGIN_IS_NOT_LOADED", 1524, "Plugin \'%-.192s\' is not loaded" }, +{ "ER_WRONG_VALUE", 1525, "Incorrect %-.32s value: \'%-.128s\'" }, +{ "ER_NO_PARTITION_FOR_GIVEN_VALUE", 1526, "Table has no partition for value %-.64s" }, +{ "ER_FILEGROUP_OPTION_ONLY_ONCE", 1527, "It is not allowed to specify %s more than once" }, +{ "ER_CREATE_FILEGROUP_FAILED", 1528, "Failed to create %s" }, +{ "ER_DROP_FILEGROUP_FAILED", 1529, "Failed to drop %s" }, +{ "ER_TABLESPACE_AUTO_EXTEND_ERROR", 1530, "The handler doesn\'t support autoextend of tablespaces" }, +{ "ER_WRONG_SIZE_NUMBER", 1531, "A size parameter was incorrectly specified, either number or on the form 10M" }, +{ "ER_SIZE_OVERFLOW_ERROR", 1532, "The size number was correct but we don\'t allow the digit part to be more than 2 billion" }, +{ "ER_ALTER_FILEGROUP_FAILED", 1533, "Failed to alter: %s" }, +{ "ER_BINLOG_ROW_LOGGING_FAILED", 1534, "Writing one row to the row-based binary log failed" }, +{ "ER_BINLOG_ROW_WRONG_TABLE_DEF", 1535, "Table definition on master and slave does not match: %s" }, +{ "ER_BINLOG_ROW_RBR_TO_SBR", 1536, "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events" }, +{ "ER_EVENT_ALREADY_EXISTS", 1537, "Event \'%-.192s\' already exists" }, +{ "ER_EVENT_STORE_FAILED", 1538, "Failed to store event %s. Error code %d from storage engine." }, +{ "ER_EVENT_DOES_NOT_EXIST", 1539, "Unknown event \'%-.192s\'" }, +{ "ER_EVENT_CANT_ALTER", 1540, "Failed to alter event \'%-.192s\'" }, +{ "ER_EVENT_DROP_FAILED", 1541, "Failed to drop %s" }, +{ "ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG", 1542, "INTERVAL is either not positive or too big" }, +{ "ER_EVENT_ENDS_BEFORE_STARTS", 1543, "ENDS is either invalid or before STARTS" }, +{ "ER_EVENT_EXEC_TIME_IN_THE_PAST", 1544, "Event execution time is in the past. Event has been disabled" }, +{ "ER_EVENT_OPEN_TABLE_FAILED", 1545, "Failed to open mysql.event" }, +{ "ER_EVENT_NEITHER_M_EXPR_NOR_M_AT", 1546, "No datetime expression provided" }, +{ "ER_COL_COUNT_DOESNT_MATCH_CORRUPTED", 1547, "Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted" }, +{ "ER_CANNOT_LOAD_FROM_TABLE", 1548, "Cannot load from mysql.%s. The table is probably corrupted" }, +{ "ER_EVENT_CANNOT_DELETE", 1549, "Failed to delete the event from mysql.event" }, +{ "ER_EVENT_COMPILE_ERROR", 1550, "Error during compilation of event\'s body" }, +{ "ER_EVENT_SAME_NAME", 1551, "Same old and new event name" }, +{ "ER_EVENT_DATA_TOO_LONG", 1552, "Data for column \'%s\' too long" }, +{ "ER_DROP_INDEX_FK", 1553, "Cannot drop index \'%-.192s\': needed in a foreign key constraint" }, +{ "ER_WARN_DEPRECATED_SYNTAX_WITH_VER", 1554, "The syntax \'%s\' is deprecated and will be removed in MySQL %s. Please use %s instead" }, +{ "ER_CANT_WRITE_LOCK_LOG_TABLE", 1555, "You can\'t write-lock a log table. Only read access is possible" }, +{ "ER_CANT_LOCK_LOG_TABLE", 1556, "You can\'t use locks with log tables." }, +{ "ER_FOREIGN_DUPLICATE_KEY", 1557, "Upholding foreign key constraints for table \'%.192s\', entry \'%-.192s\', key %d would lead to a duplicate entry" }, +{ "ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE", 1558, "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error." }, +{ "ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR", 1559, "Cannot switch out of the row-based binary log format when the session has open temporary tables" }, +{ "ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT", 1560, "Cannot change the binary logging format inside a stored function or trigger" }, +{ "ER_NDB_CANT_SWITCH_BINLOG_FORMAT", 1561, "The NDB cluster engine does not support changing the binlog format on the fly yet" }, +{ "ER_PARTITION_NO_TEMPORARY", 1562, "Cannot create temporary table with partitions" }, +{ "ER_PARTITION_CONST_DOMAIN_ERROR", 1563, "Partition constant is out of partition function domain" }, +{ "ER_PARTITION_FUNCTION_IS_NOT_ALLOWED", 1564, "This partition function is not allowed" }, +{ "ER_DDL_LOG_ERROR", 1565, "Error in DDL log" }, +{ "ER_NULL_IN_VALUES_LESS_THAN", 1566, "Not allowed to use NULL value in VALUES LESS THAN" }, +{ "ER_WRONG_PARTITION_NAME", 1567, "Incorrect partition name" }, +{ "ER_CANT_CHANGE_TX_ISOLATION", 1568, "Transaction isolation level can\'t be changed while a transaction is in progress" }, +{ "ER_DUP_ENTRY_AUTOINCREMENT_CASE", 1569, "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry \'%-.192s\' for key \'%-.192s\'" }, +{ "ER_EVENT_MODIFY_QUEUE_ERROR", 1570, "Internal scheduler error %d" }, +{ "ER_EVENT_SET_VAR_ERROR", 1571, "Error during starting/stopping of the scheduler. Error code %u" }, +{ "ER_PARTITION_MERGE_ERROR", 1572, "Engine cannot be used in partitioned tables" }, +{ "ER_CANT_ACTIVATE_LOG", 1573, "Cannot activate \'%-.64s\' log" }, +{ "ER_RBR_NOT_AVAILABLE", 1574, "The server was not built with row-based replication" }, +{ "ER_BASE64_DECODE_ERROR", 1575, "Decoding of base64 string failed" }, +{ "ER_EVENT_RECURSION_FORBIDDEN", 1576, "Recursion of EVENT DDL statements is forbidden when body is present" }, +{ "ER_EVENTS_DB_ERROR", 1577, "Cannot proceed because system tables used by Event Scheduler were found damaged at server start" }, +{ "ER_ONLY_INTEGERS_ALLOWED", 1578, "Only integers allowed as number here" }, +{ "ER_UNSUPORTED_LOG_ENGINE", 1579, "This storage engine cannot be used for log tables\"" }, +{ "ER_BAD_LOG_STATEMENT", 1580, "You cannot \'%s\' a log table if logging is enabled" }, +{ "ER_CANT_RENAME_LOG_TABLE", 1581, "Cannot rename \'%s\'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to \'%s\'" }, +{ "ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT", 1582, "Incorrect parameter count in the call to native function \'%-.192s\'" }, +{ "ER_WRONG_PARAMETERS_TO_NATIVE_FCT", 1583, "Incorrect parameters in the call to native function \'%-.192s\'" }, +{ "ER_WRONG_PARAMETERS_TO_STORED_FCT", 1584, "Incorrect parameters in the call to stored function \'%-.192s\'" }, +{ "ER_NATIVE_FCT_NAME_COLLISION", 1585, "This function \'%-.192s\' has the same name as a native function" }, +{ "ER_DUP_ENTRY_WITH_KEY_NAME", 1586, "Duplicate entry \'%-.64s\' for key \'%-.192s\'" }, +{ "ER_BINLOG_PURGE_EMFILE", 1587, "Too many files opened, please execute the command again" }, +{ "ER_EVENT_CANNOT_CREATE_IN_THE_PAST", 1588, "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." }, +{ "ER_EVENT_CANNOT_ALTER_IN_THE_PAST", 1589, "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." }, +{ "ER_SLAVE_INCIDENT", 1590, "The incident %s occured on the master. Message: %-.64s" }, +{ "ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT", 1591, "Table has no partition for some existing values" }, +{ "ER_BINLOG_UNSAFE_STATEMENT", 1592, "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s" }, +{ "ER_SLAVE_FATAL_ERROR", 1593, "Fatal error: %s" }, +{ "ER_SLAVE_RELAY_LOG_READ_FAILURE", 1594, "Relay log read failure: %s" }, +{ "ER_SLAVE_RELAY_LOG_WRITE_FAILURE", 1595, "Relay log write failure: %s" }, +{ "ER_SLAVE_CREATE_EVENT_FAILURE", 1596, "Failed to create %s" }, +{ "ER_SLAVE_MASTER_COM_FAILURE", 1597, "Master command %s failed: %s" }, +{ "ER_BINLOG_LOGGING_IMPOSSIBLE", 1598, "Binary logging not possible. Message: %s" }, +{ "ER_VIEW_NO_CREATION_CTX", 1599, "View `%-.64s`.`%-.64s` has no creation context" }, +{ "ER_VIEW_INVALID_CREATION_CTX", 1600, "Creation context of view `%-.64s`.`%-.64s\' is invalid" }, +{ "ER_SR_INVALID_CREATION_CTX", 1601, "Creation context of stored routine `%-.64s`.`%-.64s` is invalid" }, +{ "ER_TRG_CORRUPTED_FILE", 1602, "Corrupted TRG file for table `%-.64s`.`%-.64s`" }, +{ "ER_TRG_NO_CREATION_CTX", 1603, "Triggers for table `%-.64s`.`%-.64s` have no creation context" }, +{ "ER_TRG_INVALID_CREATION_CTX", 1604, "Trigger creation context of table `%-.64s`.`%-.64s` is invalid" }, +{ "ER_EVENT_INVALID_CREATION_CTX", 1605, "Creation context of event `%-.64s`.`%-.64s` is invalid" }, +{ "ER_TRG_CANT_OPEN_TABLE", 1606, "Cannot open table for trigger `%-.64s`.`%-.64s`" }, +{ "ER_CANT_CREATE_SROUTINE", 1607, "Cannot create stored routine `%-.64s`. Check warnings" }, +{ "ER_NEVER_USED", 1608, "Ambiguous slave modes combination. %s" }, +{ "ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT", 1609, "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement." }, +{ "ER_SLAVE_CORRUPT_EVENT", 1610, "Corrupted replication event was detected" }, +{ "ER_LOAD_DATA_INVALID_COLUMN", 1611, "Invalid column reference (%-.64s) in LOAD DATA" }, +{ "ER_LOG_PURGE_NO_FILE", 1612, "Being purged log %s was not found" }, +{ "ER_XA_RBTIMEOUT", 1613, "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" }, +{ "ER_XA_RBDEADLOCK", 1614, "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" }, +{ "ER_NEED_REPREPARE", 1615, "Prepared statement needs to be re-prepared" }, +{ "ER_DELAYED_NOT_SUPPORTED", 1616, "DELAYED option not supported for table \'%-.192s\'" }, +{ "WARN_NO_MASTER_INFO", 1617, "The master info structure does not exist" }, +{ "WARN_OPTION_IGNORED", 1618, "<%-.64s> option ignored" }, +{ "WARN_PLUGIN_DELETE_BUILTIN", 1619, "Built-in plugins cannot be deleted" }, +{ "WARN_PLUGIN_BUSY", 1620, "Plugin is busy and will be uninstalled on shutdown" }, +{ "ER_VARIABLE_IS_READONLY", 1621, "%s variable \'%s\' is read-only. Use SET %s to assign the value" }, +{ "ER_WARN_ENGINE_TRANSACTION_ROLLBACK", 1622, "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted" }, +{ "ER_SLAVE_HEARTBEAT_FAILURE", 1623, "Unexpected master\'s heartbeat data: %s" }, +{ "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE", 1624, "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds)." }, +{ "ER_NDB_REPLICATION_SCHEMA_ERROR", 1625, "Bad schema for mysql.ndb_replication table. Message: %-.64s" }, +{ "ER_CONFLICT_FN_PARSE_ERROR", 1626, "Error in parsing conflict function. Message: %-.64s" }, +{ "ER_EXCEPTIONS_WRITE_ERROR", 1627, "Write to exceptions table failed. Message: %-.128s\"" }, +{ "ER_TOO_LONG_TABLE_COMMENT", 1628, "Comment for table \'%-.64s\' is too long (max = %lu)" }, +{ "ER_TOO_LONG_FIELD_COMMENT", 1629, "Comment for field \'%-.64s\' is too long (max = %lu)" }, +{ "ER_FUNC_INEXISTENT_NAME_COLLISION", 1630, "FUNCTION %s does not exist. Check the \'Function Name Parsing and Resolution\' section in the Reference Manual" }, +{ "ER_DATABASE_NAME", 1631, "Database" }, +{ "ER_TABLE_NAME", 1632, "Table" }, +{ "ER_PARTITION_NAME", 1633, "Partition" }, +{ "ER_SUBPARTITION_NAME", 1634, "Subpartition" }, +{ "ER_TEMPORARY_NAME", 1635, "Temporary" }, +{ "ER_RENAMED_NAME", 1636, "Renamed" }, +{ "ER_TOO_MANY_CONCURRENT_TRXS", 1637, "Too many active concurrent transactions" }, +{ "WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED", 1638, "Non-ASCII separator arguments are not fully supported" }, +{ "ER_DEBUG_SYNC_TIMEOUT", 1639, "debug sync point wait timed out" }, +{ "ER_DEBUG_SYNC_HIT_LIMIT", 1640, "debug sync point hit limit reached" }, +{ "ER_DUP_SIGNAL_SET", 1641, "Duplicate condition information item \'%s\'" }, +{ "ER_SIGNAL_WARN", 1642, "Unhandled user-defined warning condition" }, +{ "ER_SIGNAL_NOT_FOUND", 1643, "Unhandled user-defined not found condition" }, +{ "ER_SIGNAL_EXCEPTION", 1644, "Unhandled user-defined exception condition" }, +{ "ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER", 1645, "RESIGNAL when handler not active" }, +{ "ER_SIGNAL_BAD_CONDITION_TYPE", 1646, "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE" }, +{ "WARN_COND_ITEM_TRUNCATED", 1647, "Data truncated for condition item \'%s\'" }, +{ "ER_COND_ITEM_TOO_LONG", 1648, "Data too long for condition item \'%s\'" }, +{ "ER_UNKNOWN_LOCALE", 1649, "Unknown locale: \'%-.64s\'" }, +{ "ER_SLAVE_IGNORE_SERVER_IDS", 1650, "The requested server id %d clashes with the slave startup option --replicate-same-server-id" }, +{ "ER_QUERY_CACHE_DISABLED", 1651, "Query cache is disabled; restart the server with query_cache_type=1 to enable it" }, +{ "ER_SAME_NAME_PARTITION_FIELD", 1652, "Duplicate partition field name \'%-.192s\'" }, +{ "ER_PARTITION_COLUMN_LIST_ERROR", 1653, "Inconsistency in usage of column lists for partitioning" }, +{ "ER_WRONG_TYPE_COLUMN_VALUE_ERROR", 1654, "Partition column values of incorrect type" }, +{ "ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR", 1655, "Too many fields in \'%-.192s\'" }, +{ "ER_MAXVALUE_IN_VALUES_IN", 1656, "Cannot use MAXVALUE as value in VALUES IN" }, +{ "ER_TOO_MANY_VALUES_ERROR", 1657, "Cannot have more than one value for this type of %-.64s partitioning" }, +{ "ER_ROW_SINGLE_PARTITION_FIELD_ERROR", 1658, "Row expressions in VALUES IN only allowed for multi-field column partitioning" }, +{ "ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD", 1659, "Field \'%-.192s\' is of a not allowed type for this type of partitioning" }, +{ "ER_PARTITION_FIELDS_TOO_LONG", 1660, "The total length of the partitioning fields is too large" }, +{ "ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE", 1661, "Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved." }, +{ "ER_BINLOG_ROW_MODE_AND_STMT_ENGINE", 1662, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging." }, +{ "ER_BINLOG_UNSAFE_AND_STMT_ENGINE", 1663, "Cannot execute statement: impossible to write to binary log since statement is unsafe, storage engine is limited to statement-based logging, and BINLOG_FORMAT = MIXED. %s" }, +{ "ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE", 1664, "Cannot execute statement: impossible to write to binary log since statement is in row format and at least one table uses a storage engine limited to statement-based logging." }, +{ "ER_BINLOG_STMT_MODE_AND_ROW_ENGINE", 1665, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging.%s" }, +{ "ER_BINLOG_ROW_INJECTION_AND_STMT_MODE", 1666, "Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT." }, +{ "ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE", 1667, "Cannot execute statement: impossible to write to binary log since more than one engine is involved and at least one engine is self-logging." }, +{ "ER_BINLOG_UNSAFE_LIMIT", 1668, "The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted." }, +{ "ER_BINLOG_UNSAFE_INSERT_DELAYED", 1669, "The statement is unsafe because it uses INSERT DELAYED. This is unsafe because the times when rows are inserted cannot be predicted." }, +{ "ER_BINLOG_UNSAFE_SYSTEM_TABLE", 1670, "The statement is unsafe because it uses the general log, slow query log, or performance_schema table(s). This is unsafe because system tables may differ on slaves." }, +{ "ER_BINLOG_UNSAFE_AUTOINC_COLUMNS", 1671, "Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly." }, +{ "ER_BINLOG_UNSAFE_UDF", 1672, "Statement is unsafe because it uses a UDF which may not return the same value on the slave." }, +{ "ER_BINLOG_UNSAFE_SYSTEM_VARIABLE", 1673, "Statement is unsafe because it uses a system variable that may have a different value on the slave." }, +{ "ER_BINLOG_UNSAFE_SYSTEM_FUNCTION", 1674, "Statement is unsafe because it uses a system function that may return a different value on the slave." }, +{ "ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS", 1675, "Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction." }, +{ "ER_MESSAGE_AND_STATEMENT", 1676, "%s Statement: %s" }, +{ "ER_SLAVE_CONVERSION_FAILED", 1677, "Column %d of table \'%-.192s.%-.192s\' cannot be converted from type \'%-.32s\' to type \'%-.32s\'" }, +{ "ER_SLAVE_CANT_CREATE_CONVERSION", 1678, "Can\'t create conversion table for table \'%-.192s.%-.192s\'" }, +{ "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT", 1679, "Cannot modify @@session.binlog_format inside a transaction" }, +{ "ER_PATH_LENGTH", 1680, "The path specified for %.64s is too long." }, +{ "ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT", 1681, "The syntax \'%s\' is deprecated and will be removed in MySQL %s." }, +{ "ER_WRONG_NATIVE_TABLE_STRUCTURE", 1682, "Native table \'%-.64s\'.\'%-.64s\' has the wrong structure" }, +{ "ER_WRONG_PERFSCHEMA_USAGE", 1683, "Invalid performance_schema usage." }, +{ "ER_WARN_I_S_SKIPPED_TABLE", 1684, "Table \'%s\'.\'%s\' was skipped since its definition is being modified by concurrent DDL statement" }, +{ "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT", 1685, "Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction" }, +{ "ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT", 1686, "Cannot change the binlog direct flag inside a stored function or trigger" }, +{ "ER_SPATIAL_MUST_HAVE_GEOM_COL", 1687, "A SPATIAL index may only contain a geometrical type column" }, +{ "ER_TOO_LONG_INDEX_COMMENT", 1688, "Comment for index \'%-.64s\' is too long (max = %lu)" }, +{ "ER_LOCK_ABORTED", 1689, "Wait on a lock was aborted due to a pending exclusive lock" }, +{ "ER_DATA_OUT_OF_RANGE", 1690, "%s value is out of range in \'%s\'" }, +{ "ER_WRONG_SPVAR_TYPE_IN_LIMIT", 1691, "A variable of a non-integer type in LIMIT clause" }, +{ "ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE", 1692, "Mixing self-logging and non-self-logging engines in a statement is unsafe." }, +{ "ER_BINLOG_UNSAFE_MIXED_STATEMENT", 1693, "Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them." }, +{ "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN", 1694, "Cannot modify @@session.sql_log_bin inside a transaction" }, +{ "ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN", 1695, "Cannot change the sql_log_bin inside a stored function or trigger" }, +{ "ER_FAILED_READ_FROM_PAR_FILE", 1696, "Failed to read from the .par file" }, +{ "ER_VALUES_IS_NOT_INT_TYPE_ERROR", 1697, "VALUES value for partition \'%-.64s\' must have type INT" }, +{ "ER_ACCESS_DENIED_NO_PASSWORD_ERROR", 1698, "Access denied for user \'%-.48s\'@\'%-.64s\'" }, +{ "ER_SET_PASSWORD_AUTH_PLUGIN", 1699, "SET PASSWORD has no significance for users authenticating via plugins" }, +{ "ER_GRANT_PLUGIN_USER_EXISTS", 1700, "GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists" }, +{ "ER_TRUNCATE_ILLEGAL_FK", 1701, "Cannot truncate a table referenced in a foreign key constraint (%.192s)" }, +{ "ER_PLUGIN_IS_PERMANENT", 1702, "Plugin \'%s\' is force_plus_permanent and can not be unloaded" }, +{ "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN", 1703, "The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled." }, +{ "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX", 1704, "The requested value for the heartbeat period exceeds the value of `slave_net_timeout\' seconds. A sensible value for the period should be less than the timeout." }, +{ "ER_STMT_CACHE_FULL", 1705, "Multi-row statements required more than \'max_binlog_stmt_cache_size\' bytes of storage; increase this mysqld variable and try again" }, diff --git a/code/meosdb/mysql55/mysqld_error.h b/code/meosdb/mysql55/mysqld_error.h new file mode 100644 index 0000000..bf059e7 --- /dev/null +++ b/code/meosdb/mysql55/mysqld_error.h @@ -0,0 +1,710 @@ +/* Autogenerated file, please don't edit */ + +#define ER_ERROR_FIRST 1000 +#define ER_HASHCHK 1000 +#define ER_NISAMCHK 1001 +#define ER_NO 1002 +#define ER_YES 1003 +#define ER_CANT_CREATE_FILE 1004 +#define ER_CANT_CREATE_TABLE 1005 +#define ER_CANT_CREATE_DB 1006 +#define ER_DB_CREATE_EXISTS 1007 +#define ER_DB_DROP_EXISTS 1008 +#define ER_DB_DROP_DELETE 1009 +#define ER_DB_DROP_RMDIR 1010 +#define ER_CANT_DELETE_FILE 1011 +#define ER_CANT_FIND_SYSTEM_REC 1012 +#define ER_CANT_GET_STAT 1013 +#define ER_CANT_GET_WD 1014 +#define ER_CANT_LOCK 1015 +#define ER_CANT_OPEN_FILE 1016 +#define ER_FILE_NOT_FOUND 1017 +#define ER_CANT_READ_DIR 1018 +#define ER_CANT_SET_WD 1019 +#define ER_CHECKREAD 1020 +#define ER_DISK_FULL 1021 +#define ER_DUP_KEY 1022 +#define ER_ERROR_ON_CLOSE 1023 +#define ER_ERROR_ON_READ 1024 +#define ER_ERROR_ON_RENAME 1025 +#define ER_ERROR_ON_WRITE 1026 +#define ER_FILE_USED 1027 +#define ER_FILSORT_ABORT 1028 +#define ER_FORM_NOT_FOUND 1029 +#define ER_GET_ERRNO 1030 +#define ER_ILLEGAL_HA 1031 +#define ER_KEY_NOT_FOUND 1032 +#define ER_NOT_FORM_FILE 1033 +#define ER_NOT_KEYFILE 1034 +#define ER_OLD_KEYFILE 1035 +#define ER_OPEN_AS_READONLY 1036 +#define ER_OUTOFMEMORY 1037 +#define ER_OUT_OF_SORTMEMORY 1038 +#define ER_UNEXPECTED_EOF 1039 +#define ER_CON_COUNT_ERROR 1040 +#define ER_OUT_OF_RESOURCES 1041 +#define ER_BAD_HOST_ERROR 1042 +#define ER_HANDSHAKE_ERROR 1043 +#define ER_DBACCESS_DENIED_ERROR 1044 +#define ER_ACCESS_DENIED_ERROR 1045 +#define ER_NO_DB_ERROR 1046 +#define ER_UNKNOWN_COM_ERROR 1047 +#define ER_BAD_NULL_ERROR 1048 +#define ER_BAD_DB_ERROR 1049 +#define ER_TABLE_EXISTS_ERROR 1050 +#define ER_BAD_TABLE_ERROR 1051 +#define ER_NON_UNIQ_ERROR 1052 +#define ER_SERVER_SHUTDOWN 1053 +#define ER_BAD_FIELD_ERROR 1054 +#define ER_WRONG_FIELD_WITH_GROUP 1055 +#define ER_WRONG_GROUP_FIELD 1056 +#define ER_WRONG_SUM_SELECT 1057 +#define ER_WRONG_VALUE_COUNT 1058 +#define ER_TOO_LONG_IDENT 1059 +#define ER_DUP_FIELDNAME 1060 +#define ER_DUP_KEYNAME 1061 +#define ER_DUP_ENTRY 1062 +#define ER_WRONG_FIELD_SPEC 1063 +#define ER_PARSE_ERROR 1064 +#define ER_EMPTY_QUERY 1065 +#define ER_NONUNIQ_TABLE 1066 +#define ER_INVALID_DEFAULT 1067 +#define ER_MULTIPLE_PRI_KEY 1068 +#define ER_TOO_MANY_KEYS 1069 +#define ER_TOO_MANY_KEY_PARTS 1070 +#define ER_TOO_LONG_KEY 1071 +#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072 +#define ER_BLOB_USED_AS_KEY 1073 +#define ER_TOO_BIG_FIELDLENGTH 1074 +#define ER_WRONG_AUTO_KEY 1075 +#define ER_READY 1076 +#define ER_NORMAL_SHUTDOWN 1077 +#define ER_GOT_SIGNAL 1078 +#define ER_SHUTDOWN_COMPLETE 1079 +#define ER_FORCING_CLOSE 1080 +#define ER_IPSOCK_ERROR 1081 +#define ER_NO_SUCH_INDEX 1082 +#define ER_WRONG_FIELD_TERMINATORS 1083 +#define ER_BLOBS_AND_NO_TERMINATED 1084 +#define ER_TEXTFILE_NOT_READABLE 1085 +#define ER_FILE_EXISTS_ERROR 1086 +#define ER_LOAD_INFO 1087 +#define ER_ALTER_INFO 1088 +#define ER_WRONG_SUB_KEY 1089 +#define ER_CANT_REMOVE_ALL_FIELDS 1090 +#define ER_CANT_DROP_FIELD_OR_KEY 1091 +#define ER_INSERT_INFO 1092 +#define ER_UPDATE_TABLE_USED 1093 +#define ER_NO_SUCH_THREAD 1094 +#define ER_KILL_DENIED_ERROR 1095 +#define ER_NO_TABLES_USED 1096 +#define ER_TOO_BIG_SET 1097 +#define ER_NO_UNIQUE_LOGFILE 1098 +#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 +#define ER_TABLE_NOT_LOCKED 1100 +#define ER_BLOB_CANT_HAVE_DEFAULT 1101 +#define ER_WRONG_DB_NAME 1102 +#define ER_WRONG_TABLE_NAME 1103 +#define ER_TOO_BIG_SELECT 1104 +#define ER_UNKNOWN_ERROR 1105 +#define ER_UNKNOWN_PROCEDURE 1106 +#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 +#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 +#define ER_UNKNOWN_TABLE 1109 +#define ER_FIELD_SPECIFIED_TWICE 1110 +#define ER_INVALID_GROUP_FUNC_USE 1111 +#define ER_UNSUPPORTED_EXTENSION 1112 +#define ER_TABLE_MUST_HAVE_COLUMNS 1113 +#define ER_RECORD_FILE_FULL 1114 +#define ER_UNKNOWN_CHARACTER_SET 1115 +#define ER_TOO_MANY_TABLES 1116 +#define ER_TOO_MANY_FIELDS 1117 +#define ER_TOO_BIG_ROWSIZE 1118 +#define ER_STACK_OVERRUN 1119 +#define ER_WRONG_OUTER_JOIN 1120 +#define ER_NULL_COLUMN_IN_INDEX 1121 +#define ER_CANT_FIND_UDF 1122 +#define ER_CANT_INITIALIZE_UDF 1123 +#define ER_UDF_NO_PATHS 1124 +#define ER_UDF_EXISTS 1125 +#define ER_CANT_OPEN_LIBRARY 1126 +#define ER_CANT_FIND_DL_ENTRY 1127 +#define ER_FUNCTION_NOT_DEFINED 1128 +#define ER_HOST_IS_BLOCKED 1129 +#define ER_HOST_NOT_PRIVILEGED 1130 +#define ER_PASSWORD_ANONYMOUS_USER 1131 +#define ER_PASSWORD_NOT_ALLOWED 1132 +#define ER_PASSWORD_NO_MATCH 1133 +#define ER_UPDATE_INFO 1134 +#define ER_CANT_CREATE_THREAD 1135 +#define ER_WRONG_VALUE_COUNT_ON_ROW 1136 +#define ER_CANT_REOPEN_TABLE 1137 +#define ER_INVALID_USE_OF_NULL 1138 +#define ER_REGEXP_ERROR 1139 +#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 +#define ER_NONEXISTING_GRANT 1141 +#define ER_TABLEACCESS_DENIED_ERROR 1142 +#define ER_COLUMNACCESS_DENIED_ERROR 1143 +#define ER_ILLEGAL_GRANT_FOR_TABLE 1144 +#define ER_GRANT_WRONG_HOST_OR_USER 1145 +#define ER_NO_SUCH_TABLE 1146 +#define ER_NONEXISTING_TABLE_GRANT 1147 +#define ER_NOT_ALLOWED_COMMAND 1148 +#define ER_SYNTAX_ERROR 1149 +#define ER_DELAYED_CANT_CHANGE_LOCK 1150 +#define ER_TOO_MANY_DELAYED_THREADS 1151 +#define ER_ABORTING_CONNECTION 1152 +#define ER_NET_PACKET_TOO_LARGE 1153 +#define ER_NET_READ_ERROR_FROM_PIPE 1154 +#define ER_NET_FCNTL_ERROR 1155 +#define ER_NET_PACKETS_OUT_OF_ORDER 1156 +#define ER_NET_UNCOMPRESS_ERROR 1157 +#define ER_NET_READ_ERROR 1158 +#define ER_NET_READ_INTERRUPTED 1159 +#define ER_NET_ERROR_ON_WRITE 1160 +#define ER_NET_WRITE_INTERRUPTED 1161 +#define ER_TOO_LONG_STRING 1162 +#define ER_TABLE_CANT_HANDLE_BLOB 1163 +#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 +#define ER_DELAYED_INSERT_TABLE_LOCKED 1165 +#define ER_WRONG_COLUMN_NAME 1166 +#define ER_WRONG_KEY_COLUMN 1167 +#define ER_WRONG_MRG_TABLE 1168 +#define ER_DUP_UNIQUE 1169 +#define ER_BLOB_KEY_WITHOUT_LENGTH 1170 +#define ER_PRIMARY_CANT_HAVE_NULL 1171 +#define ER_TOO_MANY_ROWS 1172 +#define ER_REQUIRES_PRIMARY_KEY 1173 +#define ER_NO_RAID_COMPILED 1174 +#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 +#define ER_KEY_DOES_NOT_EXITS 1176 +#define ER_CHECK_NO_SUCH_TABLE 1177 +#define ER_CHECK_NOT_IMPLEMENTED 1178 +#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 +#define ER_ERROR_DURING_COMMIT 1180 +#define ER_ERROR_DURING_ROLLBACK 1181 +#define ER_ERROR_DURING_FLUSH_LOGS 1182 +#define ER_ERROR_DURING_CHECKPOINT 1183 +#define ER_NEW_ABORTING_CONNECTION 1184 +#define ER_DUMP_NOT_IMPLEMENTED 1185 +#define ER_FLUSH_MASTER_BINLOG_CLOSED 1186 +#define ER_INDEX_REBUILD 1187 +#define ER_MASTER 1188 +#define ER_MASTER_NET_READ 1189 +#define ER_MASTER_NET_WRITE 1190 +#define ER_FT_MATCHING_KEY_NOT_FOUND 1191 +#define ER_LOCK_OR_ACTIVE_TRANSACTION 1192 +#define ER_UNKNOWN_SYSTEM_VARIABLE 1193 +#define ER_CRASHED_ON_USAGE 1194 +#define ER_CRASHED_ON_REPAIR 1195 +#define ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 +#define ER_TRANS_CACHE_FULL 1197 +#define ER_SLAVE_MUST_STOP 1198 +#define ER_SLAVE_NOT_RUNNING 1199 +#define ER_BAD_SLAVE 1200 +#define ER_MASTER_INFO 1201 +#define ER_SLAVE_THREAD 1202 +#define ER_TOO_MANY_USER_CONNECTIONS 1203 +#define ER_SET_CONSTANTS_ONLY 1204 +#define ER_LOCK_WAIT_TIMEOUT 1205 +#define ER_LOCK_TABLE_FULL 1206 +#define ER_READ_ONLY_TRANSACTION 1207 +#define ER_DROP_DB_WITH_READ_LOCK 1208 +#define ER_CREATE_DB_WITH_READ_LOCK 1209 +#define ER_WRONG_ARGUMENTS 1210 +#define ER_NO_PERMISSION_TO_CREATE_USER 1211 +#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 +#define ER_LOCK_DEADLOCK 1213 +#define ER_TABLE_CANT_HANDLE_FT 1214 +#define ER_CANNOT_ADD_FOREIGN 1215 +#define ER_NO_REFERENCED_ROW 1216 +#define ER_ROW_IS_REFERENCED 1217 +#define ER_CONNECT_TO_MASTER 1218 +#define ER_QUERY_ON_MASTER 1219 +#define ER_ERROR_WHEN_EXECUTING_COMMAND 1220 +#define ER_WRONG_USAGE 1221 +#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 +#define ER_CANT_UPDATE_WITH_READLOCK 1223 +#define ER_MIXING_NOT_ALLOWED 1224 +#define ER_DUP_ARGUMENT 1225 +#define ER_USER_LIMIT_REACHED 1226 +#define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 +#define ER_LOCAL_VARIABLE 1228 +#define ER_GLOBAL_VARIABLE 1229 +#define ER_NO_DEFAULT 1230 +#define ER_WRONG_VALUE_FOR_VAR 1231 +#define ER_WRONG_TYPE_FOR_VAR 1232 +#define ER_VAR_CANT_BE_READ 1233 +#define ER_CANT_USE_OPTION_HERE 1234 +#define ER_NOT_SUPPORTED_YET 1235 +#define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 +#define ER_SLAVE_IGNORED_TABLE 1237 +#define ER_INCORRECT_GLOBAL_LOCAL_VAR 1238 +#define ER_WRONG_FK_DEF 1239 +#define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240 +#define ER_OPERAND_COLUMNS 1241 +#define ER_SUBQUERY_NO_1_ROW 1242 +#define ER_UNKNOWN_STMT_HANDLER 1243 +#define ER_CORRUPT_HELP_DB 1244 +#define ER_CYCLIC_REFERENCE 1245 +#define ER_AUTO_CONVERT 1246 +#define ER_ILLEGAL_REFERENCE 1247 +#define ER_DERIVED_MUST_HAVE_ALIAS 1248 +#define ER_SELECT_REDUCED 1249 +#define ER_TABLENAME_NOT_ALLOWED_HERE 1250 +#define ER_NOT_SUPPORTED_AUTH_MODE 1251 +#define ER_SPATIAL_CANT_HAVE_NULL 1252 +#define ER_COLLATION_CHARSET_MISMATCH 1253 +#define ER_SLAVE_WAS_RUNNING 1254 +#define ER_SLAVE_WAS_NOT_RUNNING 1255 +#define ER_TOO_BIG_FOR_UNCOMPRESS 1256 +#define ER_ZLIB_Z_MEM_ERROR 1257 +#define ER_ZLIB_Z_BUF_ERROR 1258 +#define ER_ZLIB_Z_DATA_ERROR 1259 +#define ER_CUT_VALUE_GROUP_CONCAT 1260 +#define ER_WARN_TOO_FEW_RECORDS 1261 +#define ER_WARN_TOO_MANY_RECORDS 1262 +#define ER_WARN_NULL_TO_NOTNULL 1263 +#define ER_WARN_DATA_OUT_OF_RANGE 1264 +#define WARN_DATA_TRUNCATED 1265 +#define ER_WARN_USING_OTHER_HANDLER 1266 +#define ER_CANT_AGGREGATE_2COLLATIONS 1267 +#define ER_DROP_USER 1268 +#define ER_REVOKE_GRANTS 1269 +#define ER_CANT_AGGREGATE_3COLLATIONS 1270 +#define ER_CANT_AGGREGATE_NCOLLATIONS 1271 +#define ER_VARIABLE_IS_NOT_STRUCT 1272 +#define ER_UNKNOWN_COLLATION 1273 +#define ER_SLAVE_IGNORED_SSL_PARAMS 1274 +#define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275 +#define ER_WARN_FIELD_RESOLVED 1276 +#define ER_BAD_SLAVE_UNTIL_COND 1277 +#define ER_MISSING_SKIP_SLAVE 1278 +#define ER_UNTIL_COND_IGNORED 1279 +#define ER_WRONG_NAME_FOR_INDEX 1280 +#define ER_WRONG_NAME_FOR_CATALOG 1281 +#define ER_WARN_QC_RESIZE 1282 +#define ER_BAD_FT_COLUMN 1283 +#define ER_UNKNOWN_KEY_CACHE 1284 +#define ER_WARN_HOSTNAME_WONT_WORK 1285 +#define ER_UNKNOWN_STORAGE_ENGINE 1286 +#define ER_WARN_DEPRECATED_SYNTAX 1287 +#define ER_NON_UPDATABLE_TABLE 1288 +#define ER_FEATURE_DISABLED 1289 +#define ER_OPTION_PREVENTS_STATEMENT 1290 +#define ER_DUPLICATED_VALUE_IN_TYPE 1291 +#define ER_TRUNCATED_WRONG_VALUE 1292 +#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 +#define ER_INVALID_ON_UPDATE 1294 +#define ER_UNSUPPORTED_PS 1295 +#define ER_GET_ERRMSG 1296 +#define ER_GET_TEMPORARY_ERRMSG 1297 +#define ER_UNKNOWN_TIME_ZONE 1298 +#define ER_WARN_INVALID_TIMESTAMP 1299 +#define ER_INVALID_CHARACTER_STRING 1300 +#define ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301 +#define ER_CONFLICTING_DECLARATIONS 1302 +#define ER_SP_NO_RECURSIVE_CREATE 1303 +#define ER_SP_ALREADY_EXISTS 1304 +#define ER_SP_DOES_NOT_EXIST 1305 +#define ER_SP_DROP_FAILED 1306 +#define ER_SP_STORE_FAILED 1307 +#define ER_SP_LILABEL_MISMATCH 1308 +#define ER_SP_LABEL_REDEFINE 1309 +#define ER_SP_LABEL_MISMATCH 1310 +#define ER_SP_UNINIT_VAR 1311 +#define ER_SP_BADSELECT 1312 +#define ER_SP_BADRETURN 1313 +#define ER_SP_BADSTATEMENT 1314 +#define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 +#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 +#define ER_QUERY_INTERRUPTED 1317 +#define ER_SP_WRONG_NO_OF_ARGS 1318 +#define ER_SP_COND_MISMATCH 1319 +#define ER_SP_NORETURN 1320 +#define ER_SP_NORETURNEND 1321 +#define ER_SP_BAD_CURSOR_QUERY 1322 +#define ER_SP_BAD_CURSOR_SELECT 1323 +#define ER_SP_CURSOR_MISMATCH 1324 +#define ER_SP_CURSOR_ALREADY_OPEN 1325 +#define ER_SP_CURSOR_NOT_OPEN 1326 +#define ER_SP_UNDECLARED_VAR 1327 +#define ER_SP_WRONG_NO_OF_FETCH_ARGS 1328 +#define ER_SP_FETCH_NO_DATA 1329 +#define ER_SP_DUP_PARAM 1330 +#define ER_SP_DUP_VAR 1331 +#define ER_SP_DUP_COND 1332 +#define ER_SP_DUP_CURS 1333 +#define ER_SP_CANT_ALTER 1334 +#define ER_SP_SUBSELECT_NYI 1335 +#define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 +#define ER_SP_VARCOND_AFTER_CURSHNDLR 1337 +#define ER_SP_CURSOR_AFTER_HANDLER 1338 +#define ER_SP_CASE_NOT_FOUND 1339 +#define ER_FPARSER_TOO_BIG_FILE 1340 +#define ER_FPARSER_BAD_HEADER 1341 +#define ER_FPARSER_EOF_IN_COMMENT 1342 +#define ER_FPARSER_ERROR_IN_PARAMETER 1343 +#define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1344 +#define ER_VIEW_NO_EXPLAIN 1345 +#define ER_FRM_UNKNOWN_TYPE 1346 +#define ER_WRONG_OBJECT 1347 +#define ER_NONUPDATEABLE_COLUMN 1348 +#define ER_VIEW_SELECT_DERIVED 1349 +#define ER_VIEW_SELECT_CLAUSE 1350 +#define ER_VIEW_SELECT_VARIABLE 1351 +#define ER_VIEW_SELECT_TMPTABLE 1352 +#define ER_VIEW_WRONG_LIST 1353 +#define ER_WARN_VIEW_MERGE 1354 +#define ER_WARN_VIEW_WITHOUT_KEY 1355 +#define ER_VIEW_INVALID 1356 +#define ER_SP_NO_DROP_SP 1357 +#define ER_SP_GOTO_IN_HNDLR 1358 +#define ER_TRG_ALREADY_EXISTS 1359 +#define ER_TRG_DOES_NOT_EXIST 1360 +#define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 +#define ER_TRG_CANT_CHANGE_ROW 1362 +#define ER_TRG_NO_SUCH_ROW_IN_TRG 1363 +#define ER_NO_DEFAULT_FOR_FIELD 1364 +#define ER_DIVISION_BY_ZERO 1365 +#define ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 1366 +#define ER_ILLEGAL_VALUE_FOR_TYPE 1367 +#define ER_VIEW_NONUPD_CHECK 1368 +#define ER_VIEW_CHECK_FAILED 1369 +#define ER_PROCACCESS_DENIED_ERROR 1370 +#define ER_RELAY_LOG_FAIL 1371 +#define ER_PASSWD_LENGTH 1372 +#define ER_UNKNOWN_TARGET_BINLOG 1373 +#define ER_IO_ERR_LOG_INDEX_READ 1374 +#define ER_BINLOG_PURGE_PROHIBITED 1375 +#define ER_FSEEK_FAIL 1376 +#define ER_BINLOG_PURGE_FATAL_ERR 1377 +#define ER_LOG_IN_USE 1378 +#define ER_LOG_PURGE_UNKNOWN_ERR 1379 +#define ER_RELAY_LOG_INIT 1380 +#define ER_NO_BINARY_LOGGING 1381 +#define ER_RESERVED_SYNTAX 1382 +#define ER_WSAS_FAILED 1383 +#define ER_DIFF_GROUPS_PROC 1384 +#define ER_NO_GROUP_FOR_PROC 1385 +#define ER_ORDER_WITH_PROC 1386 +#define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 +#define ER_NO_FILE_MAPPING 1388 +#define ER_WRONG_MAGIC 1389 +#define ER_PS_MANY_PARAM 1390 +#define ER_KEY_PART_0 1391 +#define ER_VIEW_CHECKSUM 1392 +#define ER_VIEW_MULTIUPDATE 1393 +#define ER_VIEW_NO_INSERT_FIELD_LIST 1394 +#define ER_VIEW_DELETE_MERGE_VIEW 1395 +#define ER_CANNOT_USER 1396 +#define ER_XAER_NOTA 1397 +#define ER_XAER_INVAL 1398 +#define ER_XAER_RMFAIL 1399 +#define ER_XAER_OUTSIDE 1400 +#define ER_XAER_RMERR 1401 +#define ER_XA_RBROLLBACK 1402 +#define ER_NONEXISTING_PROC_GRANT 1403 +#define ER_PROC_AUTO_GRANT_FAIL 1404 +#define ER_PROC_AUTO_REVOKE_FAIL 1405 +#define ER_DATA_TOO_LONG 1406 +#define ER_SP_BAD_SQLSTATE 1407 +#define ER_STARTUP 1408 +#define ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR 1409 +#define ER_CANT_CREATE_USER_WITH_GRANT 1410 +#define ER_WRONG_VALUE_FOR_TYPE 1411 +#define ER_TABLE_DEF_CHANGED 1412 +#define ER_SP_DUP_HANDLER 1413 +#define ER_SP_NOT_VAR_ARG 1414 +#define ER_SP_NO_RETSET 1415 +#define ER_CANT_CREATE_GEOMETRY_OBJECT 1416 +#define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 +#define ER_BINLOG_UNSAFE_ROUTINE 1418 +#define ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 +#define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 +#define ER_STMT_HAS_NO_OPEN_CURSOR 1421 +#define ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 +#define ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 +#define ER_SP_NO_RECURSION 1424 +#define ER_TOO_BIG_SCALE 1425 +#define ER_TOO_BIG_PRECISION 1426 +#define ER_M_BIGGER_THAN_D 1427 +#define ER_WRONG_LOCK_OF_SYSTEM_TABLE 1428 +#define ER_CONNECT_TO_FOREIGN_DATA_SOURCE 1429 +#define ER_QUERY_ON_FOREIGN_DATA_SOURCE 1430 +#define ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST 1431 +#define ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE 1432 +#define ER_FOREIGN_DATA_STRING_INVALID 1433 +#define ER_CANT_CREATE_FEDERATED_TABLE 1434 +#define ER_TRG_IN_WRONG_SCHEMA 1435 +#define ER_STACK_OVERRUN_NEED_MORE 1436 +#define ER_TOO_LONG_BODY 1437 +#define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 +#define ER_TOO_BIG_DISPLAYWIDTH 1439 +#define ER_XAER_DUPID 1440 +#define ER_DATETIME_FUNCTION_OVERFLOW 1441 +#define ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 +#define ER_VIEW_PREVENT_UPDATE 1443 +#define ER_PS_NO_RECURSION 1444 +#define ER_SP_CANT_SET_AUTOCOMMIT 1445 +#define ER_MALFORMED_DEFINER 1446 +#define ER_VIEW_FRM_NO_USER 1447 +#define ER_VIEW_OTHER_USER 1448 +#define ER_NO_SUCH_USER 1449 +#define ER_FORBID_SCHEMA_CHANGE 1450 +#define ER_ROW_IS_REFERENCED_2 1451 +#define ER_NO_REFERENCED_ROW_2 1452 +#define ER_SP_BAD_VAR_SHADOW 1453 +#define ER_TRG_NO_DEFINER 1454 +#define ER_OLD_FILE_FORMAT 1455 +#define ER_SP_RECURSION_LIMIT 1456 +#define ER_SP_PROC_TABLE_CORRUPT 1457 +#define ER_SP_WRONG_NAME 1458 +#define ER_TABLE_NEEDS_UPGRADE 1459 +#define ER_SP_NO_AGGREGATE 1460 +#define ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 +#define ER_VIEW_RECURSIVE 1462 +#define ER_NON_GROUPING_FIELD_USED 1463 +#define ER_TABLE_CANT_HANDLE_SPKEYS 1464 +#define ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA 1465 +#define ER_REMOVED_SPACES 1466 +#define ER_AUTOINC_READ_FAILED 1467 +#define ER_USERNAME 1468 +#define ER_HOSTNAME 1469 +#define ER_WRONG_STRING_LENGTH 1470 +#define ER_NON_INSERTABLE_TABLE 1471 +#define ER_ADMIN_WRONG_MRG_TABLE 1472 +#define ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT 1473 +#define ER_NAME_BECOMES_EMPTY 1474 +#define ER_AMBIGUOUS_FIELD_TERM 1475 +#define ER_FOREIGN_SERVER_EXISTS 1476 +#define ER_FOREIGN_SERVER_DOESNT_EXIST 1477 +#define ER_ILLEGAL_HA_CREATE_OPTION 1478 +#define ER_PARTITION_REQUIRES_VALUES_ERROR 1479 +#define ER_PARTITION_WRONG_VALUES_ERROR 1480 +#define ER_PARTITION_MAXVALUE_ERROR 1481 +#define ER_PARTITION_SUBPARTITION_ERROR 1482 +#define ER_PARTITION_SUBPART_MIX_ERROR 1483 +#define ER_PARTITION_WRONG_NO_PART_ERROR 1484 +#define ER_PARTITION_WRONG_NO_SUBPART_ERROR 1485 +#define ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR 1486 +#define ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR 1487 +#define ER_FIELD_NOT_FOUND_PART_ERROR 1488 +#define ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 +#define ER_INCONSISTENT_PARTITION_INFO_ERROR 1490 +#define ER_PARTITION_FUNC_NOT_ALLOWED_ERROR 1491 +#define ER_PARTITIONS_MUST_BE_DEFINED_ERROR 1492 +#define ER_RANGE_NOT_INCREASING_ERROR 1493 +#define ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 +#define ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR 1495 +#define ER_PARTITION_ENTRY_ERROR 1496 +#define ER_MIX_HANDLER_ERROR 1497 +#define ER_PARTITION_NOT_DEFINED_ERROR 1498 +#define ER_TOO_MANY_PARTITIONS_ERROR 1499 +#define ER_SUBPARTITION_ERROR 1500 +#define ER_CANT_CREATE_HANDLER_FILE 1501 +#define ER_BLOB_FIELD_IN_PART_FUNC_ERROR 1502 +#define ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF 1503 +#define ER_NO_PARTS_ERROR 1504 +#define ER_PARTITION_MGMT_ON_NONPARTITIONED 1505 +#define ER_FOREIGN_KEY_ON_PARTITIONED 1506 +#define ER_DROP_PARTITION_NON_EXISTENT 1507 +#define ER_DROP_LAST_PARTITION 1508 +#define ER_COALESCE_ONLY_ON_HASH_PARTITION 1509 +#define ER_REORG_HASH_ONLY_ON_SAME_NO 1510 +#define ER_REORG_NO_PARAM_ERROR 1511 +#define ER_ONLY_ON_RANGE_LIST_PARTITION 1512 +#define ER_ADD_PARTITION_SUBPART_ERROR 1513 +#define ER_ADD_PARTITION_NO_NEW_PARTITION 1514 +#define ER_COALESCE_PARTITION_NO_PARTITION 1515 +#define ER_REORG_PARTITION_NOT_EXIST 1516 +#define ER_SAME_NAME_PARTITION 1517 +#define ER_NO_BINLOG_ERROR 1518 +#define ER_CONSECUTIVE_REORG_PARTITIONS 1519 +#define ER_REORG_OUTSIDE_RANGE 1520 +#define ER_PARTITION_FUNCTION_FAILURE 1521 +#define ER_PART_STATE_ERROR 1522 +#define ER_LIMITED_PART_RANGE 1523 +#define ER_PLUGIN_IS_NOT_LOADED 1524 +#define ER_WRONG_VALUE 1525 +#define ER_NO_PARTITION_FOR_GIVEN_VALUE 1526 +#define ER_FILEGROUP_OPTION_ONLY_ONCE 1527 +#define ER_CREATE_FILEGROUP_FAILED 1528 +#define ER_DROP_FILEGROUP_FAILED 1529 +#define ER_TABLESPACE_AUTO_EXTEND_ERROR 1530 +#define ER_WRONG_SIZE_NUMBER 1531 +#define ER_SIZE_OVERFLOW_ERROR 1532 +#define ER_ALTER_FILEGROUP_FAILED 1533 +#define ER_BINLOG_ROW_LOGGING_FAILED 1534 +#define ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 +#define ER_BINLOG_ROW_RBR_TO_SBR 1536 +#define ER_EVENT_ALREADY_EXISTS 1537 +#define ER_EVENT_STORE_FAILED 1538 +#define ER_EVENT_DOES_NOT_EXIST 1539 +#define ER_EVENT_CANT_ALTER 1540 +#define ER_EVENT_DROP_FAILED 1541 +#define ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG 1542 +#define ER_EVENT_ENDS_BEFORE_STARTS 1543 +#define ER_EVENT_EXEC_TIME_IN_THE_PAST 1544 +#define ER_EVENT_OPEN_TABLE_FAILED 1545 +#define ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 +#define ER_COL_COUNT_DOESNT_MATCH_CORRUPTED 1547 +#define ER_CANNOT_LOAD_FROM_TABLE 1548 +#define ER_EVENT_CANNOT_DELETE 1549 +#define ER_EVENT_COMPILE_ERROR 1550 +#define ER_EVENT_SAME_NAME 1551 +#define ER_EVENT_DATA_TOO_LONG 1552 +#define ER_DROP_INDEX_FK 1553 +#define ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 +#define ER_CANT_WRITE_LOCK_LOG_TABLE 1555 +#define ER_CANT_LOCK_LOG_TABLE 1556 +#define ER_FOREIGN_DUPLICATE_KEY 1557 +#define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE 1558 +#define ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR 1559 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT 1560 +#define ER_NDB_CANT_SWITCH_BINLOG_FORMAT 1561 +#define ER_PARTITION_NO_TEMPORARY 1562 +#define ER_PARTITION_CONST_DOMAIN_ERROR 1563 +#define ER_PARTITION_FUNCTION_IS_NOT_ALLOWED 1564 +#define ER_DDL_LOG_ERROR 1565 +#define ER_NULL_IN_VALUES_LESS_THAN 1566 +#define ER_WRONG_PARTITION_NAME 1567 +#define ER_CANT_CHANGE_TX_ISOLATION 1568 +#define ER_DUP_ENTRY_AUTOINCREMENT_CASE 1569 +#define ER_EVENT_MODIFY_QUEUE_ERROR 1570 +#define ER_EVENT_SET_VAR_ERROR 1571 +#define ER_PARTITION_MERGE_ERROR 1572 +#define ER_CANT_ACTIVATE_LOG 1573 +#define ER_RBR_NOT_AVAILABLE 1574 +#define ER_BASE64_DECODE_ERROR 1575 +#define ER_EVENT_RECURSION_FORBIDDEN 1576 +#define ER_EVENTS_DB_ERROR 1577 +#define ER_ONLY_INTEGERS_ALLOWED 1578 +#define ER_UNSUPORTED_LOG_ENGINE 1579 +#define ER_BAD_LOG_STATEMENT 1580 +#define ER_CANT_RENAME_LOG_TABLE 1581 +#define ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 1582 +#define ER_WRONG_PARAMETERS_TO_NATIVE_FCT 1583 +#define ER_WRONG_PARAMETERS_TO_STORED_FCT 1584 +#define ER_NATIVE_FCT_NAME_COLLISION 1585 +#define ER_DUP_ENTRY_WITH_KEY_NAME 1586 +#define ER_BINLOG_PURGE_EMFILE 1587 +#define ER_EVENT_CANNOT_CREATE_IN_THE_PAST 1588 +#define ER_EVENT_CANNOT_ALTER_IN_THE_PAST 1589 +#define ER_SLAVE_INCIDENT 1590 +#define ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT 1591 +#define ER_BINLOG_UNSAFE_STATEMENT 1592 +#define ER_SLAVE_FATAL_ERROR 1593 +#define ER_SLAVE_RELAY_LOG_READ_FAILURE 1594 +#define ER_SLAVE_RELAY_LOG_WRITE_FAILURE 1595 +#define ER_SLAVE_CREATE_EVENT_FAILURE 1596 +#define ER_SLAVE_MASTER_COM_FAILURE 1597 +#define ER_BINLOG_LOGGING_IMPOSSIBLE 1598 +#define ER_VIEW_NO_CREATION_CTX 1599 +#define ER_VIEW_INVALID_CREATION_CTX 1600 +#define ER_SR_INVALID_CREATION_CTX 1601 +#define ER_TRG_CORRUPTED_FILE 1602 +#define ER_TRG_NO_CREATION_CTX 1603 +#define ER_TRG_INVALID_CREATION_CTX 1604 +#define ER_EVENT_INVALID_CREATION_CTX 1605 +#define ER_TRG_CANT_OPEN_TABLE 1606 +#define ER_CANT_CREATE_SROUTINE 1607 +#define ER_NEVER_USED 1608 +#define ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT 1609 +#define ER_SLAVE_CORRUPT_EVENT 1610 +#define ER_LOAD_DATA_INVALID_COLUMN 1611 +#define ER_LOG_PURGE_NO_FILE 1612 +#define ER_XA_RBTIMEOUT 1613 +#define ER_XA_RBDEADLOCK 1614 +#define ER_NEED_REPREPARE 1615 +#define ER_DELAYED_NOT_SUPPORTED 1616 +#define WARN_NO_MASTER_INFO 1617 +#define WARN_OPTION_IGNORED 1618 +#define WARN_PLUGIN_DELETE_BUILTIN 1619 +#define WARN_PLUGIN_BUSY 1620 +#define ER_VARIABLE_IS_READONLY 1621 +#define ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 +#define ER_SLAVE_HEARTBEAT_FAILURE 1623 +#define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE 1624 +#define ER_NDB_REPLICATION_SCHEMA_ERROR 1625 +#define ER_CONFLICT_FN_PARSE_ERROR 1626 +#define ER_EXCEPTIONS_WRITE_ERROR 1627 +#define ER_TOO_LONG_TABLE_COMMENT 1628 +#define ER_TOO_LONG_FIELD_COMMENT 1629 +#define ER_FUNC_INEXISTENT_NAME_COLLISION 1630 +#define ER_DATABASE_NAME 1631 +#define ER_TABLE_NAME 1632 +#define ER_PARTITION_NAME 1633 +#define ER_SUBPARTITION_NAME 1634 +#define ER_TEMPORARY_NAME 1635 +#define ER_RENAMED_NAME 1636 +#define ER_TOO_MANY_CONCURRENT_TRXS 1637 +#define WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED 1638 +#define ER_DEBUG_SYNC_TIMEOUT 1639 +#define ER_DEBUG_SYNC_HIT_LIMIT 1640 +#define ER_DUP_SIGNAL_SET 1641 +#define ER_SIGNAL_WARN 1642 +#define ER_SIGNAL_NOT_FOUND 1643 +#define ER_SIGNAL_EXCEPTION 1644 +#define ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 1645 +#define ER_SIGNAL_BAD_CONDITION_TYPE 1646 +#define WARN_COND_ITEM_TRUNCATED 1647 +#define ER_COND_ITEM_TOO_LONG 1648 +#define ER_UNKNOWN_LOCALE 1649 +#define ER_SLAVE_IGNORE_SERVER_IDS 1650 +#define ER_QUERY_CACHE_DISABLED 1651 +#define ER_SAME_NAME_PARTITION_FIELD 1652 +#define ER_PARTITION_COLUMN_LIST_ERROR 1653 +#define ER_WRONG_TYPE_COLUMN_VALUE_ERROR 1654 +#define ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR 1655 +#define ER_MAXVALUE_IN_VALUES_IN 1656 +#define ER_TOO_MANY_VALUES_ERROR 1657 +#define ER_ROW_SINGLE_PARTITION_FIELD_ERROR 1658 +#define ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD 1659 +#define ER_PARTITION_FIELDS_TOO_LONG 1660 +#define ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE 1661 +#define ER_BINLOG_ROW_MODE_AND_STMT_ENGINE 1662 +#define ER_BINLOG_UNSAFE_AND_STMT_ENGINE 1663 +#define ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE 1664 +#define ER_BINLOG_STMT_MODE_AND_ROW_ENGINE 1665 +#define ER_BINLOG_ROW_INJECTION_AND_STMT_MODE 1666 +#define ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1667 +#define ER_BINLOG_UNSAFE_LIMIT 1668 +#define ER_BINLOG_UNSAFE_INSERT_DELAYED 1669 +#define ER_BINLOG_UNSAFE_SYSTEM_TABLE 1670 +#define ER_BINLOG_UNSAFE_AUTOINC_COLUMNS 1671 +#define ER_BINLOG_UNSAFE_UDF 1672 +#define ER_BINLOG_UNSAFE_SYSTEM_VARIABLE 1673 +#define ER_BINLOG_UNSAFE_SYSTEM_FUNCTION 1674 +#define ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS 1675 +#define ER_MESSAGE_AND_STATEMENT 1676 +#define ER_SLAVE_CONVERSION_FAILED 1677 +#define ER_SLAVE_CANT_CREATE_CONVERSION 1678 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT 1679 +#define ER_PATH_LENGTH 1680 +#define ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT 1681 +#define ER_WRONG_NATIVE_TABLE_STRUCTURE 1682 +#define ER_WRONG_PERFSCHEMA_USAGE 1683 +#define ER_WARN_I_S_SKIPPED_TABLE 1684 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT 1685 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT 1686 +#define ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 +#define ER_TOO_LONG_INDEX_COMMENT 1688 +#define ER_LOCK_ABORTED 1689 +#define ER_DATA_OUT_OF_RANGE 1690 +#define ER_WRONG_SPVAR_TYPE_IN_LIMIT 1691 +#define ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1692 +#define ER_BINLOG_UNSAFE_MIXED_STATEMENT 1693 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN 1694 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN 1695 +#define ER_FAILED_READ_FROM_PAR_FILE 1696 +#define ER_VALUES_IS_NOT_INT_TYPE_ERROR 1697 +#define ER_ACCESS_DENIED_NO_PASSWORD_ERROR 1698 +#define ER_SET_PASSWORD_AUTH_PLUGIN 1699 +#define ER_GRANT_PLUGIN_USER_EXISTS 1700 +#define ER_TRUNCATE_ILLEGAL_FK 1701 +#define ER_PLUGIN_IS_PERMANENT 1702 +#define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN 1703 +#define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX 1704 +#define ER_STMT_CACHE_FULL 1705 +#define ER_ERROR_LAST 1705 diff --git a/code/meosdb/mysql55/plugin.h b/code/meosdb/mysql55/plugin.h new file mode 100644 index 0000000..7f91b6c --- /dev/null +++ b/code/meosdb/mysql55/plugin.h @@ -0,0 +1,633 @@ +/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc. + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_plugin_h +#define _my_plugin_h + +/* + On Windows, exports from DLL need to be declared + Also, plugin needs to be declared as extern "C" because MSVC + unlike other compilers, uses C++ mangling for variables not only + for functions. +*/ +#if defined(_MSC_VER) +#if defined(MYSQL_DYNAMIC_PLUGIN) + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) + #else + #define MYSQL_PLUGIN_EXPORT __declspec(dllexport) + #endif +#else /* MYSQL_DYNAMIC_PLUGIN */ + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" + #else + #define MYSQL_PLUGIN_EXPORT + #endif +#endif /*MYSQL_DYNAMIC_PLUGIN */ +#else /*_MSC_VER */ +#define MYSQL_PLUGIN_EXPORT +#endif + +#ifdef __cplusplus +class THD; +class Item; +#define MYSQL_THD THD* +#else +#define MYSQL_THD void* +#endif + +#include + +#define MYSQL_XIDDATASIZE 128 +/** + struct st_mysql_xid is binary compatible with the XID structure as + in the X/Open CAE Specification, Distributed Transaction Processing: + The XA Specification, X/Open Company Ltd., 1991. + http://www.opengroup.org/bookstore/catalog/c193.htm + + @see XID in sql/handler.h +*/ +struct st_mysql_xid { + long formatID; + long gtrid_length; + long bqual_length; + char data[MYSQL_XIDDATASIZE]; /* Not \0-terminated */ +}; +typedef struct st_mysql_xid MYSQL_XID; + +/************************************************************************* + Plugin API. Common for all plugin types. +*/ + +#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0102 + +/* + The allowable types of plugins +*/ +#define MYSQL_UDF_PLUGIN 0 /* User-defined function */ +#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */ +#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */ +#define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */ +#define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */ +#define MYSQL_AUDIT_PLUGIN 5 /* The Audit plugin type */ +#define MYSQL_REPLICATION_PLUGIN 6 /* The replication plugin type */ +#define MYSQL_AUTHENTICATION_PLUGIN 7 /* The authentication plugin type */ +#define MYSQL_MAX_PLUGIN_TYPE_NUM 8 /* The number of plugin types */ + +/* We use the following strings to define licenses for plugins */ +#define PLUGIN_LICENSE_PROPRIETARY 0 +#define PLUGIN_LICENSE_GPL 1 +#define PLUGIN_LICENSE_BSD 2 + +#define PLUGIN_LICENSE_PROPRIETARY_STRING "PROPRIETARY" +#define PLUGIN_LICENSE_GPL_STRING "GPL" +#define PLUGIN_LICENSE_BSD_STRING "BSD" + +/* + Macros for beginning and ending plugin declarations. Between + mysql_declare_plugin and mysql_declare_plugin_end there should + be a st_mysql_plugin struct for each plugin to be declared. +*/ + + +#ifndef MYSQL_DYNAMIC_PLUGIN +#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int PSIZE= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin DECLS[]= { +#else +#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]= { +#endif + +#define mysql_declare_plugin(NAME) \ +__MYSQL_DECLARE_PLUGIN(NAME, \ + builtin_ ## NAME ## _plugin_interface_version, \ + builtin_ ## NAME ## _sizeof_struct_st_plugin, \ + builtin_ ## NAME ## _plugin) + +#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0}} + +/* + declarations for SHOW STATUS support in plugins +*/ +enum enum_mysql_show_type +{ + SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG, + SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, + SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, + SHOW_always_last +}; + +struct st_mysql_show_var { + const char *name; + char *value; + enum enum_mysql_show_type type; +}; + +#define SHOW_VAR_FUNC_BUFF_SIZE 1024 +typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, char *); + + +/* + declarations for server variables and command line options +*/ + + +#define PLUGIN_VAR_BOOL 0x0001 +#define PLUGIN_VAR_INT 0x0002 +#define PLUGIN_VAR_LONG 0x0003 +#define PLUGIN_VAR_LONGLONG 0x0004 +#define PLUGIN_VAR_STR 0x0005 +#define PLUGIN_VAR_ENUM 0x0006 +#define PLUGIN_VAR_SET 0x0007 +#define PLUGIN_VAR_UNSIGNED 0x0080 +#define PLUGIN_VAR_THDLOCAL 0x0100 /* Variable is per-connection */ +#define PLUGIN_VAR_READONLY 0x0200 /* Server variable is read only */ +#define PLUGIN_VAR_NOSYSVAR 0x0400 /* Not a server variable */ +#define PLUGIN_VAR_NOCMDOPT 0x0800 /* Not a command line option */ +#define PLUGIN_VAR_NOCMDARG 0x1000 /* No argument for cmd line */ +#define PLUGIN_VAR_RQCMDARG 0x0000 /* Argument required for cmd line */ +#define PLUGIN_VAR_OPCMDARG 0x2000 /* Argument optional for cmd line */ +#define PLUGIN_VAR_MEMALLOC 0x8000 /* String needs memory allocated */ + +struct st_mysql_sys_var; +struct st_mysql_value; + +/* + SYNOPSIS + (*mysql_var_check_func)() + thd thread handle + var dynamic variable being altered + save pointer to temporary storage + value user provided value + RETURN + 0 user provided value is OK and the update func may be called. + any other value indicates error. + + This function should parse the user provided value and store in the + provided temporary storage any data as required by the update func. + There is sufficient space in the temporary storage to store a double. + Note that the update func may not be called if any other error occurs + so any memory allocated should be thread-local so that it may be freed + automatically at the end of the statement. +*/ + +typedef int (*mysql_var_check_func)(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value); + +/* + SYNOPSIS + (*mysql_var_update_func)() + thd thread handle + var dynamic variable being altered + var_ptr pointer to dynamic variable + save pointer to temporary storage + RETURN + NONE + + This function should use the validated value stored in the temporary store + and persist it in the provided pointer to the dynamic variable. + For example, strings may require memory to be allocated. +*/ +typedef void (*mysql_var_update_func)(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *var_ptr, const void *save); + + +/* the following declarations are for internal use only */ + + +#define PLUGIN_VAR_MASK \ + (PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | \ + PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_NOCMDARG | \ + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC) + +#define MYSQL_PLUGIN_VAR_HEADER \ + int flags; \ + const char *name; \ + const char *comment; \ + mysql_var_check_func check; \ + mysql_var_update_func update + +#define MYSQL_SYSVAR_NAME(name) mysql_sysvar_ ## name +#define MYSQL_SYSVAR(name) \ + ((struct st_mysql_sys_var *)&(MYSQL_SYSVAR_NAME(name))) + +/* + for global variables, the value pointer is the first + element after the header, the default value is the second. + for thread variables, the value offset is the first + element after the header, the default value is the second. +*/ + + +#define DECLARE_MYSQL_SYSVAR_BASIC(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; \ + const type def_val; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_SYSVAR_SIMPLE(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; type def_val; \ + type min_val; type max_val; \ + type blk_sz; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_SYSVAR_TYPELIB(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; type def_val; \ + TYPELIB *typelib; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_THDVAR_FUNC(type) \ + type *(*resolve)(MYSQL_THD thd, int offset) + +#define DECLARE_MYSQL_THDVAR_BASIC(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + const type def_val; \ + DECLARE_THDVAR_FUNC(type); \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_THDVAR_SIMPLE(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + type def_val; type min_val; \ + type max_val; type blk_sz; \ + DECLARE_THDVAR_FUNC(type); \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_THDVAR_TYPELIB(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + type def_val; \ + DECLARE_THDVAR_FUNC(type); \ + TYPELIB *typelib; \ +} MYSQL_SYSVAR_NAME(name) + + +/* + the following declarations are for use by plugin implementors +*/ + +#define MYSQL_SYSVAR_BOOL(name, varname, opt, comment, check, update, def) \ +DECLARE_MYSQL_SYSVAR_BASIC(name, char) = { \ + PLUGIN_VAR_BOOL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def} + +#define MYSQL_SYSVAR_STR(name, varname, opt, comment, check, update, def) \ +DECLARE_MYSQL_SYSVAR_BASIC(name, char *) = { \ + PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def} + +#define MYSQL_SYSVAR_INT(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, int) = { \ + PLUGIN_VAR_INT | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_UINT(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_LONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, long) = { \ + PLUGIN_VAR_LONG | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ULONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_LONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, long long) = { \ + PLUGIN_VAR_LONGLONG | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ULONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ENUM(name, varname, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long) = { \ + PLUGIN_VAR_ENUM | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, typelib } + +#define MYSQL_SYSVAR_SET(name, varname, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long long) = { \ + PLUGIN_VAR_SET | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, typelib } + +#define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ +DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ + PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL} + +#define MYSQL_THDVAR_STR(name, opt, comment, check, update, def) \ +DECLARE_MYSQL_THDVAR_BASIC(name, char *) = { \ + PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL} + +#define MYSQL_THDVAR_INT(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_UINT(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_LONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ULONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_LONGLONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ULONGLONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ENUM(name, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long) = { \ + PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL, typelib } + +#define MYSQL_THDVAR_SET(name, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long long) = { \ + PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL, typelib } + +/* accessor macros */ + +#define SYSVAR(name) \ + (*(MYSQL_SYSVAR_NAME(name).value)) + +/* when thd == null, result points to global value */ +#define THDVAR(thd, name) \ + (*(MYSQL_SYSVAR_NAME(name).resolve(thd, MYSQL_SYSVAR_NAME(name).offset))) + + +/* + Plugin description structure. +*/ + +struct st_mysql_plugin +{ + int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + void *info; /* pointer to type-specific plugin descriptor */ + const char *name; /* plugin name */ + const char *author; /* plugin author (for I_S.PLUGINS) */ + const char *descr; /* general descriptive text (for I_S.PLUGINS) */ + int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ + int (*init)(void *); /* the function to invoke when plugin is loaded */ + int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ + unsigned int version; /* plugin version (for I_S.PLUGINS) */ + struct st_mysql_show_var *status_vars; + struct st_mysql_sys_var **system_vars; + void * __reserved1; /* reserved for dependency checking */ +}; + +/************************************************************************* + API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) +*/ +#include "plugin_ftparser.h" + +/************************************************************************* + API for Storage Engine plugin. (MYSQL_DAEMON_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_daemon +{ + int interface_version; +}; + + +/************************************************************************* + API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_information_schema +{ + int interface_version; +}; + + +/************************************************************************* + API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_HANDLERTON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + The real API is in the sql/handler.h + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_storage_engine +{ + int interface_version; +}; + +struct handlerton; + + +/* + API for Replication plugin. (MYSQL_REPLICATION_PLUGIN) +*/ + #define MYSQL_REPLICATION_INTERFACE_VERSION 0x0100 + + /** + Replication plugin descriptor + */ + struct Mysql_replication { + int interface_version; + }; + +/************************************************************************* + st_mysql_value struct for reading values from mysqld. + Used by server variables framework to parse user-provided values. + Will be used for arguments when implementing UDFs. + + Note that val_str() returns a string in temporary memory + that will be freed at the end of statement. Copy the string + if you need it to persist. +*/ + +#define MYSQL_VALUE_TYPE_STRING 0 +#define MYSQL_VALUE_TYPE_REAL 1 +#define MYSQL_VALUE_TYPE_INT 2 + +struct st_mysql_value +{ + int (*value_type)(struct st_mysql_value *); + const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length); + int (*val_real)(struct st_mysql_value *, double *realbuf); + int (*val_int)(struct st_mysql_value *, long long *intbuf); + int (*is_unsigned)(struct st_mysql_value *); +}; + + +/************************************************************************* + Miscellaneous functions for plugin implementors +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +int thd_in_lock_tables(const MYSQL_THD thd); +int thd_tablespace_op(const MYSQL_THD thd); +long long thd_test_options(const MYSQL_THD thd, long long test_options); +int thd_sql_command(const MYSQL_THD thd); +const char *thd_proc_info(MYSQL_THD thd, const char *info); +void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton); +void thd_storage_lock_wait(MYSQL_THD thd, long long value); +int thd_tx_isolation(const MYSQL_THD thd); +char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, + unsigned int max_query_len); +/* Increments the row counter, see THD::row_count */ +void thd_inc_row_count(MYSQL_THD thd); + +/** + Create a temporary file. + + @details + The temporary file is created in a location specified by the mysql + server configuration (--tmpdir option). The caller does not need to + delete the file, it will be deleted automatically. + + @param prefix prefix for temporary file name + @retval -1 error + @retval >= 0 a file handle that can be passed to dup or my_close +*/ +int mysql_tmpfile(const char *prefix); + +/** + Check the killed state of a connection + + @details + In MySQL support for the KILL statement is cooperative. The KILL + statement only sets a "killed" flag. This function returns the value + of that flag. A thread should check it often, especially inside + time-consuming loops, and gracefully abort the operation if it is + non-zero. + + @param thd user thread connection handle + @retval 0 the connection is active + @retval 1 the connection has been killed +*/ +int thd_killed(const MYSQL_THD thd); + + +/** + Return the thread id of a user thread + + @param thd user thread connection handle + @return thread id +*/ +unsigned long thd_get_thread_id(const MYSQL_THD thd); + +/** + Get the XID for this connection's transaction + + @param thd user thread connection handle + @param xid location where identifier is stored +*/ +void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid); + +/** + Invalidate the query cache for a given table. + + @param thd user thread connection handle + @param key databasename\\0tablename\\0 + @param key_length length of key in bytes, including the NUL bytes + @param using_trx flag: TRUE if using transactions, FALSE otherwise +*/ +void mysql_query_cache_invalidate4(MYSQL_THD thd, + const char *key, unsigned int key_length, + int using_trx); + + +/** + Provide a handler data getter to simplify coding +*/ +void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton); + + +/** + Provide a handler data setter to simplify coding + + @details + Set ha_data pointer (storage engine per-connection information). + + To avoid unclean deactivation (uninstall) of storage engine plugin + in the middle of transaction, additional storage engine plugin + lock is acquired. + + If ha_data is not null and storage engine plugin was not locked + by thd_set_ha_data() in this connection before, storage engine + plugin gets locked. + + If ha_data is null and storage engine plugin was locked by + thd_set_ha_data() in this connection before, storage engine + plugin lock gets released. + + If handlerton::close_connection() didn't reset ha_data, server does + it immediately after calling handlerton::close_connection(). +*/ +void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, + const void *ha_data); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/code/meosdb/mysql55/plugin_audit.h b/code/meosdb/mysql55/plugin_audit.h new file mode 100644 index 0000000..f24913f --- /dev/null +++ b/code/meosdb/mysql55/plugin_audit.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2007 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_audit_h +#define _my_audit_h + +/************************************************************************* + API for Audit plugin. (MYSQL_AUDIT_PLUGIN) +*/ + +#include "plugin.h" + +#define MYSQL_AUDIT_CLASS_MASK_SIZE 1 + +#define MYSQL_AUDIT_INTERFACE_VERSION 0x0200 + +/* + The first word in every event class struct indicates the specific + class of the event. +*/ +struct mysql_event +{ + unsigned int event_class; +}; + + +/************************************************************************* + AUDIT CLASS : GENERAL + + LOG events occurs before emitting to the general query log. + ERROR events occur before transmitting errors to the user. + RESULT events occur after transmitting a resultset to the user. + STATUS events occur after transmitting a resultset or errors + to the user. +*/ + +#define MYSQL_AUDIT_GENERAL_CLASS 0 +#define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) +#define MYSQL_AUDIT_GENERAL_LOG 0 +#define MYSQL_AUDIT_GENERAL_ERROR 1 +#define MYSQL_AUDIT_GENERAL_RESULT 2 +#define MYSQL_AUDIT_GENERAL_STATUS 3 + +struct mysql_event_general +{ + unsigned int event_class; + unsigned int event_subclass; + int general_error_code; + unsigned long general_thread_id; + const char *general_user; + unsigned int general_user_length; + const char *general_command; + unsigned int general_command_length; + const char *general_query; + unsigned int general_query_length; + struct charset_info_st *general_charset; + unsigned long long general_time; + unsigned long long general_rows; +}; + + +/* + AUDIT CLASS : CONNECTION + + CONNECT occurs after authentication phase is completed. + DISCONNECT occurs after connection is terminated. + CHANGE_USER occurs after COM_CHANGE_USER RPC is completed. +*/ + +#define MYSQL_AUDIT_CONNECTION_CLASS 1 +#define MYSQL_AUDIT_CONNECTION_CLASSMASK (1 << MYSQL_AUDIT_CONNECTION_CLASS) +#define MYSQL_AUDIT_CONNECTION_CONNECT 0 +#define MYSQL_AUDIT_CONNECTION_DISCONNECT 1 +#define MYSQL_AUDIT_CONNECTION_CHANGE_USER 2 + +struct mysql_event_connection +{ + unsigned int event_class; + unsigned int event_subclass; + int status; + unsigned long thread_id; + const char *user; + unsigned int user_length; + const char *priv_user; + unsigned int priv_user_length; + const char *external_user; + unsigned int external_user_length; + const char *proxy_user; + unsigned int proxy_user_length; + const char *host; + unsigned int host_length; + const char *ip; + unsigned int ip_length; + const char *database; + unsigned int database_length; +}; + + +/************************************************************************* + Here we define the descriptor structure, that is referred from + st_mysql_plugin. + + release_thd() event occurs when the event class consumer is to be + disassociated from the specified THD. This would typically occur + before some operation which may require sleeping - such as when + waiting for the next query from the client. + + event_notify() is invoked whenever an event occurs which is of any + class for which the plugin has interest. The first word of the + mysql_event argument indicates the specific event class and the + remainder of the structure is as required for that class. + + class_mask is an array of bits used to indicate what event classes + that this plugin wants to receive. +*/ + +struct st_mysql_audit +{ + int interface_version; + void (*release_thd)(MYSQL_THD); + void (*event_notify)(MYSQL_THD, const struct mysql_event *); + unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; +}; + + +#endif diff --git a/code/meosdb/mysql55/plugin_ftparser.h b/code/meosdb/mysql55/plugin_ftparser.h new file mode 100644 index 0000000..9e3b7d1 --- /dev/null +++ b/code/meosdb/mysql55/plugin_ftparser.h @@ -0,0 +1,211 @@ +/* Copyright (C) 2005 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#ifndef _my_plugin_ftparser_h +#define _my_plugin_ftparser_h +#include "plugin.h" + +/************************************************************************* + API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) +*/ + +#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100 + +/* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */ +enum enum_ftparser_mode +{ +/* + Fast and simple mode. This mode is used for indexing, and natural + language queries. + + The parser is expected to return only those words that go into the + index. Stopwords or too short/long words should not be returned. The + 'boolean_info' argument of mysql_add_word() does not have to be set. +*/ + MYSQL_FTPARSER_SIMPLE_MODE= 0, + +/* + Parse with stopwords mode. This mode is used in boolean searches for + "phrase matching." + + The parser is not allowed to ignore words in this mode. Every word + should be returned, including stopwords and words that are too short + or long. The 'boolean_info' argument of mysql_add_word() does not + have to be set. +*/ + MYSQL_FTPARSER_WITH_STOPWORDS= 1, + +/* + Parse in boolean mode. This mode is used to parse a boolean query string. + + The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO + structure in the 'boolean_info' argument to mysql_add_word(). + Usually that means that the parser should recognize boolean operators + in the parsing stream and set appropriate fields in + MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As for + MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored. + Instead, use FT_TOKEN_STOPWORD for the token type of such a word. +*/ + MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 +}; + +/* + Token types for boolean mode searching (used for the type member of + MYSQL_FTPARSER_BOOLEAN_INFO struct) + + FT_TOKEN_EOF: End of data. + FT_TOKEN_WORD: Regular word. + FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression). + FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression). + FT_TOKEN_STOPWORD: Stopword. +*/ + +enum enum_ft_token_type +{ + FT_TOKEN_EOF= 0, + FT_TOKEN_WORD= 1, + FT_TOKEN_LEFT_PAREN= 2, + FT_TOKEN_RIGHT_PAREN= 3, + FT_TOKEN_STOPWORD= 4 +}; + +/* + This structure is used in boolean search mode only. It conveys + boolean-mode metadata to the MySQL search engine for every word in + the search query. A valid instance of this structure must be filled + in by the plugin parser and passed as an argument in the call to + mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM + structure) when a query is parsed in boolean mode. + + type: The token type. Should be one of the enum_ft_token_type values. + + yesno: Whether the word must be present for a match to occur: + >0 Must be present + <0 Must not be present + 0 Neither; the word is optional but its presence increases the relevance + With the default settings of the ft_boolean_syntax system variable, + >0 corresponds to the '+' operator, <0 corrresponds to the '-' operator, + and 0 means neither operator was used. + + weight_adjust: A weighting factor that determines how much a match + for the word counts. Positive values increase, negative - decrease the + relative word's importance in the query. + + wasign: The sign of the word's weight in the query. If it's non-negative + the match for the word will increase document relevance, if it's + negative - decrease (the word becomes a "noise word", the less of it the + better). + + trunc: Corresponds to the '*' operator in the default setting of the + ft_boolean_syntax system variable. +*/ + +typedef struct st_mysql_ftparser_boolean_info +{ + enum enum_ft_token_type type; + int yesno; + int weight_adjust; + char wasign; + char trunc; + /* These are parser state and must be removed. */ + char prev; + char *quot; +} MYSQL_FTPARSER_BOOLEAN_INFO; + +/* + The following flag means that buffer with a string (document, word) + may be overwritten by the caller before the end of the parsing (that is + before st_mysql_ftparser::deinit() call). If one needs the string + to survive between two successive calls of the parsing function, she + needs to save a copy of it. The flag may be set by MySQL before calling + st_mysql_ftparser::parse(), or it may be set by a plugin before calling + st_mysql_ftparser_param::mysql_parse() or + st_mysql_ftparser_param::mysql_add_word(). +*/ +#define MYSQL_FTFLAGS_NEED_COPY 1 + +/* + An argument of the full-text parser plugin. This structure is + filled in by MySQL server and passed to the parsing function of the + plugin as an in/out parameter. + + mysql_parse: A pointer to the built-in parser implementation of the + server. It's set by the server and can be used by the parser plugin + to invoke the MySQL default parser. If plugin's role is to extract + textual data from .doc, .pdf or .xml content, it might extract + plaintext from the content, and then pass the text to the default + MySQL parser to be parsed. + + mysql_add_word: A server callback to add a new word. When parsing + a document, the server sets this to point at a function that adds + the word to MySQL full-text index. When parsing a search query, + this function will add the new word to the list of words to search + for. The boolean_info argument can be NULL for all cases except + when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO. + + ftparser_state: A generic pointer. The plugin can set it to point + to information to be used internally for its own purposes. + + mysql_ftparam: This is set by the server. It is used by MySQL functions + called via mysql_parse() and mysql_add_word() callback. The plugin + should not modify it. + + cs: Information about the character set of the document or query string. + + doc: A pointer to the document or query string to be parsed. + + length: Length of the document or query string, in bytes. + + flags: See MYSQL_FTFLAGS_* constants above. + + mode: The parsing mode. With boolean operators, with stopwords, or + nothing. See enum_ftparser_mode above. +*/ + +typedef struct st_mysql_ftparser_param +{ + int (*mysql_parse)(struct st_mysql_ftparser_param *, + char *doc, int doc_len); + int (*mysql_add_word)(struct st_mysql_ftparser_param *, + char *word, int word_len, + MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); + void *ftparser_state; + void *mysql_ftparam; + struct charset_info_st *cs; + char *doc; + int length; + int flags; + enum enum_ftparser_mode mode; +} MYSQL_FTPARSER_PARAM; + +/* + Full-text parser descriptor. + + interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION. + The parsing, initialization, and deinitialization functions are + invoked per SQL statement for which the parser is used. +*/ + +struct st_mysql_ftparser +{ + int interface_version; + int (*parse)(MYSQL_FTPARSER_PARAM *param); + int (*init)(MYSQL_FTPARSER_PARAM *param); + int (*deinit)(MYSQL_FTPARSER_PARAM *param); +}; + + +#endif + diff --git a/code/meosdb/mysql55/sql_common.h b/code/meosdb/mysql55/sql_common.h new file mode 100644 index 0000000..b7772f3 --- /dev/null +++ b/code/meosdb/mysql55/sql_common.h @@ -0,0 +1,113 @@ +#ifndef SQL_COMMON_INCLUDED +#define SQL_COMMON_INCLUDED + +/* Copyright (C) 2003-2004, 2006 MySQL AB + + 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; version 2 of the License. + + 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 */ + +#define SQL_COMMON_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const char *unknown_sqlstate; +extern const char *cant_connect_sqlstate; +extern const char *not_error_sqlstate; + +struct st_mysql_options_extention { + char *plugin_dir; + char *default_auth; +}; + +typedef struct st_mysql_methods +{ + my_bool (*read_query_result)(MYSQL *mysql); + my_bool (*advanced_command)(MYSQL *mysql, + enum enum_server_command command, + const unsigned char *header, + unsigned long header_length, + const unsigned char *arg, + unsigned long arg_length, + my_bool skip_check, + MYSQL_STMT *stmt); + MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + unsigned int fields); + MYSQL_RES * (*use_result)(MYSQL *mysql); + void (*fetch_lengths)(unsigned long *to, + MYSQL_ROW column, unsigned int field_count); + void (*flush_use_result)(MYSQL *mysql, my_bool flush_all_results); + int (*read_change_user_result)(MYSQL *mysql); +#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) + MYSQL_FIELD * (*list_fields)(MYSQL *mysql); + my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt); + int (*stmt_execute)(MYSQL_STMT *stmt); + int (*read_binary_rows)(MYSQL_STMT *stmt); + int (*unbuffered_fetch)(MYSQL *mysql, char **row); + void (*free_embedded_thd)(MYSQL *mysql); + const char *(*read_statistics)(MYSQL *mysql); + my_bool (*next_result)(MYSQL *mysql); + int (*read_rows_from_cursor)(MYSQL_STMT *stmt); +#endif +} MYSQL_METHODS; + +#define simple_command(mysql, command, arg, length, skip_check) \ + (*(mysql)->methods->advanced_command)(mysql, command, 0, \ + 0, arg, length, skip_check, NULL) +#define stmt_command(mysql, command, arg, length, stmt) \ + (*(mysql)->methods->advanced_command)(mysql, command, 0, \ + 0, arg, length, 1, stmt) + +extern CHARSET_INFO *default_client_charset_info; +MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, + my_bool default_value, uint server_capabilities); +void free_rows(MYSQL_DATA *cur); +void free_old_query(MYSQL *mysql); +void end_server(MYSQL *mysql); +my_bool mysql_reconnect(MYSQL *mysql); +void mysql_read_default_options(struct st_mysql_options *options, + const char *filename,const char *group); +my_bool +cli_advanced_command(MYSQL *mysql, enum enum_server_command command, + const unsigned char *header, ulong header_length, + const unsigned char *arg, ulong arg_length, + my_bool skip_check, MYSQL_STMT *stmt); +unsigned long cli_safe_read(MYSQL *mysql); +void net_clear_error(NET *net); +void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net); +void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate, + const char *err); +void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); +void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate, + const char *format, ...); + +/* client side of the pluggable authentication */ +struct st_plugin_vio_info; +void mpvio_info(Vio *vio, struct st_plugin_vio_info *info); +int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, + const char *data_plugin, const char *db); +int mysql_client_plugin_init(); +void mysql_client_plugin_deinit(); +struct st_mysql_client_plugin; +extern struct st_mysql_client_plugin *mysql_client_builtins[]; + +#ifdef __cplusplus +} +#endif + +#define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41) + +#endif /* SQL_COMMON_INCLUDED */ diff --git a/code/meosdb/mysql55/sql_state.h b/code/meosdb/mysql55/sql_state.h new file mode 100644 index 0000000..0d73be4 --- /dev/null +++ b/code/meosdb/mysql55/sql_state.h @@ -0,0 +1,220 @@ +/* Autogenerated file, please don't edit */ + +{ ER_DUP_KEY ,"23000", "" }, +{ ER_OUTOFMEMORY ,"HY001", "S1001" }, +{ ER_OUT_OF_SORTMEMORY ,"HY001", "S1001" }, +{ ER_CON_COUNT_ERROR ,"08004", "" }, +{ ER_BAD_HOST_ERROR ,"08S01", "" }, +{ ER_HANDSHAKE_ERROR ,"08S01", "" }, +{ ER_DBACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_ACCESS_DENIED_ERROR ,"28000", "" }, +{ ER_NO_DB_ERROR ,"3D000", "" }, +{ ER_UNKNOWN_COM_ERROR ,"08S01", "" }, +{ ER_BAD_NULL_ERROR ,"23000", "" }, +{ ER_BAD_DB_ERROR ,"42000", "" }, +{ ER_TABLE_EXISTS_ERROR ,"42S01", "" }, +{ ER_BAD_TABLE_ERROR ,"42S02", "" }, +{ ER_NON_UNIQ_ERROR ,"23000", "" }, +{ ER_SERVER_SHUTDOWN ,"08S01", "" }, +{ ER_BAD_FIELD_ERROR ,"42S22", "S0022" }, +{ ER_WRONG_FIELD_WITH_GROUP ,"42000", "S1009" }, +{ ER_WRONG_GROUP_FIELD ,"42000", "S1009" }, +{ ER_WRONG_SUM_SELECT ,"42000", "S1009" }, +{ ER_WRONG_VALUE_COUNT ,"21S01", "" }, +{ ER_TOO_LONG_IDENT ,"42000", "S1009" }, +{ ER_DUP_FIELDNAME ,"42S21", "S1009" }, +{ ER_DUP_KEYNAME ,"42000", "S1009" }, +{ ER_DUP_ENTRY ,"23000", "S1009" }, +{ ER_WRONG_FIELD_SPEC ,"42000", "S1009" }, +{ ER_PARSE_ERROR ,"42000", "s1009" }, +{ ER_EMPTY_QUERY ,"42000", "" }, +{ ER_NONUNIQ_TABLE ,"42000", "S1009" }, +{ ER_INVALID_DEFAULT ,"42000", "S1009" }, +{ ER_MULTIPLE_PRI_KEY ,"42000", "S1009" }, +{ ER_TOO_MANY_KEYS ,"42000", "S1009" }, +{ ER_TOO_MANY_KEY_PARTS ,"42000", "S1009" }, +{ ER_TOO_LONG_KEY ,"42000", "S1009" }, +{ ER_KEY_COLUMN_DOES_NOT_EXITS ,"42000", "S1009" }, +{ ER_BLOB_USED_AS_KEY ,"42000", "S1009" }, +{ ER_TOO_BIG_FIELDLENGTH ,"42000", "S1009" }, +{ ER_WRONG_AUTO_KEY ,"42000", "S1009" }, +{ ER_FORCING_CLOSE ,"08S01", "" }, +{ ER_IPSOCK_ERROR ,"08S01", "" }, +{ ER_NO_SUCH_INDEX ,"42S12", "S1009" }, +{ ER_WRONG_FIELD_TERMINATORS ,"42000", "S1009" }, +{ ER_BLOBS_AND_NO_TERMINATED ,"42000", "S1009" }, +{ ER_CANT_REMOVE_ALL_FIELDS ,"42000", "" }, +{ ER_CANT_DROP_FIELD_OR_KEY ,"42000", "" }, +{ ER_BLOB_CANT_HAVE_DEFAULT ,"42000", "" }, +{ ER_WRONG_DB_NAME ,"42000", "" }, +{ ER_WRONG_TABLE_NAME ,"42000", "" }, +{ ER_TOO_BIG_SELECT ,"42000", "" }, +{ ER_UNKNOWN_PROCEDURE ,"42000", "" }, +{ ER_WRONG_PARAMCOUNT_TO_PROCEDURE ,"42000", "" }, +{ ER_UNKNOWN_TABLE ,"42S02", "" }, +{ ER_FIELD_SPECIFIED_TWICE ,"42000", "" }, +{ ER_UNSUPPORTED_EXTENSION ,"42000", "" }, +{ ER_TABLE_MUST_HAVE_COLUMNS ,"42000", "" }, +{ ER_UNKNOWN_CHARACTER_SET ,"42000", "" }, +{ ER_TOO_BIG_ROWSIZE ,"42000", "" }, +{ ER_WRONG_OUTER_JOIN ,"42000", "" }, +{ ER_NULL_COLUMN_IN_INDEX ,"42000", "" }, +{ ER_PASSWORD_ANONYMOUS_USER ,"42000", "" }, +{ ER_PASSWORD_NOT_ALLOWED ,"42000", "" }, +{ ER_PASSWORD_NO_MATCH ,"42000", "" }, +{ ER_WRONG_VALUE_COUNT_ON_ROW ,"21S01", "" }, +{ ER_INVALID_USE_OF_NULL ,"22004", "" }, +{ ER_REGEXP_ERROR ,"42000", "" }, +{ ER_MIX_OF_GROUP_FUNC_AND_FIELDS ,"42000", "" }, +{ ER_NONEXISTING_GRANT ,"42000", "" }, +{ ER_TABLEACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_COLUMNACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_ILLEGAL_GRANT_FOR_TABLE ,"42000", "" }, +{ ER_GRANT_WRONG_HOST_OR_USER ,"42000", "" }, +{ ER_NO_SUCH_TABLE ,"42S02", "" }, +{ ER_NONEXISTING_TABLE_GRANT ,"42000", "" }, +{ ER_NOT_ALLOWED_COMMAND ,"42000", "" }, +{ ER_SYNTAX_ERROR ,"42000", "" }, +{ ER_ABORTING_CONNECTION ,"08S01", "" }, +{ ER_NET_PACKET_TOO_LARGE ,"08S01", "" }, +{ ER_NET_READ_ERROR_FROM_PIPE ,"08S01", "" }, +{ ER_NET_FCNTL_ERROR ,"08S01", "" }, +{ ER_NET_PACKETS_OUT_OF_ORDER ,"08S01", "" }, +{ ER_NET_UNCOMPRESS_ERROR ,"08S01", "" }, +{ ER_NET_READ_ERROR ,"08S01", "" }, +{ ER_NET_READ_INTERRUPTED ,"08S01", "" }, +{ ER_NET_ERROR_ON_WRITE ,"08S01", "" }, +{ ER_NET_WRITE_INTERRUPTED ,"08S01", "" }, +{ ER_TOO_LONG_STRING ,"42000", "" }, +{ ER_TABLE_CANT_HANDLE_BLOB ,"42000", "" }, +{ ER_TABLE_CANT_HANDLE_AUTO_INCREMENT ,"42000", "" }, +{ ER_WRONG_COLUMN_NAME ,"42000", "" }, +{ ER_WRONG_KEY_COLUMN ,"42000", "" }, +{ ER_DUP_UNIQUE ,"23000", "" }, +{ ER_BLOB_KEY_WITHOUT_LENGTH ,"42000", "" }, +{ ER_PRIMARY_CANT_HAVE_NULL ,"42000", "" }, +{ ER_TOO_MANY_ROWS ,"42000", "" }, +{ ER_REQUIRES_PRIMARY_KEY ,"42000", "" }, +{ ER_KEY_DOES_NOT_EXITS ,"42000", "S1009" }, +{ ER_CHECK_NO_SUCH_TABLE ,"42000", "" }, +{ ER_CHECK_NOT_IMPLEMENTED ,"42000", "" }, +{ ER_CANT_DO_THIS_DURING_AN_TRANSACTION ,"25000", "" }, +{ ER_NEW_ABORTING_CONNECTION ,"08S01", "" }, +{ ER_MASTER_NET_READ ,"08S01", "" }, +{ ER_MASTER_NET_WRITE ,"08S01", "" }, +{ ER_TOO_MANY_USER_CONNECTIONS ,"42000", "" }, +{ ER_READ_ONLY_TRANSACTION ,"25000", "" }, +{ ER_NO_PERMISSION_TO_CREATE_USER ,"42000", "" }, +{ ER_LOCK_DEADLOCK ,"40001", "" }, +{ ER_NO_REFERENCED_ROW ,"23000", "" }, +{ ER_ROW_IS_REFERENCED ,"23000", "" }, +{ ER_CONNECT_TO_MASTER ,"08S01", "" }, +{ ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT ,"21000", "" }, +{ ER_USER_LIMIT_REACHED ,"42000", "" }, +{ ER_SPECIFIC_ACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_NO_DEFAULT ,"42000", "" }, +{ ER_WRONG_VALUE_FOR_VAR ,"42000", "" }, +{ ER_WRONG_TYPE_FOR_VAR ,"42000", "" }, +{ ER_CANT_USE_OPTION_HERE ,"42000", "" }, +{ ER_NOT_SUPPORTED_YET ,"42000", "" }, +{ ER_WRONG_FK_DEF ,"42000", "" }, +{ ER_OPERAND_COLUMNS ,"21000", "" }, +{ ER_SUBQUERY_NO_1_ROW ,"21000", "" }, +{ ER_ILLEGAL_REFERENCE ,"42S22", "" }, +{ ER_DERIVED_MUST_HAVE_ALIAS ,"42000", "" }, +{ ER_SELECT_REDUCED ,"01000", "" }, +{ ER_TABLENAME_NOT_ALLOWED_HERE ,"42000", "" }, +{ ER_NOT_SUPPORTED_AUTH_MODE ,"08004", "" }, +{ ER_SPATIAL_CANT_HAVE_NULL ,"42000", "" }, +{ ER_COLLATION_CHARSET_MISMATCH ,"42000", "" }, +{ ER_WARN_TOO_FEW_RECORDS ,"01000", "" }, +{ ER_WARN_TOO_MANY_RECORDS ,"01000", "" }, +{ ER_WARN_NULL_TO_NOTNULL ,"22004", "" }, +{ ER_WARN_DATA_OUT_OF_RANGE ,"22003", "" }, +{ WARN_DATA_TRUNCATED ,"01000", "" }, +{ ER_WRONG_NAME_FOR_INDEX ,"42000", "" }, +{ ER_WRONG_NAME_FOR_CATALOG ,"42000", "" }, +{ ER_UNKNOWN_STORAGE_ENGINE ,"42000", "" }, +{ ER_TRUNCATED_WRONG_VALUE ,"22007", "" }, +{ ER_SP_NO_RECURSIVE_CREATE ,"2F003", "" }, +{ ER_SP_ALREADY_EXISTS ,"42000", "" }, +{ ER_SP_DOES_NOT_EXIST ,"42000", "" }, +{ ER_SP_LILABEL_MISMATCH ,"42000", "" }, +{ ER_SP_LABEL_REDEFINE ,"42000", "" }, +{ ER_SP_LABEL_MISMATCH ,"42000", "" }, +{ ER_SP_UNINIT_VAR ,"01000", "" }, +{ ER_SP_BADSELECT ,"0A000", "" }, +{ ER_SP_BADRETURN ,"42000", "" }, +{ ER_SP_BADSTATEMENT ,"0A000", "" }, +{ ER_UPDATE_LOG_DEPRECATED_IGNORED ,"42000", "" }, +{ ER_UPDATE_LOG_DEPRECATED_TRANSLATED ,"42000", "" }, +{ ER_QUERY_INTERRUPTED ,"70100", "" }, +{ ER_SP_WRONG_NO_OF_ARGS ,"42000", "" }, +{ ER_SP_COND_MISMATCH ,"42000", "" }, +{ ER_SP_NORETURN ,"42000", "" }, +{ ER_SP_NORETURNEND ,"2F005", "" }, +{ ER_SP_BAD_CURSOR_QUERY ,"42000", "" }, +{ ER_SP_BAD_CURSOR_SELECT ,"42000", "" }, +{ ER_SP_CURSOR_MISMATCH ,"42000", "" }, +{ ER_SP_CURSOR_ALREADY_OPEN ,"24000", "" }, +{ ER_SP_CURSOR_NOT_OPEN ,"24000", "" }, +{ ER_SP_UNDECLARED_VAR ,"42000", "" }, +{ ER_SP_FETCH_NO_DATA ,"02000", "" }, +{ ER_SP_DUP_PARAM ,"42000", "" }, +{ ER_SP_DUP_VAR ,"42000", "" }, +{ ER_SP_DUP_COND ,"42000", "" }, +{ ER_SP_DUP_CURS ,"42000", "" }, +{ ER_SP_SUBSELECT_NYI ,"0A000", "" }, +{ ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG ,"0A000", "" }, +{ ER_SP_VARCOND_AFTER_CURSHNDLR ,"42000", "" }, +{ ER_SP_CURSOR_AFTER_HANDLER ,"42000", "" }, +{ ER_SP_CASE_NOT_FOUND ,"20000", "" }, +{ ER_DIVISION_BY_ZERO ,"22012", "" }, +{ ER_ILLEGAL_VALUE_FOR_TYPE ,"22007", "" }, +{ ER_PROCACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_XAER_NOTA ,"XAE04", "" }, +{ ER_XAER_INVAL ,"XAE05", "" }, +{ ER_XAER_RMFAIL ,"XAE07", "" }, +{ ER_XAER_OUTSIDE ,"XAE09", "" }, +{ ER_XAER_RMERR ,"XAE03", "" }, +{ ER_XA_RBROLLBACK ,"XA100", "" }, +{ ER_NONEXISTING_PROC_GRANT ,"42000", "" }, +{ ER_DATA_TOO_LONG ,"22001", "" }, +{ ER_SP_BAD_SQLSTATE ,"42000", "" }, +{ ER_CANT_CREATE_USER_WITH_GRANT ,"42000", "" }, +{ ER_SP_DUP_HANDLER ,"42000", "" }, +{ ER_SP_NOT_VAR_ARG ,"42000", "" }, +{ ER_SP_NO_RETSET ,"0A000", "" }, +{ ER_CANT_CREATE_GEOMETRY_OBJECT ,"22003", "" }, +{ ER_TOO_BIG_SCALE ,"42000", "S1009" }, +{ ER_TOO_BIG_PRECISION ,"42000", "S1009" }, +{ ER_M_BIGGER_THAN_D ,"42000", "S1009" }, +{ ER_TOO_LONG_BODY ,"42000", "S1009" }, +{ ER_TOO_BIG_DISPLAYWIDTH ,"42000", "S1009" }, +{ ER_XAER_DUPID ,"XAE08", "" }, +{ ER_DATETIME_FUNCTION_OVERFLOW ,"22008", "" }, +{ ER_ROW_IS_REFERENCED_2 ,"23000", "" }, +{ ER_NO_REFERENCED_ROW_2 ,"23000", "" }, +{ ER_SP_BAD_VAR_SHADOW ,"42000", "" }, +{ ER_SP_WRONG_NAME ,"42000", "" }, +{ ER_SP_NO_AGGREGATE ,"42000", "" }, +{ ER_MAX_PREPARED_STMT_COUNT_REACHED ,"42000", "" }, +{ ER_NON_GROUPING_FIELD_USED ,"42000", "" }, +{ ER_FOREIGN_DUPLICATE_KEY ,"23000", "S1009" }, +{ ER_CANT_CHANGE_TX_ISOLATION ,"25001", "" }, +{ ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT ,"42000", "" }, +{ ER_WRONG_PARAMETERS_TO_NATIVE_FCT ,"42000", "" }, +{ ER_WRONG_PARAMETERS_TO_STORED_FCT ,"42000", "" }, +{ ER_DUP_ENTRY_WITH_KEY_NAME ,"23000", "S1009" }, +{ ER_XA_RBTIMEOUT ,"XA106", "" }, +{ ER_XA_RBDEADLOCK ,"XA102", "" }, +{ ER_FUNC_INEXISTENT_NAME_COLLISION ,"42000", "" }, +{ ER_DUP_SIGNAL_SET ,"42000", "" }, +{ ER_SIGNAL_WARN ,"01000", "" }, +{ ER_SIGNAL_NOT_FOUND ,"02000", "" }, +{ ER_SIGNAL_EXCEPTION ,"HY000", "" }, +{ ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER ,"0K000", "" }, +{ ER_SPATIAL_MUST_HAVE_GEOM_COL ,"42000", "" }, +{ ER_DATA_OUT_OF_RANGE ,"22003", "" }, +{ ER_ACCESS_DENIED_NO_PASSWORD_ERROR ,"28000", "" }, +{ ER_TRUNCATE_ILLEGAL_FK ,"42000", "" }, diff --git a/code/meosdb/mysql55/sslopt-case.h b/code/meosdb/mysql55/sslopt-case.h new file mode 100644 index 0000000..4ab7fcf --- /dev/null +++ b/code/meosdb/mysql55/sslopt-case.h @@ -0,0 +1,32 @@ +#ifndef SSLOPT_CASE_INCLUDED +#define SSLOPT_CASE_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + case OPT_SSL_KEY: + case OPT_SSL_CERT: + case OPT_SSL_CA: + case OPT_SSL_CAPATH: + case OPT_SSL_CIPHER: + /* + Enable use of SSL if we are using any ssl option + One can disable SSL later by using --skip-ssl or --ssl=0 + */ + opt_use_ssl= 1; + break; +#endif +#endif /* SSLOPT_CASE_INCLUDED */ diff --git a/code/meosdb/mysql55/sslopt-longopts.h b/code/meosdb/mysql55/sslopt-longopts.h new file mode 100644 index 0000000..75c5ab7 --- /dev/null +++ b/code/meosdb/mysql55/sslopt-longopts.h @@ -0,0 +1,49 @@ +#ifndef SSLOPT_LONGOPTS_INCLUDED +#define SSLOPT_LONGOPTS_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + + {"ssl", OPT_SSL_SSL, + "Enable SSL for connection (automatically enabled with other flags).", + &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"ssl-ca", OPT_SSL_CA, + "CA file in PEM format (check OpenSSL docs, implies --ssl).", + &opt_ssl_ca, &opt_ssl_ca, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-capath", OPT_SSL_CAPATH, + "CA directory (check OpenSSL docs, implies --ssl).", + &opt_ssl_capath, &opt_ssl_capath, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).", + &opt_ssl_cert, &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).", + &opt_ssl_cipher, &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).", + &opt_ssl_key, &opt_ssl_key, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, +#ifdef MYSQL_CLIENT + {"ssl-verify-server-cert", OPT_SSL_VERIFY_SERVER_CERT, + "Verify server's \"Common Name\" in its cert against hostname used " + "when connecting. This option is disabled by default.", + &opt_ssl_verify_server_cert, &opt_ssl_verify_server_cert, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif +#endif /* HAVE_OPENSSL */ +#endif /* SSLOPT_LONGOPTS_INCLUDED */ diff --git a/code/meosdb/mysql55/sslopt-vars.h b/code/meosdb/mysql55/sslopt-vars.h new file mode 100644 index 0000000..1f2fc47 --- /dev/null +++ b/code/meosdb/mysql55/sslopt-vars.h @@ -0,0 +1,35 @@ +#ifndef SSLOPT_VARS_INCLUDED +#define SSLOPT_VARS_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) +#ifdef SSL_VARS_NOT_STATIC +#define SSL_STATIC +#else +#define SSL_STATIC static +#endif +SSL_STATIC my_bool opt_use_ssl = 0; +SSL_STATIC char *opt_ssl_ca = 0; +SSL_STATIC char *opt_ssl_capath = 0; +SSL_STATIC char *opt_ssl_cert = 0; +SSL_STATIC char *opt_ssl_cipher = 0; +SSL_STATIC char *opt_ssl_key = 0; +#ifdef MYSQL_CLIENT +SSL_STATIC my_bool opt_ssl_verify_server_cert= 0; +#endif +#endif +#endif /* SSLOPT_VARS_INCLUDED */ diff --git a/code/meosdb/mysql55/typelib.h b/code/meosdb/mysql55/typelib.h new file mode 100644 index 0000000..9adb8bb --- /dev/null +++ b/code/meosdb/mysql55/typelib.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2000 MySQL AB + + 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; version 2 of the License. + + 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 */ + + +#ifndef _typelib_h +#define _typelib_h + +#include "my_alloc.h" + +typedef struct st_typelib { /* Different types saved here */ + unsigned int count; /* How many types */ + const char *name; /* Name of typelib */ + const char **type_names; + unsigned int *type_lengths; +} TYPELIB; + +extern my_ulonglong find_typeset(char *x, TYPELIB *typelib,int *error_position); +extern int find_type_or_exit(const char *x, TYPELIB *typelib, + const char *option); +extern int find_type(char *x, const TYPELIB *typelib, unsigned int full_name); +extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); +extern const char *get_type(TYPELIB *typelib,unsigned int nr); +extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from); + +extern TYPELIB sql_protocol_typelib; + +my_ulonglong find_set_from_flags(const TYPELIB *lib, unsigned int default_name, + my_ulonglong cur_set, my_ulonglong default_set, + const char *str, unsigned int length, + char **err_pos, unsigned int *err_len); + +#endif /* _typelib_h */ diff --git a/code/meosdb/sqltypes.h b/code/meosdb/sqltypes.h new file mode 100644 index 0000000..7b4fd4a --- /dev/null +++ b/code/meosdb/sqltypes.h @@ -0,0 +1,59 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +enum OpFailStatus { + opStatusOK = 2, + opStatusFail = 0, + opStatusWarning = 1, + opUnreachable = -1, +}; + +#ifndef BUILD_DB_DLL + +class oEvent; +class oBase; + +extern "C"{ + +#define MEOSDB_API + int MEOSDB_API getMeosVersion(); + bool MEOSDB_API msSynchronizeList(oEvent *, int lid); + int MEOSDB_API msSynchronizeUpdate(oBase *); + int MEOSDB_API msSynchronizeRead(oBase *obj); + int MEOSDB_API msRemove(oBase *obj); + int MEOSDB_API msMonitor(oEvent *oe); + int MEOSDB_API msUploadRunnerDB(oEvent *oe); + int MEOSDB_API msOpenDatabase(oEvent *oe); + int MEOSDB_API msDropDatabase(oEvent *oe); + int MEOSDB_API msConnectToServer(oEvent *oe); + bool MEOSDB_API msGetErrorState(char *msgBuff); + bool MEOSDB_API msResetConnection(); + bool MEOSDB_API msReConnect(); + int MEOSDB_API msListCompetitions(oEvent *oe); + + int getListMask(oEvent &oe); +} + +bool repairTables(const string &db, vector &output); + +#endif diff --git a/code/meosdb/stdafx.cpp b/code/meosdb/stdafx.cpp new file mode 100644 index 0000000..2b8d0d9 --- /dev/null +++ b/code/meosdb/stdafx.cpp @@ -0,0 +1,14 @@ +// stdafx.cpp : source file that includes just the standard includes +// meosdb.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +const string _NoClub="Klubblös"; +const string _EmptyString=""; +const string _VacantName="Vakant"; +const string _UnkownName="N.N."; + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file + \ No newline at end of file diff --git a/code/meosdb/stdafx.h b/code/meosdb/stdafx.h new file mode 100644 index 0000000..87f2eec --- /dev/null +++ b/code/meosdb/stdafx.h @@ -0,0 +1,29 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define NOMINMAX +// Windows Header Files: +#include +#include + +#include +#include +#include +using namespace std; + +bool GetUserFile(char *file, const char *in); + +// TODO: reference additional headers your program requires here + +const extern string _EmptyString; +const extern string _VacantName; +const extern string _UnkownName; + diff --git a/code/meosdb/targetver.h b/code/meosdb/targetver.h new file mode 100644 index 0000000..274dae1 --- /dev/null +++ b/code/meosdb/targetver.h @@ -0,0 +1,48 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. +#endif diff --git a/code/meosexception.h b/code/meosexception.h new file mode 100644 index 0000000..210d81d --- /dev/null +++ b/code/meosexception.h @@ -0,0 +1,31 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class meosException : public std::exception { +public: + meosException(const string &msg) : std::exception(msg.c_str()) {} + meosException(const char *msg) : std::exception(msg) {} + meosException() : std::exception() {} +}; + diff --git a/code/meoslang.rc b/code/meoslang.rc new file mode 100644 index 0000000..1ceab78 --- /dev/null +++ b/code/meoslang.rc @@ -0,0 +1,19 @@ +#define IDR_3001 103 +#define IDR_3002 104 +#define IDR_3003 105 +#define IDR_3004 106 +#define IDR_3005 107 +#define IDR_3006 108 +#define IDR_3007 109 +#define IDR_3008 110 + +IDR_3001 300 DISCARDABLE "swedish.lng" +IDR_3002 300 DISCARDABLE "english.lng" +IDR_3003 300 DISCARDABLE "german.lng" +IDR_3004 300 DISCARDABLE "danish.lng" +IDR_3005 300 DISCARDABLE "russian.lng" +IDR_3006 300 DISCARDABLE "cp1250.lng" +IDR_3007 300 DISCARDABLE "cp1255.lng" +IDR_3008 300 DISCARDABLE "french.lng" +///////////////////////////////////////////////////////////////////////////// + diff --git a/code/meosvc15.vcxproj b/code/meosvc15.vcxproj new file mode 100644 index 0000000..5346b81 --- /dev/null +++ b/code/meosvc15.vcxproj @@ -0,0 +1,477 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + test + Win32 + + + + {B854EF2A-2BB7-4D62-B08B-96BD64B347E8} + meos + 8.1 + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + true + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Release\ + .\Release\ + false + .\Debug\ + .\Debug\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + meos + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/meos.tlb + + + + + MaxSpeed + AnySuitable + Speed + meosdb/mysql++;meosdb/mysql50;libharu;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Use + stdafx.h + .\Release/meos.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x041d + + + Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat.lib;mysqlpp.lib;libhpdf.lib;%(AdditionalDependencies) + .\Release/meos.exe + true + ./lib;%(AdditionalLibraryDirectories) + .\Release/meos.pdb + Windows + false + + + MachineX86 + true + + + true + .\Release/meos.bsc + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/meos.tlb + + + + + Disabled + meosdb/mysql++;libharu;meosdb/mysql50;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + NotSet + Use + stdafx.h + .\Debug/meos.pch + .\Debug/ + .\Debug/ + .\Debug/ + true + TurnOffAllWarnings + true + EditAndContinue + 4996;4100;4244;4245;4702;4389;4127;4201;%(DisableSpecificWarnings) + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat.lib;mysqlpp_vc15.lib;libhpdf.lib;%(AdditionalDependencies) + .\Debug/meos.exe + true + ./lib_db;%(AdditionalLibraryDirectories) + true + .\Debug/meos.pdb + Windows + false + + + MachineX86 + /FORCE:MULTIPLE %(AdditionalOptions) + + + true + .\Debug/meos.bsc + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/meos.tlb + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + stdafx.h + .\Debug/meos.pch + .\Debug/ + .\Debug/ + .\Debug/ + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies) + .\Debug/meos.exe + true + true + .\Debug/meos.pdb + Windows + false + + + MachineX86 + + + true + .\Debug/meos.bsc + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + %(PreprocessorDefinitions) + Create + %(PreprocessorDefinitions) + Create + %(PreprocessorDefinitions) + Create + + + + + + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + \ No newline at end of file diff --git a/code/meosversion.cpp b/code/meosversion.cpp new file mode 100644 index 0000000..11945e7 --- /dev/null +++ b/code/meosversion.cpp @@ -0,0 +1,172 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" +#include +#include "meos_util.h" + +//ABCDEFGHIJKLMNO +//V2: ABCDEFGHIHJKMN +//V31: a +//V33: abcde +int getMeosBuild() { + string revision("$Rev: 543 $"); + return 174 + atoi(revision.substr(5, string::npos).c_str()); +} + +//ABCDEFGHIJKILMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz +//V2: abcdefgh +//V3: abcdefghijklmnopqrstuvxyz +//V31: abcde +//V32: abcdefgh +//V33: abcdefghij +//V34: abcdfg +string getMeosDate() { + string date("$Date: 2017-03-25 20:00:02 +0100 (lö, 25 mar 2017) $"); + return date.substr(7,10); +} + +string getBuildType() { + return ""; // No parantheses (...) +} + +string getMajorVersion() { + return "3.4"; +} + +string getMeosFullVersion() { + char bf[256]; + string maj = getMajorVersion(); + if (getBuildType().empty()) + sprintf_s(bf, "Version X#%s.%d, %s", maj.c_str(), getMeosBuild(), getMeosDate().c_str()); + else + sprintf_s(bf, "Version X#%s.%d, %s %s", maj.c_str(), getMeosBuild(), getBuildType().c_str(), getMeosDate().c_str()); + return bf; +} + +string getMeosCompectVersion() { + if (getBuildType().empty()) + return getMajorVersion() + "." + itos(getMeosBuild()); + else + return getMajorVersion() + "." + itos(getMeosBuild()) + " (" + getBuildType() + ")"; +} + +void getSupporters(vector &supp) +{ + supp.push_back("Centrum OK"); + supp.push_back("Ove Persson, Piteå IF"); + supp.push_back("OK Rodhen"); + supp.push_back("Täby Extreme Challenge"); + supp.push_back("Thomas Engberg, VK Uvarna"); + supp.push_back("Eilert Edin, Sidensjö IK"); + supp.push_back("Göran Nordh, Trollhättans SK"); + supp.push_back("Roger Gustavsson, OK Tisaren"); + supp.push_back("Sundsvalls OK"); + supp.push_back("OK Gipens OL-skytte"); + supp.push_back("Helsingborgs SOK"); + supp.push_back("OK Gipens OL-skytte"); + supp.push_back("Rune Thurén, Vallentuna-Össeby OL"); + supp.push_back("Roland Persson, Kalmar OK"); + supp.push_back("Robert Jessen, Främmestads IK"); + supp.push_back("Anders Platt, Järla Orientering"); + supp.push_back("Almby IK, Örebro"); + supp.push_back("Peter Rydesäter, Rehns BK"); + supp.push_back("IK Hakarpspojkarna"); + supp.push_back("Rydboholms SK"); + supp.push_back("IFK Kiruna"); + supp.push_back("Peter Andersson, Söders SOL"); + supp.push_back("Björkfors GoIF"); + supp.push_back("OK Ziemelkurzeme"); + supp.push_back("Big Foot Orienteers"); + supp.push_back("FIF Hillerød"); + supp.push_back("Anne Udd"); + supp.push_back("OK Orinto"); + supp.push_back("SOK Träff"); + supp.push_back("Gamleby OK"); + supp.push_back("Vänersborgs SK"); + supp.push_back("Henrik Ortman, Västerås SOK"); + supp.push_back("Leif Olofsson, Sjuntorp"); + supp.push_back("Vallentuna/Össeby OL"); + supp.push_back("Oskarström OK"); + supp.push_back("Skogslöparna"); + supp.push_back("OK Milan"); + supp.push_back("GoIF Tjalve"); + supp.push_back("OK Skärmen"); + supp.push_back("Østkredsen"); + supp.push_back("OK Roskilde"); + supp.push_back("Holbæk Orienteringsklub"); + supp.push_back("Bodens BK"); + supp.push_back("OK Tyr, Karlstad"); + supp.push_back("Göteborg-Majorna OK"); + supp.push_back("OK Järnbärarna, Kopparberg"); + supp.push_back("FK Åsen"); + supp.push_back("Ballerup OK"); + supp.push_back("Olivier Benevello, Valbonne SAO"); + supp.push_back("Tommy Wåhlin, OK Enen"); + supp.push_back("Hjobygdens OK"); + supp.push_back("Tisvilde Hegn OK"); + supp.push_back("Lindebygdens OK"); + supp.push_back("OK Flundrehof"); + supp.push_back("Vittjärvs IK"); + supp.push_back("Annebergs GIF"); + supp.push_back("Lars-Eric Gahlin, Östersunds OK"); + supp.push_back("Sundsvalls OK:s Veteraner"); + supp.push_back("OK Skogshjortarna"); + supp.push_back("Kinnaströms SK"); + supp.push_back("OK Pan Århus"); + supp.push_back("Jan Ernberg, Täby OK"); + supp.push_back("Stjärnorps SK"); + supp.push_back("Mölndal Outdoor IF"); + supp.push_back("Roland Elg, Fjärås AIK"); + supp.push_back("Tenhults SOK"); + supp.push_back("Järfälla OK"); + supp.push_back("Lars Jonasson"); + supp.push_back("Anders Larsson, OK Nackhe"); + supp.push_back("Hans Wilhelmsson"); + supp.push_back("Patrice Lavallee, Noyon Course d'Orientation"); + supp.push_back("IFK Linköpings OS"); + supp.push_back("Lars Ove Karlsson, Västerås SOK"); + supp.push_back("OK Djerf"); + supp.push_back("OK Vivill"); + supp.push_back("IFK Mora OK"); + supp.push_back("Sonny Andersson, Huskvarna"); + supp.push_back("Hässleholms OK Skolorientering"); + supp.push_back("IBM-klubben Orientering"); + supp.push_back("OK Øst, Birkerød"); + supp.push_back("OK Klemmingen"); + supp.push_back("Hans Johansson"); + supp.push_back("KOB Kysak"); + supp.push_back("Per Ivarsson, Trollhättans SOK"); + supp.push_back("Sergio Yañez, ABC TRAIL"); + supp.push_back("Western Race Services"); + supp.push_back("IK Gandvik, Skara"); + supp.push_back("IK Stern"); + supp.push_back("OK Roslagen"); + supp.push_back("TSV Malente"); + supp.push_back("Emmaboda Verda OK"); + supp.push_back("KOB ATU Košice"); + supp.push_back("Gävle OK"); + supp.push_back("Kenneth Gattmalm, Jönköpings OK"); + supp.push_back("Søllerød OK"); + supp.push_back("O-travel"); + supp.push_back("Bengt Bengtsson"); + supp.push_back("OK Landehof"); +} diff --git a/code/metalist.cpp b/code/metalist.cpp new file mode 100644 index 0000000..b60f70f --- /dev/null +++ b/code/metalist.cpp @@ -0,0 +1,2499 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include + +#include "oEvent.h" + +#include "listeditor.h" +#include "generalresult.h" +#include "metalist.h" +#include "gdioutput.h" +#include "meosexception.h" +#include "meos_util.h" +#include "localizer.h" +#include "gdifonts.h" + +extern oEvent *gEvent; + +const int MAXLISTPARAMID = 10000000; +using namespace tr1; + +oListParam::oListParam() { + listCode = EStdResultList; //Just need a default + cb = 0; + legNumber = 0; + useControlIdResultTo = 0; + useControlIdResultFrom = 0; + filterMaxPer = 0; + pageBreak = false; + showInterTimes = false; + showSplitTimes = false; + splitAnalysis = false; + useLargeSize = false; + saved = false; + inputNumber = 0; + nextList = 0; // No linked list + previousList = 0; + relayLegIndex = -1; +} + +void oListParam::serialize(xmlparser &xml, + const MetaListContainer &container, + const map &idToIndex) const { + xml.startTag("ListParam", "Name", name); + xml.write("ListId", container.getUniqueId(listCode)); + string sel; + for (set::const_iterator it = selection.begin(); it != selection.end(); ++it) { + if (!sel.empty()) + sel += ";"; + sel += itos(*it); + } + xml.write("ClassId", sel); + xml.write("LegNumber", legNumber); + xml.write("FromControl", useControlIdResultFrom); + xml.write("ToControl", useControlIdResultTo); + xml.write("MaxFilter", filterMaxPer); + xml.write("Title", title); + xml.writeBool("Large", useLargeSize); + xml.writeBool("PageBreak", pageBreak); + xml.writeBool("ShowNamedSplits", showInterTimes); + xml.writeBool("ShowInterTitle", showInterTitle); + xml.writeBool("ShowSplits", showSplitTimes); + xml.writeBool("ShowAnalysis", splitAnalysis); + xml.write("InputNumber", inputNumber); + if (nextList != 0) { + map::const_iterator res = idToIndex.find(nextList); + if (res != idToIndex.end()) + xml.write("NextList", res->second); + } + xml.endTag(); +} + +void oListParam::deserialize(const xmlobject &xml, const MetaListContainer &container) { + xml.getObjectString("Name", name); + string id; + xml.getObjectString("ListId", id); + listCode = container.getCodeFromUnqiueId(id); + + string sel; + xml.getObjectString("ClassId", sel); + vector selVec; + split(sel, ";", selVec); + for (size_t k = 0; k < selVec.size(); k++) { + selection.insert(atoi(selVec[k].c_str())); + } + legNumber = xml.getObjectInt("LegNumber"); + useControlIdResultFrom = xml.getObjectInt("FromControl"); + useControlIdResultTo = xml.getObjectInt("ToControl"); + filterMaxPer = xml.getObjectInt("MaxFilter"); + xml.getObjectString("Title", title); + + useLargeSize = xml.getObjectBool("Large"); + pageBreak = xml.getObjectBool("PageBreak"); + showInterTimes = xml.getObjectBool("ShowNamedSplits"); + showSplitTimes = xml.getObjectBool("ShowSplits"); + splitAnalysis = xml.getObjectBool("ShowAnalysis"); + showInterTitle = xml.getObjectBool("ShowInterTitle"); + inputNumber = xml.getObjectInt("InputNumber"); + nextList = xml.getObjectInt("NextList"); + saved = true; +} + +void oListParam::getCustomTitle(char *t) const +{ + if (!title.empty()) + strcpy_s(t, 256, MakeDash(title).c_str()); +} + +const string &oListParam::getCustomTitle(const string &t) const +{ + if (!title.empty()) + return title; + else + return t; +} + +MetaList::MetaList() { + data.resize(4); + fontFaces.resize(4); + hasResults_ = false; + initSymbols(); + listType = oListInfo::EBaseTypeRunner; + listSubType = oListInfo::EBaseTypeNone; + sortOrder = SortByName; + supportFromControl = false; + supportToControl = false; +} + +MetaListPost::MetaListPost(EPostType type_, EPostType align_, int leg_) : type(type_), + alignType(align_), leg(leg_), minimalIndent(0), alignBlock(true), blockWidth(0), font(formatIgnore), + mergeWithPrevious(false), textAdjust(0), color(colorDefault) +{} + +int checksum(const string &str) { + int ret = 0; + for (size_t k = 0; k > &lines = data[i]; + for (size_t j = 0; j &cline = lines[j]; + for (size_t k = 0; k::const_iterator it = filter.begin(); it != filter.end(); ++it) + yx = yx * 31 + *it; + for (set::const_iterator it = subFilter.begin(); it != subFilter.end(); ++it) + yx = yx * 29 + *it; + + uniqueIndex = "A" + itos(ix) + "B" + itos(yx); +} + +bool MetaList::isBreak(int x) const { + return isspace(x) || x == '.' || x == ',' || + x == '-' || x == ':' || x == ';' || x == '(' + || x == ')' || x=='/' || (x>30 && x < 127 && !isalnum(x)); +} + +string MetaList::encode(const string &input_) const { + string out; + string input = lang.tl(input_); + out.reserve(input.length() + 5); + + for (size_t k = 0; k 0 ? input[k-1] : ' '; + int n = k+1 < input.length() ? input[k+1] : ' '; + + if (c == '%') { + out.push_back('%'); + out.push_back('%'); + } + else if (c == 'X' && isBreak(n) && isBreak(p) ) { + out.push_back('%'); + out.push_back('s'); + } + else + out.push_back(c); + } + return out; +} + +MetaListPost &MetaList::add(ListIndex ix, const MetaListPost &post) { + if (data[ix].empty()) + addRow(ix); + // data[ix].resize(1); + + vector &d = data[ix].back(); + d.push_back(post); + return d.back(); +} + +void MetaList::addRow(int ix) { + data[ix].push_back(vector()); +} + +static void setFixedWidth(oPrintPost &added, + const map, int> &indexPosToWidth, + int type, int j, int k) { + map, int>::const_iterator res = indexPosToWidth.find(tuple(type, j, k)); + if (res != indexPosToWidth.end()) + added.fixedWidth = res->second; + else + added.fixedWidth = 0; +} + +void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, + int lineHeight, oListInfo &li) const { + const MetaList &mList = *this; + Position pos; + const bool large = par.useLargeSize; + li.lp = par; + gdiFonts normal, header, small, italic; + double s_factor; + + map, int> fontHeight; + + for (size_t k = 0; k < fontFaces.size(); k++) { + for (map::const_iterator it = fontToSymbol.begin(); + it != fontToSymbol.end(); ++it) { + string face = fontFaces[k].font; + if (fontFaces[k].scale > 0 && fontFaces[k].scale != 100) { + face += ";" + itos(fontFaces[k].scale/100) + "." + itos(fontFaces[k].scale%100); + } + fontHeight[make_pair(it->first, int(k))] = gdi.getLineHeight(it->first, face.c_str()); + } + } + + if (large) { + s_factor = 0.9; + normal = fontLarge; + header = boldLarge; + small = normalText; + lineHeight = int(lineHeight *1.6); + italic = italicMediumPlus; + } + else { + s_factor = 1.0; + normal = normalText; + header = boldText; + small = italicSmall; + italic = italicText; + } + + map labelMap; + map stringLabelMap; + + set skip; + li.calcResults = false; + li.calcTotalResults = false; + li.rogainingResults = false; + li.calcCourseClassResults = false; + if (par.useControlIdResultFrom > 0 || par.useControlIdResultTo > 0) + li.needPunches = true; + const bool isPunchList = mList.listSubType == oListInfo::EBaseTypePunches; + map, int> indexPosToWidth; + map< pair, int> linePostCount; + for (int i = 0; i<4; i++) { + const vector< vector > &lines = mList.data[i]; + gdiFonts defaultFont = normal; + switch (i) { + case 0: + case 1: + defaultFont = header; + break; + case 3: { + if (isPunchList) + defaultFont = small; + else + defaultFont = italic; + } + } + + for (size_t j = 0; j &cline = lines[j]; + for (size_t k = 0; kcalculateResults(oEvent::RTClassResult); + oe->calculateTeamResults(false); + } + li.calcResults = true; + } + if (mp.type == lRunnerTotalPlace || mp.type == lRunnerPlaceDiff + || mp.type == lTeamTotalPlace || mp.type == lTeamPlaceDiff + || mp.type == lRunnerGeneralPlace) { + if (!li.calcTotalResults) { + oe->calculateResults(oEvent::RTTotalResult); + oe->calculateTeamResults(true); + } + li.calcTotalResults = true; + } + else if (mp.type == lRunnerRogainingPoint || mp.type == lRunnerRogainingPointTotal + || mp.type == lTeamRogainingPoint || mp.type == lTeamRogainingPointTotal) { + li.rogainingResults = true; + } + else if (mp.type == lRunnerClassCoursePlace || mp.type == lRunnerClassCourseTimeAfter) { + if (!li.calcCourseClassResults) + oe->calculateResults(oEvent::RTClassCourseResult); + + li.calcCourseClassResults = true; + } + else if (mp.type == lRunnerTempTimeAfter || mp.type == lRunnerTempTimeStatus) { + li.needPunches = true; + } + + string label = "P" + itos(i*1000 + j*100 + k); + + if (mp.type == lRunnerBib || mp.type == lTeamBib) { + if (!oe->hasBib(mp.type == lRunnerBib, mp.type == lTeamBib)) + skip.insert(mp.type); + } + + int width = 0; + if (skip.count(mp.type) == 0 && (k==0 || !mp.mergeWithPrevious)) { + gdiFonts font = defaultFont; + if (mp.font != formatIgnore) + font = mp.font; + + vector< pair > typeFormats; + typeFormats.push_back(make_pair(mp.type, encode(mp.text))); + size_t kk = k+1; + //Add merged entities + while (kk < cline.size() && cline[kk].mergeWithPrevious) { + typeFormats.push_back(make_pair(cline[kk].type, encode(cline[kk].text))); + kk++; + } + + width = li.getMaxCharWidth(oe, par.selection, typeFormats, font, + oPrintPost::encodeFont(fontFaces[i].font, + fontFaces[i].scale).c_str(), + large, max(mp.blockWidth, extraMinWidth)); + ++linePostCount[make_pair(i, j)]; // Count how many positions on this line + indexPosToWidth[tuple(i, j, k)] = width; + } + + if (mp.alignType == lNone) { + pos.add(label, width, width); + pos.indent(mp.minimalIndent); + } + else { + if (mp.alignType == lAlignNext) + pos.alignNext(label, width, mp.alignBlock); + else if (mp.alignType == lString) { + if (stringLabelMap.count(mp.alignWithText) == 0) { + throw meosException("Don't know how to align with 'X'#" + mp.alignWithText); + } + pos.update(stringLabelMap[mp.alignWithText], label, width, mp.alignBlock, true); + } + else { + if (labelMap.count(mp.alignType) == 0) { + throw meosException("Don't know how to align with 'X'#" + typeToSymbol[mp.alignType]); + } + + pos.update(labelMap[mp.alignType], label, width, mp.alignBlock, true); + } + + pos.indent(mp.minimalIndent); + } + labelMap[mp.type] = label; + if (!mp.text.empty()) + stringLabelMap[mp.text] = label; + + } + pos.newRow(); + } + pos.newRow(); + } + + bool c = true; + while (c) { + c = pos.postAdjust(); + } + + int dy = 0, next_dy = 0; + oPrintPost *last = 0; + oPrintPost *base = 0; + + int totalWidth = pos.getWidth(); + for (map, int>::iterator it = linePostCount.begin(); it != linePostCount.end(); ++it) { + if (it->second == 1) { + int base = it->first.first; + if (base == MLSubList && listSubType == oListInfo::EBaseTypePunches) + continue; // This type of list requires actual width + indexPosToWidth[tuple(base, it->first.second, 0)] = totalWidth; + } + } + + pClass sampleClass = 0; + + if (!par.selection.empty()) + sampleClass = oe->getClass(*par.selection.begin()); + if (!sampleClass) { + vector cls; + oe->getClasses(cls, false); + if (!cls.empty()) + sampleClass = cls[0]; + } + pair parLegNumber = par.getLegInfo(sampleClass); + + resultToIndex.clear(); + /*if (large == false && par.pageBreak == false) {*/ + { + int head_dy = gdi.scaleLength(mList.getExtraSpace(MLHead)); + for (size_t j = 0; j &cline = mList.getHead()[j]; + next_dy = 0; + for (size_t k = 0; kmergeWith = &added; + last->doMergeNext = true; + if (base) { + base->fixedWidth += added.fixedWidth; + added.fixedWidth = 0; + } + } + last = &added; + + next_dy = max(next_dy, fontHeight[make_pair(font, MLHead)]); + } + dy += next_dy; + next_dy = lineHeight; + } + } + + dy = lineHeight; + int subhead_dy = gdi.scaleLength(mList.getExtraSpace(MLSubHead)); + + last = 0; + base = 0; + for (size_t j = 0; j &cline = mList.getSubHead()[j]; + for (size_t k = 0; kmergeWith = &added; + last->doMergeNext = true; + if (base) { + base->fixedWidth += added.fixedWidth; + added.fixedWidth = 0; + } + } + last = &added; + + next_dy = max(next_dy, fontHeight[make_pair(font, MLSubHead)]); + } + dy += next_dy; + } + + last = 0; + base = 0; + int list_dy = gdi.scaleLength(mList.getExtraSpace(MLList));//mList.getSubList().size() > 0 ? lineHeight/2 : 0; + dy = 0; + for (size_t j = 0; j &cline = mList.getList()[j]; + next_dy = 0; + for (size_t k = 0; kdoMergeNext = true; + if (base) { + base->fixedWidth += added.fixedWidth; + added.fixedWidth = 0; + } + } + last = &added; + } + dy += next_dy; + } + + int sublist_dy = gdi.scaleLength(mList.getExtraSpace(MLSubList)); + last = 0; + base = 0; + dy = 0; + for (size_t j = 0; j &cline = mList.getSubList()[j]; + next_dy = 0; + for (size_t k = 0; kdoMergeNext = true; + if (base) { + base->fixedWidth += added.fixedWidth; + added.fixedWidth = 0; + } + } + last = &added; + } + dy += next_dy; + } + + li.listType = getListType(); + li.listSubType = listSubType; + li.sortOrder = sortOrder; + for (set::const_iterator it = filter.begin(); + it != filter.end(); ++it) { + li.setFilter(*it); + } + for (set::const_iterator it = subFilter.begin(); + it != subFilter.end(); ++it) { + li.setSubFilter(*it); + } + li.setResultModule(resultModule); + li.supportFrom = supportFromControl; + li.supportTo = supportToControl; + li.resType = getResultType(); + if (!resultModule.empty() || li.calcResults || li.calcCourseClassResults || li.calcTotalResults) + hasResults_ = true; +} + + +void Position::indent(int ind) { + int end = pos.size() - 1; + if (end < 1) + return; + if (pos[end-1].first < ind) { + int dx = ind - pos[end-1].first; + pos[end-1].first += dx; + pos[end].first += dx; + } +} + +void Position::newRow() { + if (!pos.empty()) + pos.pop_back(); + pos.push_back(PosInfo(0, 0)); +} + +void Position::alignNext(const string &newname, const int width, bool alignBlock) { + if (pos.empty()) + return; + int p = pos.empty() ? 0 : pos.back().first; + const int backAlign = 20; + const int fwdAlign = max(width/2, 40); + + if (p==0) + p = backAlign; + + int next = 0, prev = 0; + int next_p = 100000, prev_p = -100000; + + int last = pos.size()-1; + for (int k = pos.size()-2; k >= 0; k--) { + last = k; + if (pos[k+1].first < pos[k].first) + break; + } + + for (int k = 0; k <= last; k++) { + if ( pos[k].first >= p && pos[k].first < next_p ) { + next = k; + next_p = pos[k].first; + } + + if ( pos[k].first < p && pos[k].first > prev_p ) { + prev = k; + prev_p = pos[k].first; + } + } + + if ( p - prev_p < backAlign) { + int delta = p - prev_p; + for (size_t k = 0; k + 1 < pos.size(); k++) { + if (pos[k].first >= prev_p) + pos[k].first += delta; + } + update(prev, newname, width, alignBlock, false); + } + else { + if (next > 0 && (next_p - p) < fwdAlign) + update(next, newname, width, alignBlock, false); + else + add(newname, width, width); + } +} + +void Position::update(const string &oldname, const string &newname, + const int width, bool alignBlock, bool alignLock) { + if (pmap.count(oldname) == 0) + throw std::exception("Invalid position"); + + int ix = pmap[oldname]; + + update(ix, newname, width, alignBlock, alignLock); +} + +void Position::update(int ix, const string &newname, const int width, + bool alignBlock, bool alignLock) { + + int last = pos.size()-1; + + if (alignLock) { + pos[last].aligned = true; + pos[ix].aligned = true; + } + int xlimit = pos[ix].first; + if (xlimit < pos[last].first) { + int delta = pos[last].first - xlimit; + + // Find last entry to update (higher row) + int lastud = last; + while (lastud>1 && pos[lastud].first >= pos[lastud-1].first) + lastud--; + + for (int k = 0; k= xlimit) + pos[k].first += delta; + } + } + else + pos[last].first = pos[ix].first; + + int ow = pos[ix+1].first - pos[ix].first; + int nw = width; + if (alignBlock && ow>0) { + nw = max(ow, nw); + if (nw > ow) { + int delta = nw - ow; + for (size_t k = 0; k pos[ix].first) + pos[k].first += delta; + } + } + } + add(newname, nw, width); +} + +int Position::getWidth() const { + int w = 0; + for (size_t k = 0; k < pos.size(); k++) { + w = max(w, pos[k].first + pos[k].width); + } + return w; +} + +void Position::add(const string &name, int width, int blockWidth) { + + if (pos.empty()) { + pos.push_back(PosInfo(0, blockWidth)); + pmap[name] = 0; + pos.push_back(PosInfo(width, 0)); + } + else { + pmap[name] = pos.size() - 1; + pos.back().width = blockWidth; + pos.push_back(PosInfo(width + pos.back().first, 0)); + } +} + +int Position::get(const string &name) { + return pos[pmap[name]].first; +} + +int Position::get(const string &name, double scale) { + return int(pos[pmap[name]].first * scale); +} + +int Position::getOriginalPos(const string &name) { + return pos[pmap[name]].originalPos; +} + +int Position::getOriginalPos(const string &name, double scale) { + return int(pos[pmap[name]].originalPos * scale); +} + + +struct PosOrderIndex { + int pos; + int index; + int width; + int row; + bool aligned; + bool operator<(const PosOrderIndex &x) const {return pos < x.pos;} +}; + +bool Position::postAdjust() { + + vector x; + int row = 0; + vector aligned(1, -1); + + for (size_t k = 0; k < pos.size(); k++) { + PosOrderIndex poi; + poi.pos = pos[k].first; + poi.index = k; + poi.row = row; + if (pos[k].aligned) + aligned[row] = k; + if (k + 1 == pos.size() || pos[k+1].first == 0) { + poi.width = 100000; + row++; + aligned.push_back(-1); + } + else + poi.width = pos[k].width;//pos[k+1].first - pos[k].first;//XXX// + + x.push_back(poi); + } + + sort(x.begin(), x.end()); + + // Transfer aligned blocks to x + for (size_t k = 0; k=x[k].index) + x[k].aligned = true; + else + x[k].aligned = false; + } + + pair smallDiff(100000, -1); + for (size_t k = 0; k0 && x[k-1].pos == x[k].pos || x[k].pos == 0) + continue; + int diff = 0; + for (size_t j = k + 1; j < x.size(); j++) { + if (x[j].pos > x[k].pos) { + if (x[j].row == x[k].row) + break; + else { + diff = x[j].pos - x[k].pos; + + + bool skipRow = x[j].aligned || x[k].aligned; + + if (skipRow) + break; + + for (size_t i = 0; i x[k].width / 2) + break; + + if (diff < smallDiff.first) { + smallDiff.first = diff; + smallDiff.second = k; + } + } + } + } + } + + if (smallDiff.second != -1) { + int minK = smallDiff.second; + int diff = smallDiff.first; + int basePos = x[minK].pos; + set keepRow; + for (size_t k = 0; k= basePos && keepRow.count(x[k].row) == 0) { + pos[x[k].index].first += diff; + changed = true; + } + } + + return changed; + } + return false; +} + +void MetaList::save(const string &file, const oEvent *oe) const { + xmlparser xml(0); + xml.openOutput(file.c_str(), true); + save(xml, oe); + xml.closeOut(); +} + +void MetaList::save(xmlparser &xml, const oEvent *oe) const { + initSymbols(); + xml.startTag("MeOSListDefinition", "version", getMajorVersion()); +// xml.write("Title", defaultTitle); + xml.write("ListName", listName); + if (listOrigin.empty()) + listOrigin = gEvent->getName() + " (" + getLocalDate() + ")"; + xml.write("ListOrigin", listOrigin); + xml.write("Tag", tag); + xml.write("UID", getUniqueId()); + xml.write("SortOrder", orderToSymbol[sortOrder]); + xml.write("ListType", baseTypeToSymbol[listType]); + xml.write("SubListType", baseTypeToSymbol[listSubType]); + if (!resultModule.empty()) { + string ttw = DynamicResult::undecorateTag(resultModule); + xml.write("ResultModule", ttw); + try { + string srcFile; + GeneralResult &gr = oe->getGeneralResult(resultModule, srcFile); + DynamicResult &dr = dynamic_cast(gr); + if (!dr.isBuiltIn()) { + string ot = dr.getTag(); + dr.setTag(ttw); + try { + dr.save(xml); + } + catch (...) { + dr.setTag(ot); + throw; + } + dr.setTag(ot); + +// string db = "Saved res mod: " + ttw + " (" + resultModule + ") h=" + itos(dr.getHashCode())+ "\n"; +// OutputDebugString(db.c_str()); + } + } + catch (std::exception &) { // Not available + } + } + if (supportFromControl) + xml.write("SupportFrom", supportFromControl); + if (supportToControl) + xml.write("SupportTo", supportToControl); + + for (set::const_iterator it = filter.begin(); it != filter.end(); ++it) + xml.write("Filter", "name", filterToSymbol[*it]); + + for (set::const_iterator it = subFilter.begin(); it != subFilter.end(); ++it) + xml.write("SubFilter", "name", subFilterToSymbol[*it]); + + vector< pair > props(2); + xml.write("HeadFont", fontFaces[MLHead].serialize(props), fontFaces[MLHead].font); + xml.write("SubHeadFont", fontFaces[MLSubHead].serialize(props), fontFaces[MLSubHead].font); + xml.write("ListFont", fontFaces[MLList].serialize(props), fontFaces[MLList].font); + xml.write("SubListFont", fontFaces[MLSubList].serialize(props), fontFaces[MLSubList].font); + + serialize(xml, "Head", getHead()); + serialize(xml, "SubHead", getSubHead()); + serialize(xml, "List", getList()); + serialize(xml, "SubList", getSubList()); + + xml.endTag(); +} + +void MetaList::load(const string &file) { + xmlparser xml(0); + xml.read(file.c_str()); + filter.clear(); + xmlobject xDef = xml.getObject("MeOSListDefinition"); + load(xDef); +} + +void MetaList::load(const xmlobject &xDef) { + if (!xDef) + throw meosException("Ogiltigt filformat"); + + xDef.getObjectString("ListName", listName); + xDef.getObjectString("ListOrigin", listOrigin); + xDef.getObjectString("Tag", tag); + xDef.getObjectString("UID", uniqueIndex); + xDef.getObjectString("ResultModule", resultModule); + +// string db = "Specified res mod: " + resultModule + "\n"; +// OutputDebugString(db.c_str()); + + vector rs; + xDef.getObjects("MeOSResultCalculationSet", rs); + dynamicResults.resize(rs.size()); + for (size_t k = 0; k < rs.size(); k++) { + DynamicResult dr; + dr.load(rs[k]); +// string db = "Loaded res mod: " + dr.getTag() + ", h=" + itos(dr.getHashCode())+ "\n"; +// OutputDebugString(db.c_str()); + string file = "*"; + dynamicResults[k] = GeneralResultCtr(file, new DynamicResult(dr)); + } + supportFromControl = xDef.getObjectBool("SupportFrom"); + supportToControl = xDef.getObjectBool("SupportTo"); + + string tmp; + xDef.getObjectString("SortOrder", tmp); + if (symbolToOrder.count(tmp) == 0) { + string err = "Invalid sort order X#" + tmp; + throw std::exception(err.c_str()); + } + sortOrder = symbolToOrder[tmp]; + + xDef.getObjectString("ListType", tmp); + if (symbolToBaseType.count(tmp) == 0) { + string err = "Invalid type X#" + tmp; + throw std::exception(err.c_str()); + } + listType = symbolToBaseType[tmp]; + + xDef.getObjectString("SubListType", tmp); + if (!tmp.empty()) { + if (symbolToBaseType.count(tmp) == 0) { + string err = "Invalid type X#" + tmp; + throw std::exception(err.c_str()); + } + + listSubType = symbolToBaseType[tmp]; + } + xmlobject xHeadFont = xDef.getObject("HeadFont"); + xmlobject xSubHeadFont = xDef.getObject("SubHeadFont"); + xmlobject xListFont = xDef.getObject("ListFont"); + xmlobject xSubListFont = xDef.getObject("SubListFont"); + + if (xHeadFont) { + const char *f = xHeadFont.get(); + fontFaces[MLHead].font = f != 0 ? f : "arial"; + fontFaces[MLHead].scale = xHeadFont.getObjectInt("scale"); + fontFaces[MLHead].extraSpaceAbove = xHeadFont.getObjectInt("above"); + } + + if (xSubHeadFont) { + const char *f = xSubHeadFont.get(); + fontFaces[MLSubHead].font = f != 0 ? f : "arial"; + fontFaces[MLSubHead].scale = xSubHeadFont.getObjectInt("scale"); + fontFaces[MLSubHead].extraSpaceAbove = xSubHeadFont.getObjectInt("above"); + } + + if (xListFont) { + const char *f = xListFont.get(); + fontFaces[MLList].font = f != 0 ? f : "arial"; + fontFaces[MLList].scale = xListFont.getObjectInt("scale"); + fontFaces[MLList].extraSpaceAbove = xListFont.getObjectInt("above"); + } + + if (xSubListFont) { + const char *f = xSubListFont.get(); + fontFaces[MLSubList].font = f != 0 ? f : "arial"; + fontFaces[MLSubList].scale = xSubListFont.getObjectInt("scale"); + fontFaces[MLSubList].extraSpaceAbove = xSubListFont.getObjectInt("above"); + } + + xmlobject xHead = xDef.getObject("Head"); + xmlobject xSubHead = xDef.getObject("SubHead"); + xmlobject xList = xDef.getObject("List"); + xmlobject xSubList = xDef.getObject("SubList"); + + deserialize(xHead, data[MLHead]); + deserialize(xSubHead, data[MLSubHead]); + deserialize(xList, data[MLList]); + deserialize(xSubList, data[MLSubList]); + + // Check if result list + for (int i = 0; i<4; i++) { + const vector< vector > &lines = data[i]; + for (size_t j = 0; j &cline = lines[j]; + for (size_t k = 0; k &resultModules) const { + resultModules.resize(dynamicResults.size()); + for (size_t k = 0; k < dynamicResults.size(); k++) { + resultModules[k].res = dynamic_cast(dynamicResults[k].ptr); + resultModules[k].ctr = const_cast(this); + } +} + +const string &MetaList::getListInfo(const oEvent &oe) const { + vector resultModules; + getDynamicResults(resultModules); + + for (size_t k = 0; k < resultModules.size(); k++) { + if (resultModules[k].res) { + return resultModules[k].res->getDescription(); + } + } + if (!resultModule.empty()) { + string f; + try { + GeneralResult &res = oe.getGeneralResult(resultModule, f); + DynamicResult &dres = dynamic_cast(res); + return dres.getDescription(); + } + catch (...) { + + } + } + return _EmptyString; +} + + +void MetaList::retagResultModule(const string &newTag, bool retagStoredModule) { + if (newTag == resultModule) + return; + string oldTag = resultModule; + resultModule = newTag; + for (size_t k = 0; k < data.size(); k++) { + for (size_t i = 0; i < data[k].size(); i++) { + for (size_t j = 0; j < data[k][i].size(); j++) { + MetaListPost &mlp = data[k][i][j]; + if (mlp.getResultModule() == oldTag) + mlp.setResultModule(newTag); + } + } + } + + if (retagStoredModule) { + for (size_t k = 0; k < dynamicResults.size(); k++) { + DynamicResult *res = dynamic_cast(dynamicResults[k].ptr); + if (res && res->getTag() == oldTag) { + res->setTag(newTag); + } + } + } +} + +bool MetaList::updateResultModule(const DynamicResult &dr, bool updateSimilar) { + for (size_t k = 0; k < dynamicResults.size(); k++) { + DynamicResult *res = dynamic_cast(dynamicResults[k].ptr); + if (res) { + const string &tag1 = res->getTag(); + const string &tag2 = dr.getTag(); + if (tag1 == tag2 || (updateSimilar && DynamicResult::undecorateTag(tag1) == DynamicResult::undecorateTag(tag2)) ) { + long long oldCS = res->getHashCode(); + *res = dr; + retagResultModule(res->getTag(), false); + return res->getHashCode() != oldCS; + } + } + + if (dr.getTag() == resultModule) { + return true; + } + } + return false; +} + +bool MetaListContainer::updateResultModule(const DynamicResult &dr, bool updateSimilar) { + bool changed = false; + for (size_t i = 0; i < data.size(); i++) { + if (data[i].first == ExternalList) { + if (data[i].second.updateResultModule(dr, updateSimilar)) + changed = true; + } + } + + if (changed && owner) + owner->updateChanged(); + + return changed; +} + +void MetaList::serialize(xmlparser &xml, const string &tagp, + const vector< vector > &lp) const { + xml.startTag(tagp.c_str()); + + for (size_t k = 0; k > &lp) { + if (!xml) + throw meosException("Ogiltigt filformat"); + + + xmlList xLines; + xml.getObjects(xLines); + + for (size_t k = 0; k()); + xmlList xBlocks; + xLines[k].getObjects(xBlocks); + for (size_t j = 0; j > &types, int ¤tType) const { + currentType = type; + types.clear(); + types.reserve(MetaList::typeToSymbol.size()); + for (map::const_iterator it = + MetaList::typeToSymbol.begin(); it != MetaList::typeToSymbol.end(); ++it) { + if (it->first == lNone) + continue; + if (it->first == lAlignNext) + continue; + + types.push_back(make_pair(lang.tl(it->second), it->first)); + } +} + +const string &MetaListPost::getFont() const { + return MetaList::fontToSymbol[font]; +} + +void MetaListPost::getFonts(vector< pair > &fonts, int ¤tFont) const { + currentFont = font; + fonts.clear(); + fonts.reserve(MetaList::fontToSymbol.size()); + for (map::const_iterator it = + MetaList::fontToSymbol.begin(); it != MetaList::fontToSymbol.end(); ++it) { + fonts.push_back(make_pair(lang.tl(it->second), it->first)); + } +} + +void MetaListPost::getAllFonts(vector< pair > &fonts) { + fonts.clear(); + fonts.reserve(MetaList::fontToSymbol.size()); + for (map::const_iterator it = + MetaList::fontToSymbol.begin(); it != MetaList::fontToSymbol.end(); ++it) { + fonts.push_back(make_pair(lang.tl(it->second), it->first)); + } +} + +void MetaList::getAlignTypes(const MetaListPost &mlp, vector< pair > &types, int ¤tType) const { + currentType = mlp.alignType; + types.clear(); + int gix, lix, ix; + getIndex(mlp, gix, lix, ix); + set< pair > atypes; + bool q = false; + for (size_t k = 0; k < data.size(); k++) { + for (size_t j = 0; j < data[k].size(); j++) { + if ( k == gix && j == lix) { + q = true; + break; + } + for (size_t i = 0; i < data[k][j].size(); i++) { + if (data[k][j][i].type != lString) + atypes.insert(make_pair(data[k][j][i].type, "")); + else + atypes.insert(make_pair(data[k][j][i].type, data[k][j][i].text)); + } + } + + if (q) + break; + } + if (currentType != lString) + atypes.insert(make_pair(EPostType(currentType), "")); + atypes.insert(make_pair(lNone, "")); + + for (set< pair >::iterator it = atypes.begin(); it != atypes.end(); ++it) { + string type = lang.tl(typeToSymbol[it->first]); + if (it->first == lString) + type += ":" + it->second; + types.push_back(make_pair(type, it->first)); + } +} + +void MetaList::getIndex(const MetaListPost &mlp, int &gix, int &lix, int &ix) const { + for (size_t k = 0; k < data.size(); k++) { + for (size_t j = 0; j < data[k].size(); j++) { + for (size_t i = 0; i < data[k][j].size(); i++) { + if (&data[k][j][i] == &mlp) { + gix = k, lix = j, ix = i; + return; + } + } + } + } + throw meosException("Invalid object"); +} +void MetaListPost::serialize(xmlparser &xml) const { + xml.startTag("Block", "Type", MetaList::typeToSymbol[type]); + xml.write("Text", text); + if (!resultModule.empty()) + xml.write("ResultModule", DynamicResult::undecorateTag(resultModule)); + if (leg != -1) + xml.write("Leg", itos(leg)); + if (alignType == lString) + xml.write("Align", "BlockAlign", alignBlock, alignWithText); + else + xml.write("Align", "BlockAlign", alignBlock, MetaList::typeToSymbol[alignType]); + xml.write("BlockWidth", blockWidth); + xml.write("IndentMin", minimalIndent); + if (font != formatIgnore) + xml.write("Font", getFont()); + if (mergeWithPrevious) + xml.write("MergePrevious", "1"); + if (textAdjust != 0) + xml.write("TextAdjust", getTextAdjust()); + if (color != colorDefault) { + char bf[16]; + sprintf_s(bf, "%x", color); + xml.write("Color", bf); + } + xml.endTag(); +} + +void MetaListPost::deserialize(const xmlobject &xml) { + if (!xml) + throw meosException("Ogiltigt filformat"); + + string tp = xml.getAttrib("Type").get(); + if (MetaList::symbolToType.count(tp) == 0) { + string err = "Invalid type X#" + tp; + throw std::exception(err.c_str()); + } + + type = MetaList::symbolToType[tp]; + xml.getObjectString("Text", text); + xml.getObjectString("ResultModule", resultModule); + if (xml.getObject("Leg")) + leg = xml.getObjectInt("Leg"); + else + leg = -1; + xmlobject xAlignBlock = xml.getObject("Align"); + alignBlock = xAlignBlock && xAlignBlock.getObjectBool("BlockAlign"); + blockWidth = xml.getObjectInt("BlockWidth"); + minimalIndent = xml.getObjectInt("IndentMin"); + string at; + xml.getObjectString("Align", at); + + if (!at.empty()) { + if (MetaList::symbolToType.count(at) == 0) { + alignType = lString; + alignWithText = at; + } + else alignType = MetaList::symbolToType[at]; + } + + mergeWithPrevious = xml.getObjectInt("MergePrevious") != 0; + xml.getObjectString("TextAdjust", at); + + if (at == "Right") + textAdjust = textRight; + else if (at == "Center") + textAdjust = textCenter; + + xml.getObjectString("Color", at); + if (!at.empty()) { + color = (GDICOLOR)(strtol(at.c_str(), 0, 16)&0xFFFFFF); + //color = GDICOLOR(atoi(at.c_str())); + } + + string f; + xml.getObjectString("Font", f); + if (!f.empty()) { + if (MetaList::symbolToFont.count(f) == 0) { + string err = "Invalid font X#" + f; + throw meosException(err); + } + else font = MetaList::symbolToFont[f]; + } +} + +map MetaList::typeToSymbol; +map MetaList::symbolToType; +map MetaList::baseTypeToSymbol; +map MetaList::symbolToBaseType; +map MetaList::orderToSymbol; +map MetaList::symbolToOrder; +map MetaList::filterToSymbol; +map MetaList::symbolToFilter; +map MetaList::fontToSymbol; +map MetaList::symbolToFont; +map MetaList::subFilterToSymbol; +map MetaList::symbolToSubFilter; + +void MetaList::initSymbols() { + if (typeToSymbol.empty()) { + typeToSymbol[lAlignNext] = "AlignNext"; + typeToSymbol[lNone] = "None"; + typeToSymbol[lString] = "String"; + typeToSymbol[lResultDescription] = "ResultDescription"; + typeToSymbol[lTimingFromName] = "TimingFrom"; + typeToSymbol[lTimingToName] = "TimingTo"; + typeToSymbol[lCmpName] = "CmpName"; + typeToSymbol[lCmpDate] = "CmpDate"; + typeToSymbol[lCurrentTime] = "CurrentTime"; + typeToSymbol[lClubName] = "ClubName"; + typeToSymbol[lClassName] = "ClassName"; + typeToSymbol[lClassStartName] = "ClassStartName"; + typeToSymbol[lClassStartTime] = "StartTimeForClass"; + typeToSymbol[lClassStartTimeRange] = "StartTimeForClassRange"; + typeToSymbol[lClassLength] = "ClassLength"; + typeToSymbol[lClassResultFraction] = "ClassResultFraction"; + typeToSymbol[lCourseLength] = "CourseLength"; + typeToSymbol[lCourseName] = "CourseName"; + typeToSymbol[lCourseClimb] = "CourseClimb"; + typeToSymbol[lCourseUsage] = "CourseUsage"; + typeToSymbol[lCourseUsageNoVacant] = "CourseUsageNoVacant"; + typeToSymbol[lCourseClasses] = "CourseClasses"; + typeToSymbol[lCourseShortening] = "CourseShortening"; + typeToSymbol[lRunnerName] = "RunnerName"; + typeToSymbol[lRunnerGivenName] = "RunnerGivenName"; + typeToSymbol[lRunnerFamilyName] = "RunnerFamilyName"; + typeToSymbol[lRunnerCompleteName] = "RunnerCompleteName"; + typeToSymbol[lPatrolNameNames] = "PatrolNameNames"; + typeToSymbol[lPatrolClubNameNames] = "PatrolClubNameNames"; + typeToSymbol[lRunnerFinish] = "RunnerFinish"; + typeToSymbol[lRunnerTime] = "RunnerTime"; + typeToSymbol[lRunnerTimeStatus] = "RunnerTimeStatus"; + typeToSymbol[lRunnerTempTimeStatus] = "RunnerTempTimeStatus"; + typeToSymbol[lRunnerTempTimeAfter] = "RunnerTempTimeAfter"; + typeToSymbol[lRunnerTimeAfter] = "RunnerTimeAfter"; + typeToSymbol[lRunnerClassCourseTimeAfter] = "RunnerClassCourseTimeAfter"; + typeToSymbol[lRunnerMissedTime] = "RunnerTimeLost"; + typeToSymbol[lRunnerPlace] = "RunnerPlace"; + typeToSymbol[lRunnerClassCoursePlace] = "RunnerClassCoursePlace"; + typeToSymbol[lRunnerStart] = "RunnerStart"; + typeToSymbol[lRunnerStartCond] = "RunnerStartCond"; + typeToSymbol[lRunnerStartZero] = "RunnerStartZero"; + typeToSymbol[lRunnerClub] = "RunnerClub"; + typeToSymbol[lRunnerCard] = "RunnerCard"; + typeToSymbol[lRunnerBib] = "RunnerBib"; + typeToSymbol[lRunnerStartNo] = "RunnerStartNo"; + typeToSymbol[lRunnerRank] = "RunnerRank"; + typeToSymbol[lRunnerCourse] = "RunnerCourse"; + typeToSymbol[lRunnerRogainingPoint] = "RunnerRogainingPoint"; + typeToSymbol[lRunnerRogainingPointTotal] = "RunnerRogainingPointTotal"; + typeToSymbol[lRunnerRogainingPointReduction] = "RunnerRogainingReduction"; + typeToSymbol[lRunnerRogainingPointOvertime] = "RunnerRogainingOvertime"; + typeToSymbol[lRunnerTimeAdjustment] = "RunnerTimeAdjustment"; + typeToSymbol[lRunnerPointAdjustment] = "RunnerPointAdjustment"; + typeToSymbol[lRunnerRogainingPointGross] = "RunnerRogainingPointGross"; + + typeToSymbol[lRunnerUMMasterPoint] = "RunnerUMMasterPoint"; + typeToSymbol[lRunnerTimePlaceFixed] = "RunnerTimePlaceFixed"; + typeToSymbol[lRunnerLegNumberAlpha] = "RunnerLegNumberAlpha"; + typeToSymbol[lRunnerLegNumber] = "RunnerLegNumber"; + + typeToSymbol[lResultModuleTime] = "ResultModuleTime"; + typeToSymbol[lResultModuleNumber] = "ResultModuleNumber"; + typeToSymbol[lResultModuleTimeTeam] = "ResultModuleTimeTeam"; + typeToSymbol[lResultModuleNumberTeam] = "ResultModuleNumberTeam"; + + typeToSymbol[lRunnerBirthYear] = "RunnerBirthYear"; + typeToSymbol[lRunnerAge] = "RunnerAge"; + typeToSymbol[lRunnerSex] = "RunnerSex"; + typeToSymbol[lRunnerNationality] = "RunnerNationality"; + typeToSymbol[lRunnerPhone] = "RunnerPhone"; + typeToSymbol[lRunnerFee] = "RunnerFee"; + + typeToSymbol[lTeamName] = "TeamName"; + typeToSymbol[lTeamStart] = "TeamStart"; + typeToSymbol[lTeamStartCond] = "TeamStartCond"; + typeToSymbol[lTeamStartZero] = "TeamStartZero"; + + typeToSymbol[lTeamTimeStatus] = "TeamTimeStatus"; + typeToSymbol[lTeamTimeAfter] = "TeamTimeAfter"; + typeToSymbol[lTeamPlace] = "TeamPlace"; + typeToSymbol[lTeamLegTimeStatus] = "TeamLegTimeStatus"; + typeToSymbol[lTeamLegTimeAfter] = "TeamLegTimeAfter"; + typeToSymbol[lTeamRogainingPoint] = "TeamRogainingPoint"; + typeToSymbol[lTeamRogainingPointTotal] = "TeamRogainingPointTotal"; + typeToSymbol[lTeamRogainingPointReduction] = "TeamRogainingReduction"; + typeToSymbol[lTeamRogainingPointOvertime] = "TeamRogainingOvertime"; + typeToSymbol[lTeamTimeAdjustment] = "TeamTimeAdjustment"; + typeToSymbol[lTeamPointAdjustment] = "TeamPointAdjustment"; + + typeToSymbol[lTeamTime] = "TeamTime"; + typeToSymbol[lTeamStatus] = "TeamStatus"; + typeToSymbol[lTeamClub] = "TeamClub"; + typeToSymbol[lTeamRunner] = "TeamRunner"; + typeToSymbol[lTeamRunnerCard] = "TeamRunnerCard"; + typeToSymbol[lTeamBib] = "TeamBib"; + typeToSymbol[lTeamStartNo] = "TeamStartNo"; + typeToSymbol[lPunchNamedTime] = "PunchNamedTime"; + typeToSymbol[lPunchTime] = "PunchTime"; + typeToSymbol[lPunchControlNumber] = "PunchControlNumber"; + typeToSymbol[lPunchControlCode] = "PunchControlCode"; + typeToSymbol[lPunchLostTime] = "PunchLostTime"; + typeToSymbol[lPunchControlPlace] = "PunchControlPlace"; + typeToSymbol[lPunchControlPlaceAcc] = "PunchControlPlaceAcc"; + + typeToSymbol[lRogainingPunch] = "RogainingPunch"; + typeToSymbol[lTotalCounter] = "TotalCounter"; + typeToSymbol[lSubCounter] = "SubCounter"; + typeToSymbol[lSubSubCounter] = "SubSubCounter"; + typeToSymbol[lTeamFee] = "TeamFee"; + + typeToSymbol[lRunnerTotalTime] = "RunnerTotalTime"; + typeToSymbol[lRunnerTimePerKM] = "RunnerTimePerKM"; + typeToSymbol[lRunnerTotalTimeStatus] = "RunnerTotalTimeStatus"; + typeToSymbol[lRunnerTotalPlace] = "RunnerTotalPlace"; + typeToSymbol[lRunnerTotalTimeAfter] = "RunnerTotalTimeAfter"; + typeToSymbol[lRunnerTimeAfterDiff] = "RunnerTimeAfterDiff"; + typeToSymbol[lRunnerPlaceDiff] = "RunnerPlaceDiff"; + + typeToSymbol[lRunnerGeneralTimeStatus] = "RunnerGeneralTimeStatus"; + typeToSymbol[lRunnerGeneralPlace] = "RunnerGeneralPlace"; + typeToSymbol[lRunnerGeneralTimeAfter] = "RunnerGeneralTimeAfter"; + + typeToSymbol[lTeamTotalTime] = "TeamTotalTime"; + typeToSymbol[lTeamTotalTimeStatus] = "TeamTotalTimeStatus"; + typeToSymbol[lTeamTotalPlace] = "TeamTotalPlace"; + typeToSymbol[lTeamTotalTimeAfter] = "TeamTotalTimeAfter"; + typeToSymbol[lTeamTotalTimeDiff] = "TeamTotalTimeDiff"; + typeToSymbol[lTeamPlaceDiff] = "TeamPlaceDiff"; + + typeToSymbol[lCountry] = "Country"; + typeToSymbol[lNationality] = "Nationality"; + + typeToSymbol[lControlName] = "ControlName"; + typeToSymbol[lControlCourses] = "ControlCourses"; + typeToSymbol[lControlClasses] = "ControlClasses"; + typeToSymbol[lControlVisitors] = "ControlVisitors"; + typeToSymbol[lControlPunches] = "ControlPunches"; + typeToSymbol[lControlMedianLostTime] = "ControlMedianLostTime"; + typeToSymbol[lControlMaxLostTime] = "ControlMaxLostTime"; + typeToSymbol[lControlMistakeQuotient] = "ControlMistakeQuotient"; + typeToSymbol[lControlRunnersLeft] = "ControlRunnersLeft"; + typeToSymbol[lControlCodes] = "ControlCodes"; + + for (map::iterator it = typeToSymbol.begin(); + it != typeToSymbol.end(); ++it) { + symbolToType[it->second] = it->first; + } + + if (typeToSymbol.size() != lLastItem) + throw std::exception("Bad symbol setup"); + + if (symbolToType.size() != lLastItem) + throw std::exception("Bad symbol setup"); + + baseTypeToSymbol[oListInfo::EBaseTypeRunner] = "Runner"; + baseTypeToSymbol[oListInfo::EBaseTypeTeam] = "Team"; + baseTypeToSymbol[oListInfo::EBaseTypeClub] = "ClubRunner"; + baseTypeToSymbol[oListInfo::EBaseTypePunches] = "Punches"; + baseTypeToSymbol[oListInfo::EBaseTypeNone] = "None"; + baseTypeToSymbol[oListInfo::EBaseTypeRunnerGlobal] = "RunnerGlobal"; + baseTypeToSymbol[oListInfo::EBaseTypeRunnerLeg] = "RunnerLeg"; + baseTypeToSymbol[oListInfo::EBaseTypeTeamGlobal] = "TeamGlobal"; + baseTypeToSymbol[oListInfo::EBaseTypeControl] = "Control"; + baseTypeToSymbol[oListInfo::EBaseTypeCourse] = "Course"; + + for (map::iterator it = baseTypeToSymbol.begin(); + it != baseTypeToSymbol.end(); ++it) { + symbolToBaseType[it->second] = it->first; + } + + if (baseTypeToSymbol.size() != oListInfo::EBasedTypeLast_) + throw std::exception("Bad symbol setup"); + + if (symbolToBaseType.size() != oListInfo::EBasedTypeLast_) + throw std::exception("Bad symbol setup"); + + orderToSymbol[ClassStartTime] = "ClassStartTime"; + orderToSymbol[ClassStartTimeClub] = "ClassStartTimeClub"; + orderToSymbol[ClassResult] = "ClassResult"; + orderToSymbol[ClassCourseResult] = "ClassCourseResult"; + orderToSymbol[SortByName] = "SortNameOnly"; + orderToSymbol[SortByLastName] = "SortLastNameOnly"; + orderToSymbol[SortByFinishTime] = "FinishTime"; + orderToSymbol[SortByFinishTimeReverse] = "FinishTimeReverse"; + orderToSymbol[ClassFinishTime] = "ClassFinishTime"; + orderToSymbol[SortByStartTime] = "StartTime"; + orderToSymbol[ClassPoints] = "ClassPoints"; + orderToSymbol[ClassTotalResult] = "ClassTotalResult"; + orderToSymbol[ClassTeamLegResult] = "ClassTeamLegResult"; + orderToSymbol[CourseResult] = "CourseResult"; + orderToSymbol[ClassTeamLeg] = "ClassTeamLeg"; + orderToSymbol[Custom] = "CustomSort"; + + for (map::iterator it = orderToSymbol.begin(); + it != orderToSymbol.end(); ++it) { + symbolToOrder[it->second] = it->first; + } + + if (orderToSymbol.size() != SortEnumLastItem) + throw std::exception("Bad symbol setup"); + + if (symbolToOrder.size() != SortEnumLastItem) + throw std::exception("Bad symbol setup"); + + filterToSymbol[EFilterHasResult] = "FilterResult"; + filterToSymbol[EFilterHasPrelResult] = "FilterPrelResult"; + filterToSymbol[EFilterRentCard] = "FilterRentCard"; + filterToSymbol[EFilterHasCard] = "FilterHasCard"; + filterToSymbol[EFilterExcludeDNS] = "FilterStarted"; + filterToSymbol[EFilterVacant] = "FilterNotVacant"; + filterToSymbol[EFilterOnlyVacant] = "FilterOnlyVacant"; + filterToSymbol[EFilterHasNoCard] = "FilterNoCard"; + + for (map::iterator it = filterToSymbol.begin(); + it != filterToSymbol.end(); ++it) { + symbolToFilter[it->second] = it->first; + } + + if (filterToSymbol.size() != _EFilterMax) + throw std::exception("Bad symbol setup"); + + if (symbolToFilter.size() != _EFilterMax) + throw std::exception("Bad symbol setup"); + + subFilterToSymbol[ESubFilterHasResult] = "FilterResult"; + subFilterToSymbol[ESubFilterHasPrelResult] = "FilterPrelResult"; + subFilterToSymbol[ESubFilterExcludeDNS] = "FilterStarted"; + subFilterToSymbol[ESubFilterVacant] = "FilterNotVacant"; + subFilterToSymbol[ESubFilterSameParallel] = "FilterSameParallel"; + subFilterToSymbol[ESubFilterSameParallelNotFirst] = "FilterSameParallelNotFirst"; + + for (map::iterator it = subFilterToSymbol.begin(); + it != subFilterToSymbol.end(); ++it) { + symbolToSubFilter[it->second] = it->first; + } + + if (subFilterToSymbol.size() != _ESubFilterMax) + throw std::exception("Bad symbol setup"); + + if (symbolToSubFilter.size() != _ESubFilterMax) + throw std::exception("Bad symbol setup"); + + + fontToSymbol[normalText] = "NormalFont"; + fontToSymbol[boldText] = "Bold"; + fontToSymbol[boldLarge] = "BoldLarge"; + fontToSymbol[boldHuge] = "BoldHuge"; + fontToSymbol[boldSmall] = "BoldSmall"; + fontToSymbol[fontLarge] = "LargeFont"; + fontToSymbol[fontMedium] = "MediumFont"; + fontToSymbol[fontMediumPlus] = "MediumPlus"; + fontToSymbol[fontSmall] = "SmallFont"; + fontToSymbol[italicSmall] = "SmallItalic"; + fontToSymbol[italicText] = "Italic"; + fontToSymbol[italicMediumPlus] = "ItalicMediumPlus"; + + fontToSymbol[formatIgnore] = "DefaultFont"; + + for (map::iterator it = fontToSymbol.begin(); + it != fontToSymbol.end(); ++it) { + symbolToFont[it->second] = it->first; + } + + if (fontToSymbol.size() != symbolToFont.size()) + throw std::exception("Bad symbol setup"); + + } +} + +MetaListContainer::MetaListContainer(oEvent *ownerIn): owner(ownerIn) {} + +MetaListContainer::~MetaListContainer() {} + + +const MetaList &MetaListContainer::getList(int index) const { + return data[index].second; +} + +MetaList &MetaListContainer::getList(int index) { + return data[index].second; +} + +MetaList &MetaListContainer::addExternal(const MetaList &ml) { + data.push_back(make_pair(ExternalList, ml)); + if (owner) + owner->updateChanged(); + return data.back().second; +} + +void MetaListContainer::clearExternal() { + globalIndex.clear(); + uniqueIndex.clear(); + while(!data.empty() && (data.back().first == ExternalList || data.back().first == RemovedList) ) + data.pop_back(); + + listParam.clear(); +} + +void MetaListContainer::save(MetaListType type, xmlparser &xml, const oEvent *oe) const { + + for (size_t k = 0; k id2Ix; + int count = 0; + for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { + id2Ix[it->first+1] = ++count; // One indexed + } + + for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { + it->second.serialize(xml, *this, id2Ix); + } + } +} + +bool MetaListContainer::load(MetaListType type, const xmlobject &xDef, bool ignoreOld) { + if (!xDef) + return true; + xmlList xList; + xDef.getObjects("MeOSListDefinition", xList); + string majVer = getMajorVersion(); + bool hasSkipped = false; + + if (xList.empty() && strcmp(xDef.getName(), "MeOSListDefinition") == 0) + xList.push_back(xDef); + string err; + for (size_t k = 0; k majVer) { + newVersion = true; + } + } + + data.push_back(make_pair(type, MetaList())); + try { + data.back().second.load(xList[k]); + } + catch (const std::exception &ex) { + if (newVersion && ignoreOld) + hasSkipped = true; + else if (err.empty()) + err = ex.what(); + + data.pop_back(); + } + } + + setupIndex(EFirstLoadedList); + + xmlList xParam; + xDef.getObjects("ListParam", xParam); + + for (size_t k = 0; k::iterator it = listParam.begin(); it != listParam.end(); ++it) { + int next = it->second.nextList; + if (next>0) { + int ix = next - 1; + if (listParam.count(ix)) { + if (listParam[ix].previousList == 0) + listParam[ix].previousList = it->first + 1; + else + it->second.nextList = 0; // Clear relation + } + else + it->second.nextList = 0; // Clear relation + } + } + + if (owner) + owner->updateChanged(); + + if (!err.empty()) + throw meosException(err); + + return !hasSkipped; +} + +bool MetaList::isValidIx(size_t gIx, size_t lIx, size_t ix) const { + return gIx < data.size() && lIx < data[gIx].size() && (ix == -1 || ix < data[gIx][lIx].size()); +} + +MetaListPost &MetaList::addNew(int groupIx, int lineIx, int &ix) { + if (isValidIx(groupIx, lineIx, -1)) { + ix = data[groupIx][lineIx].size(); + data[groupIx][lineIx].push_back(MetaListPost(lString)); + data[groupIx][lineIx].back().setResultModule(resultModule); + return data[groupIx][lineIx].back(); + } + else if (lineIx == -1 && size_t(groupIx) < data.size()) { + lineIx = data[groupIx].size(); + addRow(groupIx); + return addNew(groupIx, lineIx, ix); + } + throw meosException("Invalid index"); +} + +MetaListPost &MetaList::getMLP(int groupIx, int lineIx, int ix) { + if (isValidIx(groupIx, lineIx, ix)) { + return data[groupIx][lineIx][ix]; + } + else + throw meosException("Invalid index"); +} + +void MetaList::removeMLP(int groupIx, int lineIx, int ix) { + if (isValidIx(groupIx, lineIx, ix)) { + data[groupIx][lineIx].erase(data[groupIx][lineIx].begin() + ix); + if (data[groupIx][lineIx].empty() && data[groupIx].size() == lineIx + 1) + data[groupIx].pop_back(); + } + else + throw meosException("Invalid index"); +} + +void MetaList::moveOnRow(int groupIx, int lineIx, int &ix, int delta) { + if (isValidIx(groupIx, lineIx, ix)) { + if (ix > 0 && delta == -1) { + ix--; + swap(data[groupIx][lineIx][ix], data[groupIx][lineIx][ix+1]); + } + else if (delta == 1 && size_t(ix + 1) < data[groupIx][lineIx].size()) { + ix++; + swap(data[groupIx][lineIx][ix], data[groupIx][lineIx][ix-1]); + } + } + else + throw meosException("Invalid index"); + +} + +string MetaListContainer::getUniqueId(EStdListType code) const { + if (int(code) < int(EFirstLoadedList)) + return "C" + itos(code); + else { + size_t ix = int(code) - int(EFirstLoadedList); + if (ix < data.size()) { + if (!data[ix].second.getTag().empty()) + return "T" + data[ix].second.getTag(); + else + return data[ix].second.getUniqueId(); + } + else + return "C-1"; + } +} + +EStdListType MetaListContainer::getCodeFromUnqiueId(const string &id) const { + if (id[0] == 'C') + return EStdListType(atoi(id.substr(1).c_str())); + else if (id[0] == 'T') { + string tag = id.substr(1); + map::const_iterator res = tagIndex.find(tag); + if (res != tagIndex.end()) + return res->second; + else + return EStdNone; + } + else { + map::const_iterator res = uniqueIndex.find(id); + if (res != uniqueIndex.end()) + return res->second; + else + return EStdNone; + } +} + +void MetaListContainer::setupIndex(int firstIndex) const { + globalIndex.clear(); + uniqueIndex.clear(); + for (size_t k = 0; k &listMap, + bool resultsOnly) const { + setupIndex(firstIndex); + + for (size_t k = 0; k::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { + if (it->second.name.length() >= len) { + if (nameIn == it->second.name) + maxValue = max(1, maxValue); + else { + if (it->second.name.substr(0, len) == nameIn) { + int v = atoi(it->second.name.substr(len + 1).c_str()); + if (v > 0) + maxValue = max(v, maxValue); + } + } + } + } + if (maxValue == -1) + return nameIn; + else + return nameIn + " " + itos(maxValue + 1); +} + + +bool MetaListContainer::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, + int lineHeight, oListInfo &li) const { + + map::const_iterator it = globalIndex.find(par.listCode); + if (it != globalIndex.end()) { + data[it->second].second.interpret(oe, gdi, par, lineHeight, li); + return true; + } + return false; +} + +EStdListType MetaListContainer::getType(const std::string &tag) const { + map::iterator it = tagIndex.find(tag); + + if (it == tagIndex.end()) + throw meosException("Could not load list 'X'.#" + tag); + + return it->second; +} + +EStdListType MetaListContainer::getType(const int index) const { + return EStdListType(index + EFirstLoadedList); +} + +void MetaListContainer::getLists(vector > &lists, bool markBuiltIn, + bool resultListOnly, bool noTeamList) const { + lists.clear(); + for (size_t k = 0; k= MAXLISTPARAMID) { + toInsertAfter -= MAXLISTPARAMID; + swap(toMerge, toInsertAfter); + } + + oListParam &after = getParam(toInsertAfter); + oListParam &merge = getParam(toMerge); + merge.showInterTitle = showTitleBetween; + + int oldNext = after.nextList; + after.nextList = toMerge + 1; + merge.previousList = toInsertAfter + 1; + + if (oldNext > 0) { + oListParam &am = getParam(oldNext - 1); + am.previousList = toMerge + 1; + merge.nextList = oldNext; + } + + if (owner) + owner->updateChanged(); +} + +void MetaListContainer::getMergeCandidates(int toMerge, vector< pair > ¶m) const { + param.clear(); + for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { + if (it->first == toMerge) + continue; + + if (it->second.previousList == 0) { + string desc = "Före X#" + it->second.getName(); + param.push_back(make_pair(lang.tl(desc), MAXLISTPARAMID + it->first)); + } + + if (it->second.nextList == 0) { + string desc = "Efter X#" + it->second.getName(); + param.push_back(make_pair(lang.tl(desc), it->first)); + } + else { + const oListParam &next = getParam(it->second.nextList - 1); + string desc = "Mellan X och Y#" + it->second.getName() + "#" + next.getName(); + param.push_back(make_pair(lang.tl(desc), it->first)); + } + } +} + +bool MetaListContainer::canSplit(int index) const { + return getParam(index).nextList > 0; +} + +void MetaListContainer::split(int index) { + oListParam &par = getParam(index); + int n = par.nextList; + par.nextList = 0; + par.previousList = 0; + if (n > 0) { + split(n-1); + if (owner) + owner->updateChanged(); + } +} + +const string &MetaListContainer::getTag(int index) const { + if (size_t(index) >= data.size()) + throw meosException("Invalid index"); + + if (data[index].first != InternalList) + throw meosException("Invalid list type"); + + return data[index].second.getTag(); +} + +void MetaListContainer::removeList(int index) { + if (size_t(index) >= data.size()) + throw meosException("Invalid index"); + + if (data[index].first != ExternalList) + throw meosException("Invalid list type"); + + data[index].first = RemovedList; + if (owner) + owner->updateChanged(); +} + +void MetaListContainer::saveList(int index, const MetaList &ml) { + if (size_t(index) >= data.size()) + throw meosException("Invalid index"); + + if (data[index].first == InternalList) + throw meosException("Invalid list type"); + + data[index].first = ExternalList; + data[index].second = ml; + data[index].second.initUniqueIndex(); + if (owner) + owner->updateChanged(); +} + +void MetaList::getFilters(vector< pair > &filters) const { + filters.clear(); + for (map::const_iterator it = filterToSymbol.begin(); + it != filterToSymbol.end(); ++it) { + bool has = this->filter.count(it->first) == 1; + filters.push_back(make_pair(it->second, has)); + } +} + +void MetaList::setFilters(const vector &filters) { + int k = 0; + filter.clear(); + assert(filters.size() == filterToSymbol.size()); + for (map::const_iterator it = filterToSymbol.begin(); + it != filterToSymbol.end(); ++it) { + bool has = filters[k++]; + if (has) + filter.insert(it->first); + } +} + +void MetaList::getSubFilters(vector< pair > &filters) const { + filters.clear(); + for (map::const_iterator it = subFilterToSymbol.begin(); + it != subFilterToSymbol.end(); ++it) { + bool has = this->subFilter.count(it->first) == 1; + filters.push_back(make_pair(it->second, has)); + } +} + +void MetaList::setSubFilters(const vector &filters) { + int k = 0; + subFilter.clear(); + assert(filters.size() == subFilterToSymbol.size()); + for (map::const_iterator it = subFilterToSymbol.begin(); + it != subFilterToSymbol.end(); ++it) { + bool has = filters[k++]; + if (has) + subFilter.insert(it->first); + } +} + +void MetaList::getResultModule(const oEvent &oe, vector< pair > &modules, int ¤tModule) const { + modules.clear(); + vector< pair > > mol; + oe.getGeneralResults(false, mol, true); + modules.push_back(make_pair(lang.tl("Standard"), 0)); + currentModule = 0; + + for (size_t k = 0; k < mol.size(); k++) { + modules.push_back(make_pair(mol[k].second.second, mol[k].first)); + if (resultModule == mol[k].second.first) + currentModule = mol[k].first; + } +} + +MetaList &MetaList::setResultModule(const oEvent &oe, int moduleIx) { + vector< pair > > mol; + oe.getGeneralResults(false, mol, false); + if (moduleIx == 0) { + //resultModule = ""; + retagResultModule("", false); + return *this; + } + else { + for (size_t k = 0; k < mol.size(); k++) { + if (moduleIx == mol[k].first) { + retagResultModule(mol[k].second.first, false); + return *this; + } + } + } + throw meosException("Unknown result module"); +} + +MetaList &MetaList::setSupportFromTo(bool from, bool to) { + supportFromControl = from; + supportToControl = to; + return *this; +} + +void MetaList::getSortOrder(bool forceIncludeCustom, vector< pair > &orders, int ¤tOrder) const { + orders.clear(); + for(map::const_iterator it = orderToSymbol.begin(); + it != orderToSymbol.end(); ++it) { + if (it->first != Custom || forceIncludeCustom || !resultModule.empty() || currentOrder == Custom) + orders.push_back(make_pair(lang.tl(it->second), it->first)); + } + currentOrder = sortOrder; +} + +void MetaList::getBaseType(vector< pair > &types, int ¤tType) const { + types.clear(); + for(map::const_iterator it = baseTypeToSymbol.begin(); + it != baseTypeToSymbol.end(); ++it) { + if (it->first == oListInfo::EBaseTypeNone || it->first == oListInfo::EBaseTypePunches) + continue; + types.push_back(make_pair(lang.tl(it->second), it->first)); + } + + currentType = listType; +} + +void MetaList::getSubType(vector< pair > &types, int ¤tType) const { + types.clear(); + + oListInfo::EBaseType t; + set tt; + + t = oListInfo::EBaseTypeNone; + tt.insert(t); + types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); + + t = oListInfo::EBaseTypePunches; + tt.insert(t); + types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); + + t = oListInfo::EBaseTypeRunner; + tt.insert(t); + types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); + + if (tt.count(listSubType) == 0) { + t = listSubType; + types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); + } + + currentType = listSubType; +} + +int MetaListContainer::getNumLists(MetaListType t) const { + int num = 0; + for (size_t k = 0; k > ¶m) const { + for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { + if (it->second.previousList > 0) + continue; + param.push_back(make_pair(it->second.getName(), it->first)); + } +} + +void MetaListContainer::removeParam(int index) { + if (listParam.count(index)) { + listParam[index].previousList = 0; + if (listParam[index].nextList > 0) { + oListParam &next = getParam(listParam[index].nextList - 1); + if (next.previousList == index + 1) + removeParam(listParam[index].nextList-1); + } + listParam.erase(index); + if (owner) + owner->updateChanged(); + } + else + throw meosException("No such parameters exist"); +} + +void MetaListContainer::addListParam(oListParam ¶m) { + param.saved = true; + int ix = 0; + if (!listParam.empty()) + ix = listParam.rbegin()->first + 1; + + listParam[ix] = param; + if (owner) + owner->updateChanged(); +} + +const oListParam &MetaListContainer::getParam(int index) const { + if (!listParam.count(index)) + throw meosException("Internal error"); + return listParam.find(index)->second; +} + +oListParam &MetaListContainer::getParam(int index) { + if (!listParam.count(index)) + throw meosException("Internal error"); + + return listParam.find(index)->second; +} + +void MetaListContainer::enumerateLists(vector< pair > > &out) const { + out.clear(); + char bf[260]; + getUserFile(bf, ""); + vector res; + expandDirectory(bf, "*.meoslist", res); + for (size_t k = 0; k < res.size(); k++) { + xmlparser xml(0); + try { + xml.read(res[k].c_str(), 6); + xmlobject xDef = xml.getObject("MeOSListDefinition"); + string name; + xDef.getObjectString("ListName", name); + string origin; + xDef.getObjectString("ListOrigin", origin); + string uid; + xDef.getObjectString("UID", uid); + + if (!origin.empty()) + name += MakeDash(" - ") + origin; + out.push_back(make_pair(name, make_pair(uid, res[k]))); + } + catch (std::exception &) { // Ignore log?! + out.push_back(make_pair("Error? " + res[k], make_pair("?", res[k]))); + } + } + sort(out.begin(), out.end()); + +} + +int MetaList::getResultModuleIndex(oEvent *oe, oListInfo &li, const MetaListPost &lp) const { + if (resultToIndex.empty()) { + vector< pair > > tagNameList; + oe->getGeneralResults(false, tagNameList, false); + resultToIndex[""] = -1; + for (size_t k = 0; k < tagNameList.size(); k++) { + resultToIndex[tagNameList[k].second.first] = k; + } + } + + if (resultToIndex.count(lp.resultModule) == 0) + throw meosException("Unknown result module: " + lp.resultModule); + + if (!lp.resultModule.empty()) + li.additionalResultModule(lp.resultModule); + + return resultToIndex[lp.resultModule]; +} + +void MetaListContainer::getListsByResultModule(const string &tag, vector &listIx) const { + listIx.clear(); + for (size_t k = 0; k. + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class oListInfo; +enum EPostType; +#include "oListInfo.h" +#include "oEvent.h" +#include +class xmlparser; +class xmlobject; +enum gdiFonts; +class oEvent; + +const string &itos(int); + +class Position +{ + struct PosInfo { + PosInfo(int f, int wid) : first(f), width(wid), aligned(false), originalPos(f) {} + int first; // Actual position + int width; // Original block width + bool aligned;// True if aligned + const int originalPos; // Original position + void operator=(const PosInfo &) {throw std::exception("Unsupported");} + }; + map pmap; + vector< PosInfo > pos; // Pair of position, specified (minimal) width + void update(int ix, const string &newname, int width, bool alignBlock, bool alignLock); + +public: + + int getWidth() const; + + bool postAdjust(); + + void add(const string &name, const int width, int blockWidth); + void add(const string &name, const int width) { + add(name, width, width); + } + + void update(const string &oldname, const string &newname, + const int width, bool alignBlock, bool alignLock); + void alignNext(const string &newname, const int width, bool alignBlock); + + void newRow(); + + int get(const string &name); + int get(const string &name, double scale); + int getOriginalPos(const string &name); + int getOriginalPos(const string &name, double scale); + + void indent(int ind); +}; + +class MetaListPost { +private: + void serialize(xmlparser &xml) const; + void deserialize(const xmlobject &xml); + + EPostType type; + string text; + string alignWithText; + string resultModule; + EPostType alignType; + int leg; + int minimalIndent; + bool alignBlock; // True if the next item should also be align (table style block) + int blockWidth; + bool mergeWithPrevious; + gdiFonts font; + int textAdjust; // 0, textRight, textCenter + GDICOLOR color; +public: + + MetaListPost(EPostType type_, EPostType align_ = lNone, int leg_ = -1); + + MetaListPost &setBlock(int width) {blockWidth = width; return *this;} + MetaListPost &setText(const string &text_) {text = text_; return *this;} + MetaListPost &setResultModule(const string &resMod) {resultModule = resMod; return *this;} + + MetaListPost &align(EPostType align_, bool alignBlock_ = true) {alignType = align_; alignBlock = alignBlock_; return *this;} + MetaListPost &align(bool alignBlock_ = true) {return align(lAlignNext, alignBlock_);} + MetaListPost &alignText(const string &t) {alignWithText = t; return *this;} + MetaListPost &mergePrevious(bool m_=true) {mergeWithPrevious = m_; return *this;} + + MetaListPost &indent(int ind) {minimalIndent = ind; return *this;} + + void getTypes(vector< pair > &types, int ¤tType) const; + + const string &getType() const; + MetaListPost &setType(EPostType type_) {type = type_; return *this;} + + const string &getText() const {return text;} + const string &getResultModule() const {return resultModule;} + const string &getAlignText() const {return alignWithText;} + + int getLeg() const {return leg;} + void setLeg(int leg_) {leg = leg_;} + + int getMinimalIndent() const {return minimalIndent;} + bool getAlignBlock() const {return alignBlock;} + bool isMergePrevious() const {return mergeWithPrevious;} + + int getBlockWidth() const {return blockWidth;} + + const string &getFont() const; + void setFont(gdiFonts font_) {font = font_;} + + void getFonts(vector< pair > &fonts, int ¤tFont) const; + + const string &getTextAdjust() const; + int getTextAdjustNum() const {return textAdjust;} + void setTextAdjust(int align); + const string &getColor() const; + void setColor(GDICOLOR color); + GDICOLOR getColorValue() const {return color;} + + static void getAllFonts(vector< pair > &fonts); + + friend class MetaList; +}; + +struct DynamicResultRef { + DynamicResultRef(const DynamicResult *resIn, MetaList *ctrIn) : res(resIn), ctr(ctrIn) {} + DynamicResultRef() : res(0), ctr(0) {} + const DynamicResult *res; + MetaList *ctr; +}; + +class MetaList { +private: + + struct FontInfo { + string font; + int scale; + int extraSpaceAbove; + + FontInfo() : scale(0), extraSpaceAbove(0) {} + + const vector< pair > &serialize(vector< pair > &props) const { + props[0].first = "scale"; + props[0].second = itos(scale); + props[1].first = "above"; + props[1].second = itos(extraSpaceAbove); + return props; + } + }; + + vector< vector< vector > > data; + vector fontFaces; + + string listName; + mutable string listOrigin; + string tag; + mutable string uniqueIndex; + + mutable bool hasResults_; + + oListInfo::EBaseType listType; + oListInfo::EBaseType listSubType; + SortOrder sortOrder; + + set filter; + set subFilter; + vector dynamicResults; + + string resultModule; + bool supportFromControl; + bool supportToControl; + + enum ListIndex {MLHead = 0, MLSubHead = 1, MLList = 2, MLSubList=3}; + MetaListPost &add(ListIndex ix, const MetaListPost &post); + void addRow(int ix); + string encode(const string &input) const; + bool isBreak(int x) const; + + static map typeToSymbol; + static map symbolToType; + + static map baseTypeToSymbol; + static map symbolToBaseType; + + static map orderToSymbol; + static map symbolToOrder; + + static map filterToSymbol; + static map symbolToFilter; + + static map subFilterToSymbol; + static map symbolToSubFilter; + + static map fontToSymbol; + static map symbolToFont; + + static void initSymbols(); + + void serialize(xmlparser &xml, const string &tag, + const vector< vector > &lp) const; + void deserialize(const xmlobject &xml, vector< vector > &lp); + + int getResultModuleIndex(oEvent *oe, oListInfo &li, const MetaListPost &lp) const; + mutable map resultToIndex; + +public: + MetaList(); + virtual ~MetaList() {} + + bool supportClasses() const; + + const string &getListInfo(const oEvent &oe) const; + void clearTag() {tag.clear();} + + void initUniqueIndex() const; + const string &getUniqueId() const { + if (uniqueIndex.empty()) + initUniqueIndex(); + return uniqueIndex; + } + + void retagResultModule(const string &newTag, bool retagStoredModule); + bool updateResultModule(const DynamicResult &dr, bool updateSimilar); + + void getDynamicResults(vector &resultModules) const; + void getFilters(vector< pair > &filters) const; + void setFilters(const vector &filters); + void getSubFilters(vector< pair > &filters) const; + void setSubFilters(const vector &filters); + + void getResultModule(const oEvent &oe, vector< pair > &modules, int ¤tModule) const; + const string &getResultModule() const {return resultModule;} + + MetaList &setSupportFromTo(bool from, bool to); + bool supportFrom() const {return supportFromControl;} + bool supportTo() const {return supportToControl;} + void getSortOrder(bool forceIncludeCustom, vector< pair > &orders, int ¤tOrder) const; + void getBaseType(vector< pair > &types, int ¤tType) const; + void getSubType(vector< pair > &types, int ¤tType) const; + + const string &getFontFace(int type) const {return fontFaces[type].font;} + int getFontFaceFactor(int type) const {return fontFaces[type].scale;} + int getExtraSpace(int type) const {return fontFaces[type].extraSpaceAbove;} + + MetaList &setFontFace(int type, const string &face, int factor) { + fontFaces[type].font = face; + fontFaces[type].scale = factor; + return *this; + } + + MetaList &setExtraSpace(int type, int space) { + fontFaces[type].extraSpaceAbove = space; + return *this; + } + + void getExistingTypes(vector< pair > &types) const; + + const string &getListName() const {return listName;} + oListInfo::EBaseType getListType() const; + + oListInfo::ResultType getResultType() const; // Classwise or global + + bool hasResults() const {return hasResults_;} + const string &getTag() const {return tag;} + + void getAlignTypes(const MetaListPost &mlp, vector< pair > &types, int ¤tType) const; + void getIndex(const MetaListPost &mlp, int &gix, int &lix, int &ix) const; + + MetaList &setResultModule(const oEvent &oe, int moduleIx); + + MetaList &setListType(oListInfo::EBaseType t) {listType = t; return *this;} + MetaList &setSubListType(oListInfo::EBaseType t) {listSubType = t; return *this;} + MetaList &setSortOrder(SortOrder so) {sortOrder = so; return *this;} + + MetaList &addFilter(EFilterList f) {filter.insert(f); return *this;} + MetaList &addSubFilter(ESubFilterList f) {subFilter.insert(f); return *this;} + + void save(const string &file, const oEvent *oe) const; + void load(const string &file); + + bool isValidIx(size_t gIx, size_t lIx, size_t ix) const; + + void save(xmlparser &xml, const oEvent *oe) const; + void load(const xmlobject &xDef); + + void interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, + int lineHeight, oListInfo &li) const; + + MetaList &setListName(const string &title) {listName = title; return *this;} + + MetaListPost &addNew(int groupIx, int lineIx, int &ix); + MetaListPost &getMLP(int groupIx, int lineIx, int ix); + void removeMLP(int groupIx, int lineIx, int ix); + void moveOnRow(int groupIx, int lineIx, int &ix, int delta); + + MetaListPost &addToHead(const MetaListPost &post) {return add(MLHead, post);} + MetaListPost &addToSubHead(const MetaListPost &post) {return add(MLSubHead, post).setBlock(10);} + MetaListPost &addToList(const MetaListPost &post) {return add(MLList, post);} + MetaListPost &addToSubList(const MetaListPost &post) {return add(MLSubList, post);} + + const vector< vector > &getList() const {return data[MLList];} + const vector< vector > &getSubList() const {return data[MLSubList];} + const vector< vector > &getHead() const {return data[MLHead];} + const vector< vector > &getSubHead() const {return data[MLSubHead];} + + vector< vector > &getList() {return data[MLList];} + vector< vector > &getSubList() {return data[MLSubList];} + vector< vector > &getHead() {return data[MLHead];} + vector< vector > &getSubHead() {return data[MLSubHead];} + + void newListRow() {addRow(MLList);} + void newSubListRow() {addRow(MLSubList);} + void newHead() {addRow(MLHead);} + void newSubHead() {addRow(MLSubHead);} + + friend class MetaListPost; +}; + +class MetaListContainer { +public: + enum MetaListType {InternalList, ExternalList, RemovedList}; +private: + vector< pair > data; + mutable map globalIndex; + mutable map tagIndex; + mutable map uniqueIndex; + + map listParam; + oEvent *owner; +public: + + MetaListContainer(oEvent *owner); + virtual ~MetaListContainer(); + + string getUniqueId(EStdListType code) const; + EStdListType getCodeFromUnqiueId(const string &id) const; + string makeUniqueParamName(const string &nameIn) const; + + bool updateResultModule(const DynamicResult &res, bool updateSimilar); + + int getNumParam() const {return listParam.size();} + int getNumLists() const {return data.size();} + int getNumLists(MetaListType) const; + + EStdListType getType(const string &tag) const; + EStdListType getType(const int index) const; + + const MetaList &getList(int index) const; + MetaList &getList(int index); + + const oListParam &getParam(int index) const; + oListParam &getParam(int index); + + void getListsByResultModule(const string &tag, vector &listIx) const; + + MetaList &addExternal(const MetaList &ml); + void clearExternal(); + + void getLists(vector< pair > &lists, + bool markBuiltIn, + bool resultListOnly, + bool noTeamList) const; + + const string &getTag(int index) const; + + void removeList(int index); + void saveList(int index, const MetaList &ml); + bool isInternal(int index) const {return data[index].first == InternalList;} + bool isExternal(int index) const {return data[index].first == ExternalList;} + + void save(MetaListType type, xmlparser &xml, const oEvent *oe) const; + /** Returns true if all lists where loaded, false if some list was in a unnsupported version and ignoreOld was set. + Throws if some list was incorrect. */ + bool load(MetaListType type, const xmlobject &xDef, bool ignoreOld); + + void setupListInfo(int firstIndex, map &listMap, bool resultsOnly) const; + void setupIndex(int firstIndex) const; + + void getListParam( vector< pair > ¶m) const; + void removeParam(int index); + void addListParam(oListParam &listParam); + + void mergeParam(int toInsertAfter, int toMerge, bool showTitleBetween); + void getMergeCandidates(int toMerge, vector< pair > ¶m) const; + bool canSplit(int index) const; + void split(int index); + + bool interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, + int lineHeight, oListInfo &li) const; + + void enumerateLists(vector< pair > > &out) const; +}; diff --git a/code/methodeditor.cpp b/code/methodeditor.cpp new file mode 100644 index 0000000..b2629de --- /dev/null +++ b/code/methodeditor.cpp @@ -0,0 +1,1067 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include + +#include "methodeditor.h" +#include "generalresult.h" +#include "gdioutput.h" +#include "meosexception.h" +#include "gdistructures.h" +#include "meos_util.h" +#include "localizer.h" +#include "gdifonts.h" +#include "oEvent.h" +#include "tabbase.h" +#include "CommDlg.h" +#include "random.h" +#include "metalist.h" + +MethodEditor::MethodEditor(oEvent *oe_) { + oe = oe_; + inputNumber = 0; + currentResult = 0; + currentIndex = -1; + dirtyInt = false; + wasLoadedBuiltIn = false; +} + +MethodEditor::~MethodEditor() { + setCurrentResult(0, ""); +} + +void MethodEditor::setCurrentResult(DynamicResult *lst, const string &fileSrc) { + delete currentResult; + currentResult = lst; + fileNameSource = fileSrc; +} + +int methodCB(gdioutput *gdi, int type, void *data) { + void *clz = gdi->getData("MethodEditorClz"); + MethodEditor *le = (MethodEditor *)clz; + BaseInfo *bi = (BaseInfo *)data; + if (le) + return le->methodCb(*gdi, type, *bi); + + throw meosException("Unexpected error"); +} + +void MethodEditor::show(gdioutput &gdi) { + oe->loadGeneralResults(true); + + gdi.setRestorePoint("BeginMethodEdit"); + + gdi.pushX(); + gdi.setCX(gdi.getCX() + gdi.scaleLength(6)); + if (currentResult) + gdi.addString("", boldLarge, MakeDash("Result Module - X#") + currentResult->getName(true)); + else + gdi.addString("", boldLarge, "Edit Result Modules"); + + gdi.setOnClearCb(methodCB); + gdi.setData("MethodEditorClz", this); + gdi.dropLine(0.5); + gdi.fillRight(); + + gdi.addButton("OpenFile", "Importera från fil", methodCB); + gdi.addButton("OpenInside", "Öppna", methodCB); + + if (currentResult) { + gdi.addButton("SaveFile", "Exportera till fil...", methodCB); + gdi.addButton("SaveInside", "Spara", methodCB); + gdi.addButton("Remove", "Ta bort", methodCB); + + makeDirty(gdi, NoTouch); + } + + gdi.addButton("NewRules", "New Result Module", methodCB); + gdi.addButton("Close", "Stäng", methodCB); + +#ifdef _DEBUG + gdi.addButton("WriteDoc", "#WriteDoc", methodCB); +#endif + gdi.popX(); + gdi.dropLine(2); + gdi.fillDown(); + + if (currentResult) { + gdi.dropLine(0.5); + if (currentResult->getTag().empty()) + currentResult->setTag(uniqueTag("result")); + + gdi.addInput("Name", currentResult->getName(false), 20, methodCB, "Name of result module:"); + + string tag = currentResult->getTag(); + vector listIx; + oe->getListContainer().getListsByResultModule(tag, listIx); + + string udtag = DynamicResult::undecorateTag(tag); + gdi.addInput("Tag", udtag, 20, methodCB, "Result module identifier:"); + if (!listIx.empty()) { + gdi.disableInput("Tag"); + gdi.getBaseInfo("Tag").setExtra(1); + string lists = oe->getListContainer().getList(listIx.front()).getListName(); + if (listIx.size() > 1) + lists += ", ..."; + gdi.addString("", 0, "Resultatmodulen används i X.#" + lists); + } + + string desc = currentResult->getDescription(); + if (wasLoadedBuiltIn) + desc = lang.tl(desc); + + gdi.addInputBox("Desc", 300, 70, desc, methodCB, "Description:"); + + gdi.dropLine(); + gdi.fillRight(); + gdi.addSelection("Method", 200, 200, methodCB, "Edit rule for:"); + vector< pair > mt; + currentResult->getMethodTypes(mt); + + for (size_t k = 0; k < mt.size(); k++) + gdi.addItem("Method", lang.tl(mt[k].second), mt[k].first); + + gdi.dropLine(); + gdi.addButton("SaveSource", "Save changes", methodCB); + gdi.addButton("CancelSource", "Cancel", methodCB); + gdi.addButton("TestRule", "Test Result Module", methodCB); + gdi.disableInput("SaveSource"); + gdi.disableInput("CancelSource"); + gdi.dropLine(2); + gdi.popX(); + gdi.fillDown(); + + gdi.setRestorePoint("TestRule"); + } + + gdi.refresh(); +} + +bool MethodEditor::checkTag(const string &tag, bool throwError) const { + vector< pair > > tagNameList; + oe->getGeneralResults(false, tagNameList, false); + for (size_t k = 0; k < tag.length(); k++) { + char c = tag[k]; + if (c == '-' || c == '_' || c == '%') + continue; + if (!isalnum(c)) { + if (throwError) + throw meosException("Invalid character in tag X.#" + tag); + else + return false; + } + } + if (tag.empty()) { + if (throwError) + throw meosException("Empty tag is invalid"); + else + return false; + } + for (size_t k = 0; k < tagNameList.size(); k++) { + if (_strcmpi(tagNameList[k].second.first.c_str(), tag.c_str()) == 0) { + if (throwError) + throw meosException("The tag X is in use.#" + tag); + else + return false; + } + } + return true; +} + +string MethodEditor::uniqueTag(const string &tag) const { + vector< pair > > tagNameList; + oe->getGeneralResults(false, tagNameList, false); + set tags; + for (size_t k = 0; k < tagNameList.size(); k++) + tags.insert(tagNameList[k].second.first); + + int a = GetRandomNumber(65536); + srand(GetTickCount()); + int b = rand() % 65536; + char un[64]; + sprintf_s(un, "-%04X-%04X-", a, b); + int iter = 0; + while (tags.count(tag + un + itos(++iter))); + return tag + un + itos(iter); +} + +int MethodEditor::methodCb(gdioutput &gdi, int type, BaseInfo &data) { + if (type == GUI_BUTTON) { + ButtonInfo bi = dynamic_cast(data); + + if (bi.id == "Cancel") { + gdi.restore("EditList"); + gdi.enableInput("EditList"); + } + else if (bi.id == "CloseWindow") { + gdi.closeWindow(); + } + else if (bi.id == "WriteDoc") { + ofstream fout("methoddoc.txt"); + DynamicResult dr; + dr.declareSymbols(DynamicResult::MRScore, true); + vector< pair > symbs; + dr.getSymbols(symbs); + fout << "#head{" << lang.tl("Deltagare") << "}\n#table{2}" << endl; + for (size_t k = 0; k < symbs.size(); k++) { + string name, desc; + dr.getSymbolInfo(symbs[k].second, name, desc); + fout << "{#mono{" << name << "}}{" << lang.tl(desc) << "}" << endl; + } + + dr.declareSymbols(DynamicResult::MTScore, true); + dr.getSymbols(symbs); + fout << "#head{" << lang.tl("Lag") << "}\n#table{2}" << endl; + for (size_t k = 0; k < symbs.size(); k++) { + string name, desc; + dr.getSymbolInfo(symbs[k].second, name, desc); + fout << "{#mono{" << name << "}}{" << lang.tl(desc) << "}" << endl; + } + } + else if (bi.id == "NewRules") { + if (!checkSave(gdi)) + return 0; + gdi.clearPage(false); + gdi.setData("MethodEditorClz", this); + gdi.addString("", boldLarge, "New Set of Result Rules"); + + setCurrentResult(new DynamicResult(), ""); + wasLoadedBuiltIn = false; + currentResult->setName(lang.tl("Result Calculation")); + currentIndex = -1; + makeDirty(gdi, ClearDirty); + show(gdi); + gdi.setInputStatus("Remove", resultIsInstalled()); + } + else if (bi.id == "SaveFile") { + if (!currentResult) + return 0; + checkChangedSave(gdi); + + string fileName; + + int ix = 0; + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.rules")); + fileName = gdi.browseForSave(ext, "rules", ix); + if (fileName.empty()) + return 0; + + saveSettings(gdi); + string path = fileNameSource.empty() ? getInternalPath(currentResult->getTag()) : fileNameSource; + currentResult->save(path); + fileNameSource = path; + oe->loadGeneralResults(true); + makeDirty(gdi, ClearDirty); + + currentResult->save(fileName); + //savedFileName = fileName; + return 1; + } + else if (bi.id == "SaveInside") { + if (!currentResult) + return 0; + saveSettings(gdi); + checkChangedSave(gdi); + + string path = fileNameSource.empty() ? getInternalPath(currentResult->getTag()) : fileNameSource; + currentResult->save(path); + fileNameSource = path; + + int nl = oe->getListContainer().getNumLists(); + string utag = DynamicResult::undecorateTag(currentResult->getTag()); + bool doUpdate = false; + for (int j = 0; j < nl && !doUpdate; j++) { + if (!oe->getListContainer().isExternal(j)) + continue; + + const string &mtag = oe->getListContainer().getList(j).getResultModule(); + if (mtag.empty() || currentResult->getTag() == mtag) + continue; + + if (utag == DynamicResult::undecorateTag(mtag)) { + doUpdate = gdi.ask("Vill du uppdatera resultatlistorna i den öppande tävlingen?"); + break; + } + } + + oe->synchronize(false); + oe->getListContainer().updateResultModule(*currentResult, doUpdate); + + oe->loadGeneralResults(true); + + oe->synchronize(true); + + makeDirty(gdi, ClearDirty); + gdi.setInputStatus("Remove", resultIsInstalled()); + return 1; + } + else if (bi.id == "Remove") { + if (!currentResult) + return 0; + if (gdi.ask("Vill du ta bort 'X'?#" + currentResult->getName(true))) { + string path = fileNameSource;//getInternalPath(currentResult->getTag()); + string rm = path + ".removed"; + DeleteFile(rm.c_str()); + rename(path.c_str(), rm.c_str()); + oe->loadGeneralResults(true); + makeDirty(gdi, ClearDirty); + setCurrentResult(0, ""); + gdi.clearPage(false); + show(gdi); + } + return 1; + } + else if (bi.id == "OpenFile") { + if (!checkSave(gdi)) + return 0; + + vector< pair > ext; + ext.push_back(make_pair("xml-data", "*.rules")); + string fileName = gdi.browseForOpen(ext, "rules"); + if (fileName.empty()) + return 0; + + DynamicResult *tmp = new DynamicResult(); + try { + tmp->load(fileName); + } + catch(...) { + delete tmp; + throw; + } + + wasLoadedBuiltIn = false; + setCurrentResult(tmp, ""); + currentIndex = -1; + gdi.clearPage(false); + + //savedFileName = fileName; + makeDirty(gdi, ClearDirty); + show(gdi); + } + else if (bi.id == "OpenInside") { + if (!checkSave(gdi)) + return 0; + + gdi.clearPage(true); + gdi.setOnClearCb(methodCB); + gdi.setData("MethodEditorClz", this); + + gdi.pushX(); + vector< pair > lists; + //oe->getListContainer().getLists(lists); + vector< pair > > tagNameList; + oe->getGeneralResults(true, tagNameList, true); + for (size_t k = 0; k < tagNameList.size(); k++) { + string tag = tagNameList[k].second.first; + string utag = DynamicResult::undecorateTag(tag); + vector listIx; + oe->getListContainer().getListsByResultModule(tag, listIx); + string n = tagNameList[k].second.second + " (" + utag + ")"; + + if (listIx.size() > 0) { + n += " *"; + } + + lists.push_back(make_pair(n, tagNameList[k].first)); + } + sort(lists.begin(), lists.end()); + gdi.fillRight(); + gdi.addSelection("OpenList", 350, 400, methodCB, "Choose result module:", "Rader markerade med (*) kommer från en lista i tävlingen."); + gdi.addItem("OpenList", lists); + gdi.autoGrow("OpenList"); + gdi.selectFirstItem("OpenList"); + + gdi.dropLine(); + gdi.addButton("DoOpen", "Öppna", methodCB); + gdi.addButton("DoOpenCopy", "Open a Copy", methodCB); + + if (!lists.empty()) { + string srcFile; + + bool ro = dynamic_cast(oe->getGeneralResult(tagNameList.front().second.first, srcFile)).isReadOnly(); + gdi.setInputStatus("DoOpen", !ro); + } + else { + gdi.disableInput("DoOpen"); + gdi.disableInput("DoOpenCopy"); + } + + gdi.addButton("CancelReload", "Avbryt", methodCB); + gdi.dropLine(4); + gdi.popX(); + } + else if (bi.id == "DoOpen" || bi.id == "DoOpenCopy") { + ListBoxInfo lbi; + DynamicResult *dr = 0; + if (gdi.getSelectedItem("OpenList", lbi)) { + vector< pair > > tagNameList; + oe->getGeneralResults(true, tagNameList, false); + size_t ix = -1; + for (size_t k = 0; k < tagNameList.size(); k++) { + if (tagNameList[k].first == lbi.data) { + ix = k; + break; + } + } + + if (ix < tagNameList.size()) { + string srcFile; + DynamicResult &drIn = dynamic_cast(oe->getGeneralResult(tagNameList[ix].second.first, srcFile)); + wasLoadedBuiltIn = drIn.isReadOnly(); + dr = new DynamicResult(drIn); + if (bi.id == "DoOpenCopy") { + dr->setTag(uniqueTag("result")); + dr->setName(lang.tl("Copy of ") + dr->getName(false)); + setCurrentResult(dr, ""); + } + else + setCurrentResult(dr, srcFile); + } + + if (bi.id == "DoOpen") + makeDirty(gdi, ClearDirty); + else + makeDirty(gdi, MakeDirty); + + gdi.clearPage(false); + show(gdi); + if (dr) dr->compile(true); + } + } + else if (bi.id == "CancelReload") { + gdi.clearPage(false); + show(gdi); + } + else if (bi.id == "Close") { + if (!checkSave(gdi)) + return 0; + + setCurrentResult(0, ""); + makeDirty(gdi, ClearDirty); + currentIndex = -1; + gdi.getTabs().get(TListTab)->loadPage(gdi); + return 0; + } + else if (bi.id == "SaveSource") { + DynamicResult::DynamicMethods dm = DynamicResult::DynamicMethods(bi.getExtraInt()); + string src = gdi.getText("Source"); + currentResult->setMethodSource(dm, src); + gdi.setText("Source", src); + } + else if (bi.id == "CancelSource") { + checkChangedSave(gdi); + gdi.restore("NoSourceEdit", true); + gdi.selectItemByData("Method", -1); + gdi.disableInput("SaveSource"); + gdi.disableInput("CancelSource"); + } + else if (bi.id == "TestRule") { + checkChangedSave(gdi); + + gdi.restore("TestRule", false); + gdi.setRestorePoint("TestRule"); + gdi.disableInput("SaveSource"); + gdi.disableInput("CancelSource"); + gdi.selectItemByData("Method", -1); + + int y = gdi.getCY(); + vector r; + vector t; + oe->getRunners(0, 0, r, true); + oe->getTeams(0, t, true); + vector rr; + vector tr; + for (size_t k = 0; k < r.size(); k++) { + if (r[k]->getStatus() != StatusUnknown) + rr.push_back(r[k]); + } + for (size_t k = 0; k < t.size(); k++) { + if (t[k]->getStatus() != StatusUnknown) + tr.push_back(t[k]); + else { + for (int j = 0; j < t[k]->getNumRunners(); j++) { + if (t[k]->getRunner(j) && t[k]->getRunner(j)->getStatus() != StatusUnknown) { + tr.push_back(t[k]); + break; + } + } + } + } + gdi.fillDown(); + if (tr.size() + rr.size() == 0) { + gdi.addString("", 1, "Tävlingen innehåller inga resultat").setColor(colorRed); + } + else + gdi.addString("", 1, "Applying rules to the current competition"); + gdi.dropLine(0.5); + int xp = gdi.getCX(); + int yp = gdi.getCY(); + int diff = gdi.scaleLength(3); + const int w[5] = {200, 70, 70, 70, 85}; + set errors; + currentResult->prepareCalculations(*oe, tr.size()>0, inputNumber); + + for (size_t k = 0; k < rr.size(); k++) { + int txp = xp; + int wi = 0; + gdi.addStringUT(yp, txp, 0, rr[k]->getCompleteIdentification(), w[wi]-diff); + txp += w[wi++]; + currentResult->prepareCalculations(*rr[k]); + int rt = 0, pt = 0; + RunnerStatus st = StatusUnknown; + { + string err; + string str; + try { + st = currentResult->deduceStatus(*rr[k]); + str = oe->formatStatus(st); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + RECT rc = ti.textRect; + gdi.addToolTip("", err, 0, &rc); + } + txp += w[wi++]; + } + { + string err; + string str; + try { + rt = currentResult->deduceTime(*rr[k], rr[k]->getStartTime()); + str = formatTime(rt); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + + { + string err; + string str; + try { + pt = currentResult->deducePoints(*rr[k]); + str = itos(pt); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + + { + string err; + string str; + try { + int score = currentResult->score(*rr[k], st, rt, pt, false); + str = itos(score); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + rr[k]->setTempResultZero(oAbstractRunner::TempResult(st, rr[k]->getStartTime(), rt, pt)); + + gdi.addString("Debug", yp, txp, 0, "Debug...", 0, methodCB).setColor(colorGreen).setExtra(rr[k]->getId()); + yp += gdi.getLineHeight(); + } + + yp += gdi.getLineHeight(); + + if (tr.size() > 0) { + gdi.addString("", yp, xp, 1, "Lag"); + yp += gdi.getLineHeight(); + } + else { + } + + for (size_t k = 0; k < tr.size(); k++) { + int txp = xp; + int wi = 0; + gdi.addStringUT(yp, txp, 0, tr[k]->getName(), w[wi]-diff); + txp += w[wi++]; + currentResult->prepareCalculations(*tr[k]); + int rt = 0, pt = 0; + RunnerStatus st = StatusUnknown; + { + string err; + string str; + try { + st = currentResult->deduceStatus(*tr[k]); + str = oe->formatStatus(st); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + { + string err; + string str; + try { + rt = currentResult->deduceTime(*tr[k]); + str = formatTime(rt); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + + { + string err; + string str; + try { + pt = currentResult->deducePoints(*tr[k]); + str = itos(pt); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + + { + string err; + string str; + try { + int score = currentResult->score(*tr[k], st, rt, pt); + str = itos(score); + } + catch (meosException &ex) { + err = ex.what(); + errors.insert(ex.what()); + str = "Error"; + } + TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff); + if (!err.empty()) { + ti.setColor(colorRed); + gdi.addToolTip("", err, 0, &ti.textRect); + } + txp += w[wi++]; + } + + gdi.addString("Debug", yp, txp, 0, "Debug...", 0, methodCB).setColor(colorGreen).setExtra(-tr[k]->getId()); + + yp += gdi.getLineHeight(); + } + + gdi.scrollTo(0, y); + gdi.refresh(); + } + } + else if (type == GUI_LISTBOX) { + ListBoxInfo &lbi = dynamic_cast(data); + if (lbi.id == "Method") { + checkChangedSave(gdi); + + DynamicResult::DynamicMethods m = DynamicResult::DynamicMethods(lbi.data); + const string &src = currentResult->getMethodSource(m); + gdi.enableInput("SaveSource"); + gdi.enableInput("CancelSource"); + gdi.getBaseInfo("SaveSource").setExtra(lbi.data); + + if (!gdi.hasField("Source")) { + gdi.fillRight(); + gdi.restore("TestRule", false); + gdi.pushX(); + gdi.setRestorePoint("NoSourceEdit"); + gdi.addInputBox("Source", 450, 300, + src, + methodCB, "Source code:").setFont(gdi, monoText); + gdi.fillDown(); + gdi.setCX(gdi.getCX() + gdi.getLineHeight()); + gdi.addListBox("Symbols", 450, 300-20, methodCB, "Available symbols:"); + gdi.setTabStops("Symbols", 180); + gdi.addString("SymbInfo", gdi.getCY(), gdi.getCX(), 0, "", 350, 0); + gdi.popX(); + gdi.setCY(gdi.getHeight()); + gdi.dropLine(); + gdi.scrollToBottom(); + } + else { + gdi.setText("Source", src); + } + + currentResult->declareSymbols(m, true); + vector< pair > symb; + currentResult->getSymbols(symb); + gdi.addItem("Symbols", symb); + } + else if (lbi.id == "Symbols") { + string name, desc; + currentResult->getSymbolInfo(lbi.data, name, desc); + gdi.setText("SymbInfo", name + ":" + lang.tl(desc) +".", true); + } + else if (lbi.id == "OpenList") { + vector< pair > > tagNameList; + oe->getGeneralResults(true, tagNameList, false); + size_t ix = -1; + for (size_t k = 0; k < tagNameList.size(); k++) { + if (tagNameList[k].first == lbi.data) { + ix = k; + break; + } + } + string srcFile; + if (ix < tagNameList.size()) { + bool ro = dynamic_cast(oe->getGeneralResult(tagNameList[ix].second.first, srcFile)).isReadOnly(); + gdi.setInputStatus("DoOpen", !ro); + } + else + gdi.setInputStatus("DoOpen", true); + } + } + else if (type == GUI_LISTBOXSELECT) { + ListBoxInfo &lbi = dynamic_cast(data); + if (lbi.id == "Symbols") { + string name, desc; + currentResult->getSymbolInfo(lbi.data, name, desc); + gdi.replaceSelection("Source", name); + } + } + else if (type==GUI_CLEAR) { + return checkSave(gdi); + } + else if (type == GUI_INPUT) { + InputInfo &ii = dynamic_cast(data); + if (ii.changed()) + makeDirty(gdi, MakeDirty); + + } + else if (type == GUI_LINK) { + TextInfo &ti = dynamic_cast(data); + + if (ti.id == "Debug") { + int id = ti.getExtraInt(); + if (id > 0) { + debug(gdi, id, false); + } + else if (id < 0) { + debug(gdi, -id, true); + } + } + } + + return 0; +} + +void MethodEditor::saveSettings(gdioutput &gdi) { + string name = gdi.getText("Name"); + string tag; + const bool updateTag = gdi.getBaseInfo("Tag").getExtraInt() == 0; + if (updateTag) + tag = gdi.getText("Tag"); + else + tag = currentResult->getTag(); + + string desc = gdi.getText("Desc"); + + if (_strcmpi(currentResult->getTag().c_str(), tag.c_str()) != 0) { + checkTag(tag, true); + string oldPath = fileNameSource.empty() ? getInternalPath(currentResult->getTag()) : fileNameSource; + string path = getInternalPath(tag); + rename(oldPath.c_str(), path.c_str()); + fileNameSource = path; + } + + currentResult->setTag(tag); + currentResult->setName(name); + currentResult->setDescription(desc); + gdi.setText("Name", name); + gdi.setText("Tag", tag); + gdi.setText("Desc", desc); +} + +void MethodEditor::checkUnsaved(gdioutput &gdi) { + /*if (gdi.hasData("IsEditing")) { + if (gdi.isInputChanged("")) { + gdi.setData("NoRedraw", 1); + gdi.sendCtrlMessage("Apply"); + } + } + if (gdi.hasData("IsEditingList")) { + if (gdi.isInputChanged("")) { + gdi.setData("NoRedraw", 1); + gdi.sendCtrlMessage("ApplyListProp"); + } + }*/ +} + + +void MethodEditor::makeDirty(gdioutput &gdi, DirtyFlag inside) { + if (inside == MakeDirty) + dirtyInt = true; + else if (inside == ClearDirty) + dirtyInt = false; + + if (gdi.hasField("SaveInside")) { + gdi.setInputStatus("SaveInside", dirtyInt); + gdi.setInputStatus("Remove", resultIsInstalled()); + } +} + +bool MethodEditor::checkSave(gdioutput &gdi) { + if (dirtyInt) { + gdioutput::AskAnswer answer = gdi.askCancel("Vill du spara ändringar?"); + if (answer == gdioutput::AnswerCancel) + return false; + + if (answer == gdioutput::AnswerYes) { + gdi.sendCtrlMessage("SaveInside"); + } + makeDirty(gdi, ClearDirty); + } + + return true; +} + +void MethodEditor::checkChangedSave(gdioutput &gdi) { + if (gdi.hasField("Source")) { + gdi.getText("Source"); + if (dynamic_cast(gdi.getBaseInfo("Source")).changed() && + gdi.ask("Save changes in rule code?")) { + DynamicResult::DynamicMethods dm = DynamicResult::DynamicMethods(gdi.getExtraInt("SaveSource")); + string src = gdi.getText("Source"); + currentResult->setMethodSource(dm, src); + gdi.setText("Source", src); + } + } +} + +string MethodEditor::getInternalPath(const string &tag) { + string udTag = DynamicResult::undecorateTag(tag); + string resFile; + if (udTag == tag) + resFile = tag + ".rules"; + else + resFile = "imp_" + udTag + ".rules"; + + char path[260]; + getUserFile(path, resFile.c_str()); + return path; +} + +bool MethodEditor::resultIsInstalled() const { + if (!currentResult || fileNameSource.empty()) + return false; + + string tag = currentResult->getTag(); + vector listIx; + oe->getListContainer().getListsByResultModule(tag, listIx); + + if (!listIx.empty()) + return false; // Used in a list in this competition + + //string path = getInternalPath(currentResult->getTag()); + return fileExist(fileNameSource.c_str()); +} + +void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) { + + oAbstractRunner *art = 0; + if (isTeam) + art = oe->getTeam(id); + else + art = oe->getRunner(id, 0); + + if (!art || !currentResult) + throw meosException("Internal error"); + + gdioutput *gdi_new = getExtraWindow("debug", true); + string title = lang.tl("Debug X for Y#" + currentResult->getName(false) + "#" + art->getName()); + + if (!gdi_new) + gdi_new = createExtraWindow("debug", title, + gdi_in.scaleLength(500) ); + else + gdi_new->setWindowTitle(title); + + gdi_new->clearPage(false); + gdi_new->setData("MethodEditorClz", this); + gdioutput &gdi = *gdi_new; + currentResult->prepareCalculations(*oe, isTeam, inputNumber); + gdi_new->addString("", fontMediumPlus, "Debug Output"); + if (!isTeam) { + oRunner &r = *pRunner(art); + currentResult->prepareCalculations(r); + int rt = 0, pt = 0; + RunnerStatus st = StatusUnknown; + gdi.dropLine(); + try { + st = currentResult->deduceStatus(r); + currentResult->debugDumpVariables(gdi, true); + + gdi.addStringUT(1, "ComputedStatus: " + oe->formatStatus(st)).setColor(colorGreen); + } + catch (meosException &ex) { + currentResult->debugDumpVariables(gdi, true); + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Status Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MDeduceRStatus)) + currentResult->debugDumpVariables(gdi, false); + + try { + rt = currentResult->deduceTime(r, r.getStartTime()); + gdi.addStringUT(1, "ComputedTime: " + formatTime(rt)).setColor(colorGreen); + } + catch (meosException &ex) { + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Time Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MDeduceRTime)) + currentResult->debugDumpVariables(gdi, false); + + try { + pt = currentResult->deducePoints(r); + gdi.addStringUT(1, "ComputedPoints: " + itos(pt)).setColor(colorGreen); + } + catch (meosException &ex) { + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Points Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MDeduceRPoints)) + currentResult->debugDumpVariables(gdi, true); + + try { + int score = currentResult->score(r, st, rt, pt, false); + gdi.addStringUT(1, "ComputedScore: " + itos(score)).setColor(colorGreen); + } + catch (meosException &ex) { + currentResult->debugDumpVariables(gdi, true); + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Score Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MRScore)) + currentResult->debugDumpVariables(gdi, false); + } + else { + oTeam &t = *pTeam(art); + currentResult->prepareCalculations(t); + int rt = 0, pt = 0; + RunnerStatus st = StatusUnknown; + gdi.dropLine(); + try { + st = currentResult->deduceStatus(t); + currentResult->debugDumpVariables(gdi, true); + + gdi.addStringUT(1, "ComputedStatus: " + oe->formatStatus(st)).setColor(colorGreen); + } + catch (meosException &ex) { + currentResult->debugDumpVariables(gdi, true); + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Status Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MDeduceTStatus)) + currentResult->debugDumpVariables(gdi, false); + + try { + rt = currentResult->deduceTime(t); + gdi.addStringUT(1, "ComputedTime: " + formatTime(rt)).setColor(colorGreen); + } + catch (meosException &ex) { + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Time Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MDeduceRTime)) + currentResult->debugDumpVariables(gdi, false); + + try { + pt = currentResult->deducePoints(t); + gdi.addStringUT(1, "ComputedPoints: " + itos(pt)).setColor(colorGreen); + } + catch (meosException &ex) { + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Points Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MDeduceTPoints)) + currentResult->debugDumpVariables(gdi, true); + + try { + int score = currentResult->score(t, st, rt, pt); + gdi.addStringUT(1, "ComputedScore:" + itos(score)).setColor(colorGreen); + } + catch (meosException &ex) { + currentResult->debugDumpVariables(gdi, true); + string err = lang.tl(ex.what()); + gdi.addString("", 0, "Status Calculation Failed: X#" + err).setColor(colorRed); + } + if (currentResult->hasMethod(DynamicResult::MTScore)) + currentResult->debugDumpVariables(gdi, false); + } + + gdi.addButton("CloseWindow", "Stäng", methodCB); + gdi.refresh(); +} diff --git a/code/methodeditor.h b/code/methodeditor.h new file mode 100644 index 0000000..d973d88 --- /dev/null +++ b/code/methodeditor.h @@ -0,0 +1,75 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class DynamicResult; +class gdioutput; +class BaseInfo; +class ButtonInfo; +class oEvent; + +#include + +class MethodEditor { +private: + enum SaveType {NotSaved, SavedInside, SavedFile}; + oEvent *oe; + DynamicResult *currentResult; + string fileNameSource; + void setCurrentResult(DynamicResult *lst, const string &src); + int currentIndex; + bool dirtyInt; + bool wasLoadedBuiltIn; + enum DirtyFlag {MakeDirty, ClearDirty, NoTouch}; + + /// Check (and autosave) if there are unsaved changes in a dialog box + void checkUnsaved(gdioutput &gdi); + + void checkChangedSave(gdioutput &gdi); + + /// Check and ask if there are changes to save + bool checkSave(gdioutput &gdi); + + int methodCb(gdioutput &gdi, int type, BaseInfo &data); + + void makeDirty(gdioutput &gdi, DirtyFlag inside); + + bool checkTag(const string &tag, bool throwError) const; + string uniqueTag(const string &tag) const; + + static string getInternalPath(const string &tag); + + void saveSettings(gdioutput &gdi); + + bool resultIsInstalled() const; + + int inputNumber; + void debug(gdioutput &gdi, int id, bool isTeam); +public: + MethodEditor(oEvent *oe); + virtual ~MethodEditor(); + + void show(gdioutput &gdi); + + friend int methodCB(gdioutput*, int, void *); +}; diff --git a/code/minizip/crc32.h b/code/minizip/crc32.h new file mode 100644 index 0000000..5de49bc --- /dev/null +++ b/code/minizip/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/code/minizip/crypt.h b/code/minizip/crypt.h new file mode 100644 index 0000000..8d818ac --- /dev/null +++ b/code/minizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/code/minizip/deflate.h b/code/minizip/deflate.h new file mode 100644 index 0000000..e9044c1 --- /dev/null +++ b/code/minizip/deflate.h @@ -0,0 +1,342 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2010 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/code/minizip/gzguts.h b/code/minizip/gzguts.h new file mode 100644 index 0000000..7ff93a8 --- /dev/null +++ b/code/minizip/gzguts.h @@ -0,0 +1,132 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifdef _MSC_VER +# include +# define vsnprintf _vsnprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifdef STDC +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default i/o buffer size -- double this for output when reading */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + z_off64_t pos; /* current position in uncompressed data */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + unsigned char *next; /* next output data to deliver or write */ + /* just for reading */ + unsigned have; /* amount of output data unused at next */ + int eof; /* true if end of input file reached */ + z_off64_t start; /* where the gzip data started, for rewinding */ + z_off64_t raw; /* where the raw data started, for seeking */ + int how; /* 0: get header, 1: copy, 2: decompress */ + int direct; /* true if last read direct, false if gzip */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/code/minizip/inffast.h b/code/minizip/inffast.h new file mode 100644 index 0000000..e1e6db4 --- /dev/null +++ b/code/minizip/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/code/minizip/inffixed.h b/code/minizip/inffixed.h new file mode 100644 index 0000000..423d5c5 --- /dev/null +++ b/code/minizip/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/code/minizip/inflate.h b/code/minizip/inflate.h new file mode 100644 index 0000000..a8ef428 --- /dev/null +++ b/code/minizip/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/code/minizip/inftrees.h b/code/minizip/inftrees.h new file mode 100644 index 0000000..a685d8c --- /dev/null +++ b/code/minizip/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/code/minizip/ioapi.h b/code/minizip/ioapi.h new file mode 100644 index 0000000..06e1240 --- /dev/null +++ b/code/minizip/ioapi.h @@ -0,0 +1,200 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/minizip/iowin32.h b/code/minizip/iowin32.h new file mode 100644 index 0000000..69c01ba --- /dev/null +++ b/code/minizip/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/code/minizip/mztools.h b/code/minizip/mztools.h new file mode 100644 index 0000000..ec556ea --- /dev/null +++ b/code/minizip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/code/minizip/trees.h b/code/minizip/trees.h new file mode 100644 index 0000000..ce8f620 --- /dev/null +++ b/code/minizip/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/code/minizip/unzip.h b/code/minizip/unzip.h new file mode 100644 index 0000000..f34d6ac --- /dev/null +++ b/code/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/code/minizip/zconf.h b/code/minizip/zconf.h new file mode 100644 index 0000000..88f90f9 --- /dev/null +++ b/code/minizip/zconf.h @@ -0,0 +1,428 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# define uncompress z_uncompress +# define zError z_zError +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef STDC +# include /* for off_t */ +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define z_off64_t off64_t +#else +# define z_off64_t z_off_t +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/code/minizip/zip.h b/code/minizip/zip.h new file mode 100644 index 0000000..ca9aaff --- /dev/null +++ b/code/minizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/code/minizip/zlib.h b/code/minizip/zlib.h new file mode 100644 index 0000000..cba7ab2 --- /dev/null +++ b/code/minizip/zlib.h @@ -0,0 +1,1613 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.5, April 19th, 2010 + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.5" +#define ZLIB_VERNUM 0x1250 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 5 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all the uncompressed data. (The size + of the uncompressed data may have been saved by the compressor for this + purpose.) The next operation on this stream must be inflateEnd to deallocate + the decompression state. The use of Z_FINISH is never required, but can be + used to inform inflate that a faster approach may be used for the single + inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK or Z_TREES is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been + found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the + success case, the application may save the current current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef voidp gzFile; /* opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) Also "a" + can be used instead of "w" to request that the gzip stream that will be + written be appended to the file. "+" will result in an error, since reading + and writing to the same gzip file is not supported. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file was not in gzip format, gzread copies the given number of + bytes into the buffer. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream, or failing that, reading the rest + of the input file directly without decompression. The entire input file + will be read if gzread is called until it returns less than the requested + len. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. This state can change from + false to true while reading the input file if the end of a gzip stream is + reached, but is followed by data that is not another gzip stream. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the for the crc. Pre- and post-conditioning (one's + complement) is performed within this function so it shouldn't be done by the + application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# ifdef _LARGEFILE64_SOURCE + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/code/minizip/zutil.h b/code/minizip/zutil.h new file mode 100644 index 0000000..a36a406 --- /dev/null +++ b/code/minizip/zutil.h @@ -0,0 +1,274 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#ifdef STDC +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); +void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/code/mysqldaemon.cpp b/code/mysqldaemon.cpp new file mode 100644 index 0000000..f0419ce --- /dev/null +++ b/code/mysqldaemon.cpp @@ -0,0 +1,169 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "oEvent.h" +#include "TabAuto.h" +#include "meos_util.h" +#include "gdiconstants.h" +#include "meosdb/sqltypes.h" +#include + +MySQLReconnect::MySQLReconnect(const string &errorIn) : AutoMachine("MySQL-daemon"), error(errorIn) +{ + timeError = getLocalTime(); + hThread=0; +} + +MySQLReconnect::~MySQLReconnect() +{ + CloseHandle(hThread); + hThread=0; +} + +bool MySQLReconnect::stop() +{ + if (interval==0) + return true; + + return MessageBox(0, "If this daemon is stopped, then MeOS will not reconnect to the network. Continue?", + "Warning", MB_YESNO|MB_ICONWARNING)==IDYES; +} + +static CRITICAL_SECTION CS_MySQL; +static volatile DWORD mysqlConnecting=0; +static volatile DWORD mysqlStatus=0; + +void initMySQLCriticalSection(bool init) { + if (init) + InitializeCriticalSection(&CS_MySQL); + else + DeleteCriticalSection(&CS_MySQL); +} + +bool isThreadReconnecting() +{ + EnterCriticalSection(&CS_MySQL); + bool res = (mysqlConnecting != 0); + LeaveCriticalSection(&CS_MySQL); + return res; +} + +unsigned __stdcall reconnectThread(void *v) { + EnterCriticalSection(&CS_MySQL); + mysqlConnecting=1; + mysqlStatus=0; + LeaveCriticalSection(&CS_MySQL); + + bool res = msReConnect(); + + EnterCriticalSection(&CS_MySQL); + if (res) + mysqlStatus=1; + else + mysqlStatus=-1; + + mysqlConnecting=0; + LeaveCriticalSection(&CS_MySQL); + + return 0; +} + +void MySQLReconnect::settings(gdioutput &gdi, oEvent &oe, bool created) { +} + +void MySQLReconnect::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) +{ + if (isThreadReconnecting()) + return; + + if (mysqlStatus==1) { + if (hThread){ + CloseHandle(hThread); + hThread=0; + } + mysqlStatus=0; + char bf[256]; + if (!oe->reConnect(bf)) { + gdi.addInfoBox("", "warning:dbproblem#" + string(bf), 9000); + interval = 10; + } + else { + gdi.addInfoBox("", "Återansluten mot databasen, tävlingen synkroniserad.", 10000); + timeReconnect = getLocalTime(); + gdi.setDBErrorState(false); + gdi.setWindowTitle(oe->getTitleName()); + interval=0; + } + } + else if (mysqlStatus==-1) { + if (hThread){ + CloseHandle(hThread); + hThread=0; + } + mysqlStatus=0; + interval = 10;//Wait ten seconds for next attempt + + gdi.setDBErrorState(true); + char bf[256]; + if (oe->HasDBConnection) { + msGetErrorState(bf); + } + return; + } + else { + mysqlConnecting = 1; + hThread = (HANDLE) _beginthreadex (0, 0, &reconnectThread, 0, 0, 0); + interval = 1; + } +} + +int AutomaticCB(gdioutput *gdi, int type, void *data); + +void MySQLReconnect::status(gdioutput &gdi) { + gdi.dropLine(0.5); + gdi.addString("", 1, name); + gdi.pushX(); + if (interval>0){ + gdi.addStringUT(1, timeError + ": " + lang.tl("DATABASE ERROR")).setColor(colorDarkRed); + gdi.fillRight(); + gdi.addString("", 0, "Nästa försök:"); + gdi.addTimer(gdi.getCY(), gdi.getCX()+10, timerCanBeNegative, (GetTickCount()-timeout)/1000); + } + else { + gdi.addStringUT(0, timeError + ": " + lang.tl("DATABASE ERROR")).setColor(colorDarkGrey); + gdi.fillRight(); + gdi.addStringUT(0, timeReconnect + ":"); + gdi.addString("", 1, "Återansluten mot databasen, tävlingen synkroniserad.").setColor(colorDarkGreen); + gdi.dropLine(); + gdi.fillDown(); + gdi.popX(); + } + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(); + + gdi.popX(); + gdi.dropLine(0.3); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); +} diff --git a/code/newcompetition.cpp b/code/newcompetition.cpp new file mode 100644 index 0000000..8fe7a99 --- /dev/null +++ b/code/newcompetition.cpp @@ -0,0 +1,394 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" +#include "gdiconstants.h" +#include "meos_util.h" +#include "TabCompetition.h" +#include "localizer.h" +#include "meosException.h" +#include "MeOSFeatures.h" +#include "importformats.h" + +#include +#include +#include +#include + +int CompetitionCB(gdioutput *gdi, int type, void *data); + +int NewGuideCB(gdioutput *gdi, int type, void *data) { + TabCompetition &tc = dynamic_cast(*gdi->getTabs().get(TCmpTab)); + return tc.newGuideCB(*gdi, type, data); +} + +int TabCompetition::newGuideCB(gdioutput &gdi, int type, void *data) +{ + if (type == GUI_LINK) { + TextInfo ti = *(TextInfo *)data; + if (ti.id == "link") { + } + } + else if (type==GUI_BUTTON) { + ButtonInfo bi=*(ButtonInfo *)data; + + if (bi.id == "ImportEntries") { + newCompetitionGuide(gdi, 1); + } + else if (bi.id == "BasicSetup") { + gdi.restore("entrychoice"); + entryChoice(gdi); + gdi.refresh(); + } + else if (bi.id == "DoImportEntries") { + createCompetition(gdi); + try { + gdi.autoRefresh(true); + saveEntries(gdi, false, true); + } + catch (std::exception &) { + newCompetitionGuide(gdi, 1); + throw; + } + gdi.restore("newcmp"); + gdi.setCX(gdi.getCX() + gdi.getLineHeight()); + gdi.pushX(); + gdi.setRestorePoint("entrychoice"); + + newCompetitionGuide(gdi, 2); + } + else if (bi.id == "NoEntries") { + gdi.restore("entrychoice"); + newCompetitionGuide(gdi, 2); + } + else if (bi.id == "Cancel") { + oe->clear(); + oe->updateTabs(true, false); + loadPage(gdi); + } + else if (bi.id == "FAll") { + if (gdi.hasField("Name")) + createCompetition(gdi); + gdi.clearPage(true); + gdi.fillRight(); + gdi.addString("", fontMediumPlus, "Skapar tävling..."); + gdi.refresh(); + Sleep(400); + oe->getMeOSFeatures().useAll(*oe); + oe->updateTabs(true, false); + loadPage(gdi); + } + else if (bi.id == "FBasic") { + if (gdi.hasField("Name")) + createCompetition(gdi); + oe->getMeOSFeatures().clear(*oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Clubs, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::RunnerDb, true, *oe); + + oe->updateTabs(true, false); + loadPage(gdi); + } + else if (bi.id == "FSelect") { + newCompetitionGuide(gdi, 3); + } + else if (bi.id == "StoreFeatures") { + if (gdi.hasField("Name")) + createCompetition(gdi); + saveMeosFeatures(gdi, true); + gdi.clearPage(true); + gdi.fillRight(); + gdi.addString("", fontMediumPlus, "Skapar tävling..."); + gdi.refresh(); + Sleep(400); + oe->updateTabs(true, false); + loadPage(gdi); + } + else if (bi.id == "FIndividual") { + if (gdi.hasField("Name")) + createCompetition(gdi); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Speaker, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Economy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::EditClub, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Network, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Vacancy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::InForest, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::DrawStartList, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Bib, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::RunnerDb, true, *oe); + + gdi.clearPage(true); + gdi.fillRight(); + gdi.addString("", fontMediumPlus, "Skapar tävling..."); + gdi.refresh(); + Sleep(400); + oe->updateTabs(true, false); + loadPage(gdi); + } + else if (bi.id == "FForked") { + if (gdi.hasField("Name")) + createCompetition(gdi); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Speaker, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Economy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::EditClub, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Network, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Vacancy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::InForest, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::DrawStartList, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Bib, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::RunnerDb, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *oe); + + gdi.clearPage(true); + gdi.fillRight(); + gdi.addString("", fontMediumPlus, "Skapar tävling..."); + gdi.refresh(); + Sleep(400); + oe->updateTabs(true, false); + loadPage(gdi); + } + else if (bi.id == "FTeam") { + if (gdi.hasField("Name")) + createCompetition(gdi); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Speaker, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Economy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::EditClub, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Network, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Vacancy, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::InForest, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::DrawStartList, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Bib, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::RunnerDb, true, *oe); + oe->getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *oe); + + if (oe->hasMultiRunner()) + oe->getMeOSFeatures().useFeature(MeOSFeatures::MultipleRaces, true, *oe); + + gdi.clearPage(true); + gdi.fillRight(); + gdi.addString("", fontMediumPlus, "Skapar tävling..."); + gdi.refresh(); + Sleep(400); + oe->updateTabs(true, false); + loadPage(gdi); + } + } + else if (type == GUI_INPUT) { + InputInfo &ii = *(InputInfo*)data; + if (ii.id == "FirstStart" || ii.id == "Date") { + int t,d; + SYSTEMTIME st; + if (ii.id == "FirstStart") { + t = convertAbsoluteTimeHMS(ii.text, -1); + d = convertDateYMS(gdi.getText("Date"), st, true); + ii.setBgColor(t == -1 ? colorLightRed: colorDefault); + } + else { + t = convertAbsoluteTimeHMS(gdi.getText("FirstStart"), -1); + d = convertDateYMS(ii.text, st, true); + ii.setBgColor(d <= 0 ? colorLightRed: colorDefault); + } + + if (t <= 0 || d <= 0) { + gdi.setTextTranslate("AllowedInterval", "Felaktigt datum/tid", true); + } + else { + long long absT = SystemTimeToInt64Second(st); + absT += max(0, t - 3600); + long long stopT = absT + 23 * 3600; + SYSTEMTIME start = Int64SecondToSystemTime(absT); + SYSTEMTIME end = Int64SecondToSystemTime(stopT); + string s = "Tävlingen måste avgöras mellan X och Y.#" + convertSystemTime(start) + "#" + convertSystemTime(end); + gdi.setTextTranslate("AllowedInterval", s, true); + } + } + + } + return 0; +} + +void TabCompetition::newCompetitionGuide(gdioutput &gdi, int step) { + static RECT rc; + const int width = 600; + if (step == 0) { + oe->updateTabs(true, true); + gdi.clearPage(false); + gdi.addString("", boldLarge, "Ny tävling"); + gdi.dropLine(); + gdi.setRestorePoint("newcmp"); + + rc.top = gdi.getCY(); + rc.left = gdi.getCX(); + gdi.dropLine(); + + gdi.setCX(gdi.getCX() + gdi.getLineHeight()); + + gdi.addString("", fontMediumPlus, "Namn och tidpunkt"); + + gdi.dropLine(0.5); + gdi.addInput("Name", lang.tl("Ny tävling"), 34, 0, "Tävlingens namn:"); + + gdi.pushX(); + gdi.fillRight(); + InputInfo &date = gdi.addInput("Date", getLocalDate(), 16, NewGuideCB, "Datum (för första start):"); + + gdi.addInput("FirstStart", "07:00:00", 12, NewGuideCB, "Första tillåtna starttid:"); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(3.5); + gdi.addString("AllowedInterval", 0, ""); + newGuideCB(gdi, GUI_INPUT, &date); + gdi.dropLine(2); + rc.right = rc.left + gdi.scaleLength(width); + rc.bottom = gdi.getCY(); + gdi.addRectangle(rc, colorLightBlue, true); + gdi.dropLine(); + gdi.setRestorePoint("entrychoice"); + entryChoice(gdi); + gdi.refresh(); + } + else if (step == 1) { + gdi.restore("entrychoice"); + rc.top = gdi.getCY(); + gdi.fillDown(); + entryForm(gdi, true); + rc.bottom = gdi.getCY(); + gdi.dropLine(); + gdi.addRectangle(rc, colorLightBlue, true); + + gdi.fillRight(); + gdi.addButton("BasicSetup", "<< Bakåt", NewGuideCB); + gdi.addButton("DoImportEntries", "Importera", NewGuideCB); + gdi.addButton("Cancel", "Avbryt", NewGuideCB).setCancel(); + + gdi.popX(); + gdi.dropLine(2); + gdi.fillDown(); + gdi.scrollToBottom(); + gdi.refresh(); + } + else if (step == 2) { + rc.top = gdi.getCY(); + gdi.fillDown(); + gdi.dropLine(); + gdi.addString("", fontMediumPlus, "Funktioner i MeOS"); + gdi.dropLine(0.5); + gdi.addString("", 10, "newcmp:featuredesc"); + gdi.dropLine(); + gdi.addString("", 1, "Välj vilka funktioner du vill använda"); + gdi.dropLine(0.5); + gdi.fillRight(); + gdi.addButton("FIndividual", "Individuell tävling", NewGuideCB); + gdi.addButton("FForked", "Individuellt, gafflat", NewGuideCB); + gdi.addButton("FTeam", "Tävling med lag", NewGuideCB); + gdi.popX(); + gdi.dropLine(2); + gdi.addButton("FBasic", "Endast grundläggande", NewGuideCB); + gdi.addButton("FAll", "Alla funktioner", NewGuideCB); + gdi.addButton("FSelect", "Välj från lista...", NewGuideCB); + gdi.addButton("Cancel", "Avbryt", NewGuideCB).setCancel(); + + if (oe->hasTeam()) { + gdi.disableInput("FIndividual"); + gdi.disableInput("FForked"); + gdi.disableInput("FBasic"); + } + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(3); + + rc.bottom = gdi.getCY(); + gdi.dropLine(); + gdi.addRectangle(rc, colorLightBlue, true); + + gdi.refresh(); + } + else if (step == 3) { + gdi.restore("entrychoice"); + RECT rcl = rc; + rcl.top = gdi.getCY(); + gdi.fillDown(); + gdi.pushX(); + meosFeatures(gdi, true); + rcl.bottom = gdi.getHeight(); + if (gdi.getWidth() >= rc.right + gdi.scaleLength(30)) + rcl.right = gdi.getWidth(); + gdi.dropLine(); + gdi.addRectangle(rcl, colorLightBlue, true); + + gdi.popX(); + gdi.dropLine(); + gdi.setCY(gdi.getHeight()); + gdi.fillRight(); + gdi.addButton("NoEntries", "<< Bakåt", NewGuideCB); + gdi.addButton("StoreFeatures", "Skapa tävlingen", NewGuideCB); + gdi.addButton("Cancel", "Avbryt", NewGuideCB).setCancel(); + + gdi.popX(); + gdi.dropLine(2); + gdi.fillDown(); + + gdi.refresh(); + + } +} + +void TabCompetition::entryChoice(gdioutput &gdi) { + gdi.fillRight(); + gdi.pushX(); + gdi.addButton("ImportEntries", "Importera anmälda", NewGuideCB); + //gdi.addButton("FreeEntry", "Fri inmatning av deltagare", NewGuideCB); + gdi.addButton("NoEntries", "Anmäl inga deltagare nu", NewGuideCB); + gdi.addButton("Cancel", "Avbryt", NewGuideCB).setCancel(); + + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2); +} + +void TabCompetition::createCompetition(gdioutput &gdi) { + string name = gdi.getText("Name"); + string date = gdi.getText("Date"); + string start = gdi.getText("FirstStart"); + + oe->newCompetition("tmp"); + oe->setName(name); + oe->setDate(date); + + int t = convertAbsoluteTimeHMS(start, -1); + if (t > 0 && t < 3600*24) { + t = max(0, t-3600); + oe->setZeroTime(formatTimeHMS(t)); + } + else + throw meosException("Ogiltig tid"); + } + diff --git a/code/oBase.cpp b/code/oBase.cpp new file mode 100644 index 0000000..0fc5aa2 --- /dev/null +++ b/code/oBase.cpp @@ -0,0 +1,190 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oBase.cpp: implementation of the oBase class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "meos.h" +#include "oBase.h" +#include "oCard.h" +#include "meos_util.h" + +#include "oEvent.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +char RunnerStatusOrderMap[100]; + +oBase::oBase(oEvent *poe) +{ + Removed = false; + oe = poe; + Id = 0; + changed = false; + reChanged = false; + counter = 0; + Modified.update(); + correctionNeeded = true; +} + +oBase::~oBase() +{ +} + +bool oBase::synchronize(bool writeOnly) +{ + if (oe && changed) { + changedObject(); + oe->dataRevision++; + } + if (oe && oe->HasDBConnection && (changed || !writeOnly)) { + correctionNeeded = false; + return oe->msSynchronize(this); + } + else { + if (changed) { + if (!oe->HasPendingDBConnection) // True if we are trying to reconnect to mysql + changed = false; + } + } + return true; +} + +void oBase::clearCombo(HWND hWnd) +{ + SendMessage(hWnd, CB_RESETCONTENT, 0, 0); +} + +void oBase::addToCombo(HWND hWnd, const string &str, int data) +{ + int index=SendMessage(hWnd, CB_ADDSTRING, 0, LPARAM(str.c_str())); + SendMessage(hWnd, CB_SETITEMDATA, index, data); +} + +void oBase::setExtIdentifier(__int64 id) +{ + getDI().setInt64("ExtId", id); +} + +__int64 oBase::getExtIdentifier() const +{ + return getDCI().getInt64("ExtId"); +} + +string oBase::getExtIdentifierString() const { + __int64 raw = getExtIdentifier(); + char res[16]; + if (raw == 0) + return ""; + if (raw & BaseGenStringFlag) + convertDynamicBase(raw & ExtStringMask, 256-32, res); + else if (raw & Base36StringFlag) + convertDynamicBase(raw & ExtStringMask, 36, res); + else + convertDynamicBase(raw, 10, res); + return res; +} + +void oBase::converExtIdentifierString(__int64 raw, char bf[16]) { + if (raw & BaseGenStringFlag) + convertDynamicBase(raw & ExtStringMask, 256-32, bf); + else if (raw & Base36StringFlag) + convertDynamicBase(raw & ExtStringMask, 36, bf); + else + convertDynamicBase(raw, 10, bf); +} + +__int64 oBase::converExtIdentifierString(const string &str) { + __int64 val; + int base = convertDynamicBase(str, val); + if (base == 36) + val |= Base36StringFlag; + else if (base > 36) + val |= BaseGenStringFlag; + return val; +} + +void oBase::setExtIdentifier(const string &str) { + __int64 val = converExtIdentifierString(str); + setExtIdentifier(val); +} + +int oBase::idFromExtId(__int64 val) { + int basePart = int(val & 0x0FFFFFFF); + if (basePart == val) + return basePart; + + __int64 hash = (val&ExtStringMask) % 2000000011ul; + + int res = basePart + int(hash&0xFFFFFF); + if (res == 0) + res += int(hash); + + return res & 0x0FFFFFFF; +} + +bool oBase::isStringIdentifier() const { + __int64 raw = getExtIdentifier(); + return (raw & (BaseGenStringFlag|Base36StringFlag)) != 0; +} + +string oBase::getTimeStamp() const { + if (oe && oe->isClient() && !sqlUpdated.empty()) + return sqlUpdated; + else return Modified.getStampString(); +} + +void oBase::changeId(int newId) { + Id = newId; +} + +oDataInterface oBase::getDI(void) { + pvoid data; + pvoid olddata; + pvectorstr strData; + oDataContainer &dc = getDataBuffers(data, olddata, strData); + return dc.getInterface(data, getDISize(), this); +} + +oDataConstInterface oBase::getDCI(void) const +{ + pvoid data; + pvoid olddata; + pvectorstr strData; + oDataContainer &dc = getDataBuffers(data, olddata, strData); + return dc.getConstInterface(data, getDISize(), this); +} + +void oBase::updateChanged() { + Modified.update(); + changed=true; +} diff --git a/code/oBase.h b/code/oBase.h new file mode 100644 index 0000000..29f10a6 --- /dev/null +++ b/code/oBase.h @@ -0,0 +1,179 @@ +// oBase.h: interface for the oBase class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OBASE_H__C950D806_EEC7_4C56_B298_132C67FCF719__INCLUDED_) +#define AFX_OBASE_H__C950D806_EEC7_4C56_B298_132C67FCF719__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "TimeStamp.h" +#include "stdafx.h" +#include + +class oEvent; +class gdioutput; +class oDataInterface; +class oDataConstInterface; +class oDataContainer; +typedef void * pvoid; +typedef vector< vector > * pvectorstr; + +enum RunnerStatus {StatusOK=1, StatusDNS=20, StatusMP=3, + StatusDNF=4, StatusDQ=5, StatusMAX=6, + StatusUnknown=0, StatusNotCompetiting=99}; + +extern char RunnerStatusOrderMap[100]; + +enum SortOrder {ClassStartTime, + ClassTeamLeg, + ClassResult, + ClassCourseResult, + ClassTotalResult, + ClassTeamLegResult, + ClassFinishTime, + ClassStartTimeClub, + ClassPoints, + SortByName, + SortByLastName, + SortByFinishTime, + SortByFinishTimeReverse, + SortByStartTime, + CourseResult, + Custom, + SortEnumLastItem}; + +class oBase +{ +private: + void storeChangeStatus() {reChanged = changed;} + void resetChangeStatus() {changed &= reChanged;} + bool reChanged; + bool changed; + + const static unsigned long long BaseGenStringFlag = 1ull << 63; + const static unsigned long long Base36StringFlag = 1ull << 62; + const static unsigned long long ExtStringMask = ~(BaseGenStringFlag|Base36StringFlag); + +protected: + int Id; + TimeStamp Modified; + string sqlUpdated; //SQL TIMESTAMP + int counter; + + // True if the object is incorrect and needs correction + // An example is if id changed as we wrote. Then owner + // needs to be updated. + bool correctionNeeded; + + oEvent *oe; + bool Removed; + + //Used for selections, etc. + int _objectmarker; + + /// Mark the object as changed (on client) and that it needs synchronize to server + virtual void updateChanged(); + + /// Mark the object as "changed" (locally or remotely), eg lists and other views may need update + virtual void changedObject() = 0; + + /** Change the id of the object */ + virtual void changeId(int newId); + + //Used for handeling GUI combo boxes; + static void clearCombo(HWND hWnd); + static void addToCombo(HWND hWnd, const string &str, int data); + + /** Get internal data buffers for DI */ + virtual oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const = 0; + virtual int getDISize() const = 0; + +public: + /// Returns textual information on the object + virtual string getInfo() const = 0; + + //Called (by a table) when user enters data in a cell + virtual bool inputData(int id, const string &input, int inputId, + string &output, bool noUpdate) {output=""; return false;} + + //Called (by a table) to fill a list box with contents in a table + virtual void fillInput(int id, vector< pair > &elements, size_t &selected) + {throw std::exception("Not implemented");} + + oEvent *getEvent() const {return oe;} + int getId() const {return Id;} + bool isChanged() const {return changed;} + bool isRemoved() const {return Removed;} + int getAge() const {return Modified.getAge();} + unsigned int getModificationTime() const {return Modified.getModificationTime();} + + bool synchronize(bool writeOnly=false); + string getTimeStamp() const; + + bool existInDB() const { return !sqlUpdated.empty(); } + + oDataInterface getDI(); + + oDataConstInterface getDCI() const; + + // Remove object from the competition + virtual void remove() = 0; + + // Check if object can be remove (is not used by someone else) + virtual bool canRemove() const = 0; + + /// Set an external identifier (0 if none) + void setExtIdentifier(__int64 id); + + /// Get an external identifier (or 0) if none + __int64 getExtIdentifier() const; + + string getExtIdentifierString() const; + void setExtIdentifier(const string &str); + bool isStringIdentifier() const; + + // Convert an external to a int id. The result + // need not be unique, of course. + static int idFromExtId(__int64 extId); + static void converExtIdentifierString(__int64 raw, char bf[16]); + static __int64 converExtIdentifierString(const string &str); + + oBase(oEvent *poe); + virtual ~oBase(); + + friend class RunnerDB; + friend class MeosSQL; + friend class oEvent; + friend class oDataInterface; + friend class oDataContainer; + friend class MetaListContainer; +}; + +typedef oBase * pBase; + +#endif // !defined(AFX_OBASE_H__C950D806_EEC7_4C56_B298_132C67FCF719__INCLUDED_) diff --git a/code/oCard.cpp b/code/oCard.cpp new file mode 100644 index 0000000..5f33dbe --- /dev/null +++ b/code/oCard.cpp @@ -0,0 +1,780 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oCard.cpp: implementation of the oCard class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "oCard.h" +#include "oEvent.h" +#include "gdioutput.h" +#include "table.h" +#include "Localizer.h" +#include "meos_util.h" + +#include +#include + +#include "SportIdent.h" +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +oCard::oCard(oEvent *poe): oBase(poe) +{ + Id=oe->getFreeCardId(); + cardNo=0; + readId=0; + tOwner=0; +} + +oCard::oCard(oEvent *poe, int id): oBase(poe) +{ + Id=id; + cardNo=0; + readId=0; + tOwner=0; + oe->qFreeCardId = max(id, oe->qFreeCardId); +} + +oCard::~oCard() +{ + +} + +bool oCard::Write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Card"); + xml.write("CardNo", cardNo); + xml.write("Punches", getPunchString()); + xml.write("ReadId", readId); + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.endTag(); + + return true; +} + +void oCard::Set(const xmlobject &xo) +{ + xmlList xl; + xo.getObjects(xl); + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("CardNo")){ + cardNo = it->getInt(); + } + else if (it->is("Punches")){ + importPunches(it->get()); + } + else if (it->is("ReadId")){ + readId = it->getInt(); + } + else if (it->is("Id")){ + Id = it->getInt(); + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + } +} + +void oCard::setCardNo(int c) +{ + if (cardNo!=c) + updateChanged(); + + cardNo=c; +} + +const string &oCard::getCardNoString() const +{ + return itos(cardNo); +} + +void oCard::addPunch(int type, int time, int matchControlId) +{ + oPunch p(oe); + p.Time = time; + p.Type = type; + p.tMatchControlId = matchControlId; + p.isUsed = matchControlId!=0; + + if (punches.empty()) + punches.push_back(p); + else { + oPunch oldBack = punches.back(); + if (oldBack.isFinish()) { //Make sure finish is last. + punches.pop_back(); + punches.push_back(p); + punches.push_back(oldBack); + } + else + punches.push_back(p); + } + updateChanged(); +} + +string oCard::getPunchString() +{ + oPunchList::iterator it; + + string pstring; + + for(it=punches.begin(); it != punches.end(); ++it){ + pstring += it->codeString(); + } + + return pstring; +} + +void oCard::importPunches(const string &s) { + int startpos=0; + int endpos; + + endpos=s.find_first_of(';', startpos); + punches.clear(); + + while(endpos!=string::npos) { + oPunch p(oe); + p.decodeString(s.substr(startpos, endpos)); + punches.push_back(p); + startpos=endpos+1; + endpos=s.find_first_of(';', startpos); + } + return; +} + +bool oCard::fillPunches(gdioutput &gdi, const string &name, pCourse crs) { + oPunchList::iterator it; + synchronize(true); + int ix = 0; + for (it=punches.begin(); it != punches.end(); ++it) { + it->tCardIndex = ix++; + } + + gdi.clearList(name); + + bool showStart = crs ? !crs->useFirstAsStart() : true; + bool showFinish = crs ? !crs->useLastAsFinish() : true; + + bool hasStart=false; + bool hasFinish=false; + bool extra=false; + int k=0; + + pControl ctrl=0; + + int matchPunch=0; + int punchRemain=1; + bool hasRogaining = false; + if (crs) { + ctrl=crs->getControl(matchPunch); + hasRogaining = crs->hasRogaining(); + } + if (ctrl) + punchRemain=ctrl->getNumMulti(); + + map > rogainingIndex; + + if (crs) { + for (it=punches.begin(); it != punches.end(); ++it) { + if (it->tRogainingIndex >= 0) { + rogainingIndex[it->tRogainingIndex] = make_pair(it->tCardIndex, &*it); + } + ix++; + } + } + + for (it=punches.begin(); it != punches.end(); ++it){ + if (!hasStart && !it->isStart()){ + if (it->isUsed){ + if (showStart) + gdi.addItem(name, lang.tl("Start")+"\t-", -1); + hasStart=true; + } + } + + if (crs && it->tRogainingIndex != -1) + continue; + + { + if (it->isStart()) + hasStart=true; + else if (crs && it->isUsed && !it->isFinish() && !it->isCheck()) { + while(ctrl && it->tMatchControlId!=ctrl->getId()) { + if (ctrl->isRogaining(hasRogaining)) { + if (rogainingIndex.count(matchPunch) == 1) + gdi.addItem(name, rogainingIndex[matchPunch].second->getString(), + rogainingIndex[matchPunch].first); + else + gdi.addItem(name, "-\t-", -1); + } + else { + while(0getControl(++matchPunch):0; + punchRemain=ctrl ? ctrl->getNumMulti() : 1; + } + } + + + if ((!crs || it->isUsed) || (showFinish && it->isFinish()) || (showStart && it->isStart())) { + if (it->isFinish() && hasRogaining && crs) { + while (ctrl) { + if (ctrl->isRogaining(hasRogaining)) { + // Check if we have reach finihs without adding rogaining punches + while (ctrl && ctrl->isRogaining(hasRogaining)) { + if (rogainingIndex.count(matchPunch) == 1) + gdi.addItem(name, rogainingIndex[matchPunch].second->getString(), + rogainingIndex[matchPunch].first); + else + gdi.addItem(name, "-\t-", -1); + ctrl = crs->getControl(++matchPunch); + } + punchRemain = ctrl ? ctrl->getNumMulti() : 1; + } + else { + gdi.addItem(name, "-\t-", -1); + ctrl = crs->getControl(++matchPunch); + } + } + } + + if (it->isFinish() && crs) { //Add missing punches before the finish + while(ctrl) { + gdi.addItem(name, "-\t-", -1); + ctrl = crs->getControl(++matchPunch); + } + } + + gdi.addItem(name, it->getString(), it->tCardIndex); + + if (!(it->isFinish() || it->isStart())) { + punchRemain--; + if (punchRemain<=0) { + // Next contol + ctrl = crs ? crs->getControl(++matchPunch):0; + + // Match rogaining here + while (ctrl && ctrl->isRogaining(hasRogaining)) { + if (rogainingIndex.count(matchPunch) == 1) + gdi.addItem(name, rogainingIndex[matchPunch].second->getString(), + rogainingIndex[matchPunch].first); + else + gdi.addItem(name, "-\t-", -1); + ctrl = crs->getControl(++matchPunch); + } + punchRemain = ctrl ? ctrl->getNumMulti() : 1; + } + } + } + else + extra=true; + + k++; + + if (it->isFinish() && showFinish) + hasFinish=true; + } + } + + if (!hasStart && showStart) + gdi.addItem(name, lang.tl("Start")+"\t-", -1); + + if (!hasFinish && showFinish) { + + while (ctrl) { + if (ctrl->isRogaining(hasRogaining)) { + // Check if we have reach finihs without adding rogaining punches + while (ctrl && ctrl->isRogaining(hasRogaining)) { + if (rogainingIndex.count(matchPunch) == 1) + gdi.addItem(name, rogainingIndex[matchPunch].second->getString(), + rogainingIndex[matchPunch].first); + else + gdi.addItem(name, "-\t-", -1); + ctrl = crs->getControl(++matchPunch); + } + punchRemain = ctrl ? ctrl->getNumMulti() : 1; + } + else { + gdi.addItem(name, "-\t-", -1); + ctrl = crs->getControl(++matchPunch); + } + } + + gdi.addItem(name, lang.tl("Mål")+"\t-", -1); + } + + if (extra) { + //Show punches that are not used. + k=0; + gdi.addItem(name, "", -1); + gdi.addItem(name, lang.tl("Extra stämplingar"), -1); + for (it=punches.begin(); it != punches.end(); ++it) { + if (!it->isUsed && !(it->isFinish() && showFinish) && !(it->isStart() && showStart)) + gdi.addItem(name, it->getString(), it->tCardIndex); + } + } + return true; +} + + +void oCard::insertPunchAfter(int pos, int type, int time) +{ + if (pos==1023) + return; + + oPunchList::iterator it; + + oPunch punch(oe); + punch.Time=time; + punch.Type=type; + + int k=-1; + for (it=punches.begin(); it != punches.end(); ++it) { + if (k==pos) { + updateChanged(); + punches.insert(it, punch); + return; + } + k++; + } + + updateChanged(); + //Insert last + punches.push_back(punch); +} + +void oCard::deletePunch(pPunch pp) +{ + if (pp == 0) + throw std::exception("Punch not found"); + int k=0; + oPunchList::iterator it; + + for (it=punches.begin(); it != punches.end(); ++it) { + if (&*it == pp) { + punches.erase(it); + updateChanged(); + return; + } + k++; + } +} + +string oCard::getInfo() const +{ + char bf[128]; + sprintf_s(bf, lang.tl("Löparbricka %d").c_str(), cardNo); + return bf; +} + +oPunch *oCard::getPunch(const pPunch punch) +{ + int k=0; + oPunchList::iterator it; + + for (it=punches.begin(); it != punches.end(); ++it) { + if (&*it == punch) return &*it; + k++; + } + return 0; +} + + +oPunch *oCard::getPunchByType(int Type) const +{ + oPunchList::const_iterator it; + + for (it=punches.begin(); it != punches.end(); ++it) + if (it->Type==Type) + return pPunch(&*it); + + return 0; +} + +oPunch *oCard::getPunchById(int courseControlId) const +{ + pair idix = oControl::getIdIndexFromCourseControlId(courseControlId); + oPunchList::const_iterator it; + pPunch res = 0; + for (it=punches.begin(); it != punches.end(); ++it) { + if (it->tMatchControlId==idix.first) { + res = pPunch(&*it); + if (idix.second == 0) + return res; + --idix.second; // Not this match, decrease count + } + } + return 0; // Punch not found +} + + +oPunch *oCard::getPunchByIndex(int ix) const +{ + oPunchList::const_iterator it; + for (it=punches.begin(); it != punches.end(); ++it) { + if (0 == ix--) + return pPunch(&*it); + } + return 0; +} + + +void oCard::setReadId(const SICard &card) +{ + updateChanged(); + readId=card.calculateHash(); +} + +bool oCard::isCardRead(const SICard &card) const +{ + if (readId==card.calculateHash()) + return true; + else return false; +} + +void oCard::getSICard(SICard &card) const { + card.clear(0); + card.CardNumber = cardNo; + oPunchList::const_iterator it; + for (it = punches.begin(); it != punches.end(); ++it) { + if (it->Type>30) + card.Punch[card.nPunch++].Code = it->Type; + } +} + + +pRunner oCard::getOwner() const { + return tOwner && !tOwner->isRemoved() ? tOwner : 0; +} + +bool oCard::setPunchTime(const pPunch punch, const string &time) +{ + oPunch *op=getPunch(punch); + if (!op) return false; + + DWORD ot=op->Time; + op->setTime(time); + + if (ot!=op->Time) + updateChanged(); + + return true; +} + + +pCard oEvent::getCard(int Id) const +{ + if (Id < int(Cards.size() / 2)) { + for (oCardList::const_iterator it = Cards.begin(); it != Cards.end(); ++it){ + if (it->Id==Id) + return const_cast(&*it); + } + } + else { + for (oCardList::const_reverse_iterator it = Cards.rbegin(); it != Cards.rend(); ++it){ + if (it->Id==Id) + return const_cast(&*it); + } + } + return 0; +} + +void oEvent::getCards(vector &c) { + synchronizeList(oLCardId); + c.clear(); + c.reserve(Cards.size()); + + for (oCardList::iterator it = Cards.begin(); it != Cards.end(); ++it) { + if (!it->isRemoved()) + c.push_back(&*it); + } +} + + +pCard oEvent::addCard(const oCard &oc) +{ + if (oc.Id<=0) + return 0; + + Cards.push_back(oc); + + return &Cards.back(); +} + + +pCard oEvent::getCardByNumber(int cno) const +{ + oCardList::const_reverse_iterator it; + pCard second = 0; + for (it=Cards.rbegin(); it != Cards.rend(); ++it){ + if (it->cardNo==cno) { + if (it->getOwner() == 0) + return const_cast(&*it); + else if (second == 0) + second = const_cast(&*it); + } + } + return second; +} + +bool oEvent::isCardRead(const SICard &card) const +{ + oCardList::const_iterator it; + + for(it=Cards.begin(); it!=Cards.end(); ++it) { + if (it->isRemoved()) + continue; + + if (it->cardNo==card.CardNumber && it->isCardRead(card)) + return true; + } + + return false; +} + + +Table *oEvent::getCardsTB() //Table mode +{ + oCardList::iterator it; + + Table *table=new Table(this, 20, "Brickor", "cards"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Bricka", 120, true); + table->addColumn("Deltagare", 200, false); + + table->addColumn("Starttid", 70, false); + table->addColumn("Måltid", 70, false); + table->addColumn("Stämplingar", 70, true); + + table->setTableProp(Table::CAN_DELETE); + table->update(); + + return table; +} + +void oEvent::generateCardTableData(Table &table, oCard *addCard) +{ + if (addCard) { + addCard->addTableRow(table); + return; + } + + oCardList::iterator it; + synchronizeList(oLCardId, true, false); + synchronizeList(oLRunnerId, false, true); + + for (it=Cards.begin(); it!=Cards.end(); ++it) { + if (!it->isRemoved()) { + it->addTableRow(table); + } + } +} + +void oCard::addTableRow(Table &table) const { + + string runner(lang.tl("Oparad")); + if (getOwner()) + runner = tOwner->getNameAndRace(true); + + oCard &it = *pCard(this); + table.addRow(getId(), &it); + + int row = 0; + table.set(row++, it, TID_ID, itos(getId()), false); + table.set(row++, it, TID_MODIFIED, getTimeStamp(), false); + + table.set(row++, it, TID_CARD, getCardNoString(), true, cellAction); + + table.set(row++, it, TID_RUNNER, runner, true, cellAction); + + oPunch *p=getPunchByType(oPunch::PunchStart); + string time = "-"; + if (p) + time = p->getTime(); + table.set(row++, it, TID_START, time, false, cellEdit); + + p = getPunchByType(oPunch::PunchFinish); + time = "-"; + if (p) + time = p->getTime(); + table.set(row++, it, TID_FINISH, time, false, cellEdit); + + char npunch[16]; + sprintf_s(npunch, "%d", getNumPunches()); + table.set(row++, it, TID_COURSE, npunch, false, cellEdit); +} + +oDataContainer &oCard::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + throw std::exception("Unsupported"); +} + +int oCard::getSplitTime(int startTime, const pPunch punch) const { + + for (oPunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + if (&*it == punch) { + int t = it->getAdjustedTime(); + if (t<=0) + return -1; + + if (startTime > 0) + return t - startTime; + else + return -1; + } + else if (it->isUsed) + startTime = it->getAdjustedTime(); + } + return -1; +} + + +string oCard::getRogainingSplit(int ix, int startTime) const +{ + oPunchList::const_iterator it; + for (it = punches.begin(); it != punches.end(); ++it) { + int t = it->getAdjustedTime(); + if (0 == ix--) { + if (t > 0 && t > startTime) + return formatTime(t - startTime); + } + if (it->isUsed) + startTime = t; + } + return "-"; +} + +void oCard::remove() +{ + if (oe) + oe->removeCard(Id); +} + +bool oCard::canRemove() const +{ + return getOwner() == 0; +} + +pair oCard::getTimeRange() const { + pair t(24*3600, 0); + for(oPunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + if (it->Time > 0) { + t.first = min(t.first, it->Time); + t.second = max(t.second, it->Time); + } + } + return t; +} + +void oCard::getPunches(vector &punchesOut) const { + punchesOut.clear(); + punchesOut.reserve(punches.size()); + for(oPunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + punchesOut.push_back(pPunch(&*it)); + } +} + +bool oCard::comparePunchTime(oPunch *p1, oPunch *p2) { + return p1->Time < p2->Time; +} + +void oCard::setupFromRadioPunches(oRunner &r) { + oe->synchronizeList(oLPunchId, true, true); + vector p; + oe->getPunchesForRunner(r.getId(), p); + + sort(p.begin(), p.end(), comparePunchTime); + + for (size_t k = 0; k < p.size(); k++) + addPunch(p[k]->Type, p[k]->Time, 0); + + cardNo = r.getCardNo(); + readId = ConstructedFromPunches; //Indicates +} + +void oCard::changedObject() { + if (tOwner) + tOwner->markClassChanged(-1); +} + +int oCard::getNumControlPunches(int startPunchType, int finishPunchType) const { + int count = 0; + for(oPunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + if (it->isFinish(finishPunchType) || it->isCheck() || it->isStart(startPunchType)) { + continue; + } + count++; + } + return count; +} + +void oCard::adaptTimes(int startTime) { + int st = -1; + oPunchList::iterator it = punches.begin(); + while (it != punches.end()) { + if (it->Time > 0) { + st = it->Time; + break; + } + ++it; + } + + if (st == -1) + return; + + const int h24 = 24 * 3600; + int offset = st / h24; + if (offset > 0) { + for (it = punches.begin(); it != punches.end(); ++it) { + if (it->Time > 0 && it->Time < offset * h24) + return; // Inconsistent, do nothing + } + + + for (it = punches.begin(); it != punches.end(); ++it) { + if (it->Time > 0) + it->Time -= offset * h24; + } + updateChanged(); + } + + if (startTime >= h24) { + offset = startTime / h24; + for (it = punches.begin(); it != punches.end(); ++it) { + if (it->Time > 0) + it->Time += offset * h24; + } + updateChanged(); + } +} \ No newline at end of file diff --git a/code/oCard.h b/code/oCard.h new file mode 100644 index 0000000..7b498d8 --- /dev/null +++ b/code/oCard.h @@ -0,0 +1,145 @@ +// oCard.h: interface for the oCard class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OCARD_H__674EAB76_A232_4E44_A9B4_C52F6A04D7CF__INCLUDED_) +#define AFX_OCARD_H__674EAB76_A232_4E44_A9B4_C52F6A04D7CF__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "oBase.h" +#include "oPunch.h" + +#include "xmlparser.h" + +typedef list oPunchList; + +class gdioutput; +class oCard; +typedef oCard *pCard; + +class oCourse; +class oRunner; +typedef oRunner *pRunner; + +struct SICard; +class Table; + +class oCard : public oBase { +protected: + oPunchList punches; + int cardNo; + DWORD readId; //Identify a specific read-out + + const static DWORD ConstructedFromPunches = 1; + + pRunner tOwner; + oPunch *getPunch(const pPunch punch); + + int getDISize() const {return -1;} + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + static bool comparePunchTime(oPunch *p1, oPunch *p2); + + void changedObject(); + +public: + + // Returns true if the card was constructed from punches. + bool isConstructedFromPunches() {return ConstructedFromPunches == readId;} + + // Setup a card from the runner's punches + void setupFromRadioPunches(oRunner &r); + + void remove(); + bool canRemove() const; + + pair getTimeRange() const; + + string getInfo() const; + + void addTableRow(Table &table) const; + + /// Returns the split time from the last used punch + /// to the current punch, as indicated by evaluateCard + int getSplitTime(int startTime, const pPunch punch) const; + + pRunner getOwner() const; + int getNumPunches() const {return punches.size();} + + /** Returns the number of real control punches on the course. */ + int getNumControlPunches(int startPunchType, int finishPunchType) const; + + bool setPunchTime(const pPunch punch, const string &time); + bool isCardRead(const SICard &card) const; + void setReadId(const SICard &card); + // Get SI-Card from oCard (just punches) + void getSICard(SICard &card) const; + + void deletePunch(pPunch pp); + void insertPunchAfter(int pos, int type, int time); + + bool fillPunches(gdioutput &gdi, const string &name, oCourse *crs); + + void addPunch(int type, int time, int matchControlId); + oPunch *getPunchByType(int type) const; + + //Get punch by (matched) control punch id. + oPunch *getPunchById(int courseControlId) const; + oPunch *getPunchByIndex(int ix) const; + + // Get all punches + void getPunches(vector &punches) const; + // Return split time to previous matched control + string getRogainingSplit(int ix, int startTime) const; + + /** Adapt the 24-hours based time to a start time that may br larger that 24-hour after zero time. */ + void adaptTimes(int startTime); + + int getCardNo() const {return cardNo;} + const string &getCardNoString() const; + void setCardNo(int c); + void importPunches(const string &s); + string getPunchString(); + + void Set(const xmlobject &xo); + bool Write(xmlparser &xml); + + oCard(oEvent *poe); + oCard(oEvent *poe, int id); + + virtual ~oCard(); + + friend class oEvent; + friend class oRunner; + friend class oTeam; + friend class MeosSQL; +}; + +#endif // !defined(AFX_OCARD_H__674EAB76_A232_4E44_A9B4_C52F6A04D7CF__INCLUDED_) diff --git a/code/oClass.cpp b/code/oClass.cpp new file mode 100644 index 0000000..1d15b90 --- /dev/null +++ b/code/oClass.cpp @@ -0,0 +1,4154 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oClass.cpp: implementation of the oClass class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#define DODECLARETYPESYMBOLS + +#include +#include "oClass.h" +#include "oEvent.h" +#include "Table.h" +#include "meos_util.h" +#include +#include "Localizer.h" +#include +#include "inthashmap.h" +#include "intkeymapimpl.hpp" +#include "SportIdent.h" +#include "MeOSFeatures.h" +#include "gdioutput.h" +#include "gdistructures.h" +#include "meosexception.h" +#include "random.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +oClass::oClass(oEvent *poe): oBase(poe) +{ + getDI().initData(); + Course=0; + Id=oe->getFreeClassId(); + tLeaderTime.resize(1); + tNoTiming = -1; + tIgnoreStartPunch = -1; + tLegTimeToPlace = 0; + tLegAccTimeToPlace = 0; + tSplitRevision = 0; + tSortIndex = 0; + tMaxTime = 0; + tCoursesChanged = false; + tStatusRevision = 0; + tShowMultiDialog = false; +} + +oClass::oClass(oEvent *poe, int id): oBase(poe) +{ + getDI().initData(); + Course=0; + if (id == 0) + id = oe->getFreeClassId(); + Id=id; + oe->qFreeClassId = max(id, oe->qFreeClassId); + tLeaderTime.resize(1); + tNoTiming = -1; + tIgnoreStartPunch = -1; + tLegTimeToPlace = 0; + tLegAccTimeToPlace = 0; + tSplitRevision = 0; + tSortIndex = 0; + tMaxTime = 0; + tCoursesChanged = false; + tStatusRevision = 0; + tShowMultiDialog = false; +} + +oClass::~oClass() +{ + if (tLegTimeToPlace) + delete tLegTimeToPlace; + if (tLegAccTimeToPlace) + delete tLegAccTimeToPlace; +} + +bool oClass::Write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Class"); + + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.write("Name", Name); + + if (Course) + xml.write("Course", Course->Id); + + if (MultiCourse.size()>0) + xml.write("MultiCourse", codeMultiCourse()); + + if (legInfo.size()>0) + xml.write("LegMethod", codeLegMethod()); + + getDI().write(xml); + xml.endTag(); + + return true; +} + + +void oClass::Set(const xmlobject *xo) +{ + xmlList xl; + xo->getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Id")){ + Id = it->getInt(); + } + else if (it->is("Name")){ + Name = it->get(); + if (Name.size() > 1 && Name.at(0) == '%') { + Name = lang.tl(Name.substr(1)); + } + } + else if (it->is("Course")){ + Course = oe->getCourse(it->getInt()); + } + else if (it->is("MultiCourse")){ + set cid; + vector< vector > multi; + parseCourses(it->get(), multi, cid); + importCourses(multi); + } + else if (it->is("LegMethod")){ + importLegMethod(it->get());; + } + else if (it->is("oData")){ + getDI().set(*it); + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + } + + // Reinit temporary data + getNoTiming(); +} + +void oClass::importCourses(const vector< vector > &multi) +{ + MultiCourse.resize(multi.size()); + + for (size_t k=0;kgetCourse(multi[k][j]); + } + } + setNumStages(MultiCourse.size()); +} + +set &oClass::getMCourseIdSet(set &in) const +{ + in.clear(); + for (size_t k=0;kgetId()); + } + } + return in; +} + +string oClass::codeMultiCourse() const +{ + vector< vector >::const_iterator stage_it; + string str; + char bf[16]; + + for (stage_it=MultiCourse.begin();stage_it!=MultiCourse.end(); ++stage_it) { + vector::const_iterator it; + for (it=stage_it->begin();it!=stage_it->end(); ++it) { + if (*it){ + sprintf_s(bf, 16, " %d", (*it)->getId()); + str+=bf; + } + else str+=" 0"; + } + str += ";"; + } + + if (str.length() == 1) + return "@"; // Special code for the case of one stage and no course + else if (str.length()>0) { + return trim(str.substr(0, str.length()-1)); + } + //if (str.length()>0) + // return trim(str); + else return ""; +} + +void oClass::parseCourses(const string &courses, + vector< vector > &multi, + set &courseId) +{ + courseId.clear(); + multi.clear(); + if (courses.empty()) + return; + + const char *str=courses.c_str(); + + vector empty; + multi.push_back(empty); + int n_stage=0; + + while (*str && isspace(*str)) + str++; + + while (*str) { + int cid=atoi(str); + + if (cid) { + multi[n_stage].push_back(cid); + courseId.insert(cid); + } + + while (*str && (*str!=';' && *str!=' ')) str++; + + if (*str==';') { + str++; + while (*str && *str==' ') str++; + n_stage++; + multi.push_back(empty); + } + else { + if (*str) str++; + } + } +} + +string oLegInfo::codeLegMethod() const +{ + char bf[256]; + sprintf_s(bf, "(%s:%s:%d:%d:%d:%d)", StartTypeNames[startMethod], + LegTypeNames[legMethod], + legStartData, legRestartTime, + legRopeTime, duplicateRunner); + return bf; +} + +void oLegInfo::importLegMethod(const string &leg) +{ + //Defaults + startMethod=STTime; + legMethod=LTNormal; + legStartData = 0; + legRestartTime = 0; + + size_t begin=leg.find_first_of('('); + + if (begin==leg.npos) + return; + begin++; + + string coreLeg=leg.substr(begin, leg.find_first_of(')')-begin); + + vector< string > legsplit; + split(coreLeg, ":", legsplit); + + if (legsplit.size()>=1) { + for( int st = 0 ; st < nStartTypes ; ++st ) { + if ( legsplit[0]==StartTypeNames[st] ) { + startMethod=(StartTypes)st; + break; + } + } + } + if (legsplit.size()>=2) { + for( int t = 0 ; t < nLegTypes ; ++t ) { + if ( legsplit[1]==LegTypeNames[t] ) { + legMethod=(LegTypes)t; + break; + } + } + } + + if (legsplit.size()>=3) + legStartData = atoi(legsplit[2].c_str()); + + if (legsplit.size()>=4) + legRestartTime = atoi(legsplit[3].c_str()); + + if (legsplit.size()>=5) + legRopeTime = atoi(legsplit[4].c_str()); + + if (legsplit.size()>=6) + duplicateRunner = atoi(legsplit[5].c_str()); +} + +string oClass::codeLegMethod() const +{ + string code; + for(size_t k=0;k0) code+="*"; + code+=legInfo[k].codeLegMethod(); + } + return code; +} + +string oClass::getInfo() const +{ + return "Klass " + Name; +} + +void oClass::importLegMethod(const string &legMethods) +{ + vector< string > legsplit; + split(legMethods, "*", legsplit); + + legInfo.clear(); + for (size_t k=0;kRunners.begin(); it != oe->Runners.end(); ++it) { + if (it->getClassId()==Id) { + if (it->skip()) + continue; + if (checkFirstLeg && it->tLeg > 0) + continue; + if (noCountVacant && it->isVacant()) + continue; + if (noCountNotCompeting && it->getStatus() == StatusNotCompetiting) + continue; + nRunners++; + } + } + return nRunners; +} + + +void oClass::setCourse(pCourse c) +{ + if (Course!=c){ + if (MultiCourse.size() == 1) { + // MultiCourse wich is in fact only one course, (e.g. for fixed start time in class). Keep in synch. + if (c != 0) { + if (MultiCourse[0].size() == 1) + MultiCourse[0][0] = c; + else if (MultiCourse[0].size() == 0) + MultiCourse[0].push_back(c); + } + else { + if (MultiCourse[0].size() == 1) + MultiCourse[0].pop_back(); + } + } + Course=c; + tCoursesChanged = true; + updateChanged(); + // Update start from course + if (Course && !Course->getStart().empty()) { + setStart(Course->getStart()); + } + } +} + +void oClass::setName(const string &name) +{ + if (getName() != name) { + Name=name; + updateChanged(); + } +} + +oDataContainer &oClass::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = 0; + return *oe->oClassData; +} + +pClass oEvent::getClassCreate(int Id, const string &CreateName) +{ + oClassList::iterator it; + + if (Id>0) { + for (it=Classes.begin(); it != Classes.end(); ++it) { + if (it->Id==Id && !it->isRemoved()) { + + if (compareClassName(CreateName, it->getName())) { + if (it!=Classes.begin()) + Classes.splice(Classes.begin(), Classes, it, Classes.end()); + + return &Classes.front(); + } + else { + Id=0; //Bad Id + break; + } + } + } + } + + if (CreateName.empty() && Id>0) { + oClass c(this, Id); + c.setName(getAutoClassName()); + return addClass(c); + } + else { + //Check if class exist under different id + for (it=Classes.begin(); it != Classes.end(); ++it) { + if (!it->isRemoved() && compareClassName(it->Name, CreateName)) + return &*it; + } + + if (Id<=0) + Id=getFreeClassId(); + + oClass c(this, Id); + c.Name = CreateName; + + //No! Create class with this Id + pClass pc=addClass(c); + + //Not found. Auto add... + return pc; + } +} + +bool oEvent::getClassesFromBirthYear(int year, PersonSex sex, vector &classes) const { + classes.clear(); + + int age = year>0 ? getThisYear() - year : 0; + + int bestMatchClass = -1; + int bestMatchDist = 1000; + + for (oClassList::const_iterator it=Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + PersonSex clsSex = it->getSex(); + if (clsSex == sFemale && sex == sMale) + continue; + if (clsSex == sMale && sex == sFemale) + continue; + + int distance = 1000; + if (age>0) { + int high, low; + it->getAgeLimit(low, high); + + if (high>0 && age>high) + continue; + + if (low>0 && age0) + distance = high - age; + + if (low>0) + distance = min(distance, age-low); + + if (distance < bestMatchDist) { + if (bestMatchClass != -1) + classes.push_back(bestMatchClass); + // Add best class last + bestMatchClass = it->getId(); + bestMatchDist = distance; + } + else + classes.push_back(it->getId()); + } + else + classes.push_back(it->getId()); + } + + // Add best class last + if (bestMatchClass != -1) { + classes.push_back(bestMatchClass); + return true; + } + return false; +} + + + +static bool clsSortFunction (pClass i, pClass j) { + return (*i < *j); +} + +void oEvent::getClasses(vector &classes, bool sync) const { + if (sync) { + oe->synchronizeList(oLCourseId); + oe->reinitializeClasses(); + } + + classes.clear(); + for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + classes.push_back(pClass(&*it)); + } + + sort(classes.begin(), classes.end(), clsSortFunction); +} + + +pClass oEvent::getBestClassMatch(const string &cname) const { + return getClass(cname); +} + +pClass oEvent::getClass(const string &cname) const +{ + for (oClassList::const_iterator it=Classes.begin(); it != Classes.end(); ++it) { + if (!it->isRemoved() && compareClassName(cname, it->Name)) + return pClass(&*it); + } + return 0; +} + +pClass oEvent::getClass(int Id) const +{ + if (Id<=0) + return 0; + + oClassList::const_iterator it; + + for (it=Classes.begin(); it != Classes.end(); ++it){ + if (it->Id==Id && !it->isRemoved()) { + return pClass(&*it); + } + } + return 0; +} + +pClass oEvent::addClass(const string &pname, int CourseId, int classId) +{ + if (classId > 0){ + pClass pOld=getClass(classId); + if (pOld) + return 0; + } + + oClass c(this, classId); + c.Name=pname; + + if (CourseId>0) + c.Course=getCourse(CourseId); + + Classes.push_back(c); + Classes.back().synchronize(); + updateTabs(); + return &Classes.back(); +} + +pClass oEvent::addClass(oClass &c) +{ + if (c.Id==0) + return 0; + else { + pClass pOld=getClass(c.getId()); + if (pOld) + return 0; + } + + Classes.push_back(c); + + if (!Classes.back().existInDB()) { + Classes.back().changed = true; + Classes.back().synchronize(); + } + return &Classes.back(); +} + +bool oClass::fillStageCourses(gdioutput &gdi, int stage, + const string &name) const +{ + if (unsigned(stage)>=MultiCourse.size()) + return false; + + gdi.clearList(name); + const vector &Stage=MultiCourse[stage]; + vector::const_iterator it; + string out; + string str=""; + char bf[128]; + int m=0; + + for (it=Stage.begin(); it!=Stage.end(); ++it) { + sprintf_s(bf, "%d: %s", ++m, (*it)->getName().c_str()); + gdi.addItem(name, bf, (*it)->getId()); + } + + return true; +} + +bool oClass::addStageCourse(int iStage, int courseId) +{ + return addStageCourse(iStage, oe->getCourse(courseId)); +} + +bool oClass::addStageCourse(int iStage, pCourse pc) +{ + if (unsigned(iStage)>=MultiCourse.size()) + return false; + + vector &Stage=MultiCourse[iStage]; + + if (pc) { + tCoursesChanged = true; + Stage.push_back(pc); + updateChanged(); + return true; + } + return false; +} + + +void oClass::clearStageCourses(int stage) { + if (size_t(stage) < MultiCourse.size()) + MultiCourse[stage].clear(); +} + +bool oClass::removeStageCourse(int iStage, int CourseId, int position) +{ + if (unsigned(iStage)>=MultiCourse.size()) + return false; + + vector &Stage=MultiCourse[iStage]; + + if ( !(DWORD(position)getId()==CourseId){ + tCoursesChanged = true; + Stage.erase(Stage.begin()+position); + updateChanged(); + return true; + } + + return false; +} + +void oClass::setNumStages(int no) +{ + if (no>=0) { + if (MultiCourse.size() != no) + updateChanged(); + MultiCourse.resize(no); + legInfo.resize(no); + tLeaderTime.resize(max(no, 1)); + } + oe->updateTabs(); +} + +void oClass::getTrueStages(vector &stages) const +{ + stages.clear(); + if (!legInfo.empty()) { + for (size_t k = 0; k+1 < legInfo.size(); k++) { + if (legInfo[k].trueLeg != legInfo[k+1].trueLeg) { + stages.push_back(TrueLegInfo(k, legInfo[k].trueLeg)); + } + } + stages.push_back(TrueLegInfo(legInfo.size()-1, legInfo.back().trueLeg)); + + for (size_t k = 0; k 0 ? stages[k-1].first + 1: 0; + while(stages[k].nonOptional <= stages[k].first) { + if (!legInfo[stages[k].nonOptional].isOptional()) + break; + else + stages[k].nonOptional++; + } + } + } + else { + stages.push_back(TrueLegInfo(0,1)); + stages.back().nonOptional = -1; + } + +} + +bool oClass::startdataIgnored(int i) const +{ + StartTypes st=getStartType(i); + LegTypes lt=getLegType(i); + + if (lt==LTIgnore || lt==LTExtra || lt==LTParallel || lt == LTParallelOptional) + return true; + + if (st==STChange || st==STDrawn) + return true; + + return false; +} + +bool oClass::restartIgnored(int i) const +{ + StartTypes st=getStartType(i); + LegTypes lt=getLegType(i); + + if (lt==LTIgnore || lt==LTExtra || lt==LTParallel || lt == LTParallelOptional || lt == LTGroup) + return true; + + if (st==STTime || st==STDrawn) + return true; + + return false; +} + +void oClass::fillStartTypes(gdioutput &gdi, const string &name, bool firstLeg) +{ + gdi.clearList(name); + + gdi.addItem(name, lang.tl("Starttid"), STTime); + if (!firstLeg) + gdi.addItem(name, lang.tl("Växling"), STChange); + gdi.addItem(name, lang.tl("Tilldelad"), STDrawn); + if (!firstLeg) + gdi.addItem(name, lang.tl("Jaktstart"), STHunting); +} + +StartTypes oClass::getStartType(int leg) const +{ + if (unsigned(leg) 0 && (isParallel(leg) || isOptional(leg)) ) + return getRestartTime(leg-1); + + if (unsigned(leg) 0 && (isParallel(leg) || isOptional(leg)) ) + return getRopeTime(leg-1); + if (unsigned(leg)0) + return oe->getAbsTime(s); + else return "-"; + } + else if (t==STChange || t==STDrawn) + return "-"; + + return "?"; +} + +string oClass::getRestartTimeS(int leg) const +{ + int s=getRestartTime(leg); + StartTypes t=getStartType(leg); + + if (t==STChange || t==STHunting) { + if (s>0) + return oe->getAbsTime(s); + else return "-"; + } + else if (t==STTime || t==STDrawn) + return "-"; + + return "?"; +} + +string oClass::getRopeTimeS(int leg) const +{ + int s=getRopeTime(leg); + StartTypes t=getStartType(leg); + + if (t==STChange || t==STHunting) { + if (s>0) + return oe->getAbsTime(s); + else return "-"; + } + else if (t==STTime || t==STDrawn) + return "-"; + + return "?"; +} + +int oClass::getLegRunner(int leg) const +{ + if (unsigned(leg)=0) { + changed=true; + legInfo.resize(leg+1); + } + + legInfo[leg].duplicateRunner=runnerNo; + + if (changed) + updateChanged(); +} + +bool oClass::checkStartMethod() { + StartTypes st = STTime; + bool error = false; + for (size_t j = 0; j < legInfo.size(); j++) { + if (!legInfo[j].isParallel()) + st = legInfo[j].startMethod; + else if ((legInfo[j].startMethod == STChange || legInfo[j].startMethod == STHunting) && st != legInfo[j].startMethod) { + legInfo[j].startMethod = STDrawn; + error = true; + } + } + return error; +} + +void oClass::setStartType(int leg, StartTypes st, bool throwError) +{ + bool changed=false; + + if (unsigned(leg)=0) { + changed=true; + legInfo.resize(leg+1); + } + + legInfo[leg].startMethod=st; + + bool error = checkStartMethod(); + + if (changed || error) + updateChanged(); + + if (error && throwError) { + throw meosException("Ogiltig startmetod på sträcka X#" + itos(leg+1)); + } +} + +void oClass::setLegType(int leg, LegTypes lt) +{ + bool changed=false; + + if (unsigned(leg)=0) { + changed=true; + legInfo.resize(leg+1); + } + + legInfo[leg].legMethod=lt; + + bool error = checkStartMethod(); + + if (changed || error) { + apply(); + updateChanged(); + } + + if (error) { + throw meosException("Ogiltig startmetod på sträcka X#" + itos(leg+1)); + } +} + +bool oClass::setStartData(int leg, const string &s) { + int rt; + StartTypes styp=getStartType(leg); + if (styp==STTime || styp==STHunting) + rt=oe->getRelativeTime(s); + else + rt=atoi(s.c_str()); + + return setStartData(leg, rt); +} + +bool oClass::setStartData(int leg, int value) { + bool changed = false; + if (unsigned(leg)=0) { + changed = true; + legInfo.resize(leg+1); + } + legInfo[leg].legStartData = value; + + if (changed) + updateChanged(); + return changed; +} + +void oClass::setRestartTime(int leg, const string &t) +{ + int rt=oe->getRelativeTime(t); + bool changed=false; + + if (unsigned(leg)=0) { + changed=true; + legInfo.resize(leg+1); + } + legInfo[leg].legRestartTime=rt; + + if (changed) + updateChanged(); +} + +void oClass::setRopeTime(int leg, const string &t) +{ + int rt=oe->getRelativeTime(t); + bool changed=false; + + if (unsigned(leg)=0) { + changed=true; + legInfo.resize(leg+1); + } + legInfo[leg].legRopeTime=rt; + + if (changed) + updateChanged(); +} + + +void oClass::fillLegTypes(gdioutput &gdi, const string &name) +{ + vector< pair > types; + types.push_back( make_pair(lang.tl("Normal"), LTNormal)); + types.push_back( make_pair(lang.tl("Parallell"), LTParallel)); + types.push_back( make_pair(lang.tl("Valbar"), LTParallelOptional)); + types.push_back( make_pair(lang.tl("Extra"), LTExtra)); + types.push_back( make_pair(lang.tl("Summera"), LTSum)); + types.push_back( make_pair(lang.tl("Medlöpare"), LTIgnore)); + types.push_back( make_pair(lang.tl("Gruppera"), LTGroup)); + + gdi.addItem(name, types); +} + +void oEvent::fillClasses(gdioutput &gdi, const string &id, ClassExtra extended, ClassFilter filter) +{ + vector< pair > d; + oe->fillClasses(d, extended, filter); + gdi.addItem(id, d); +} + +const vector< pair > &oEvent::fillClasses(vector< pair > &out, + ClassExtra extended, ClassFilter filter) +{ + set undrawn; + set hasRunner; + out.clear(); + if (extended == extraDrawn) { + oRunnerList::iterator rit; + + for (rit=Runners.begin(); rit != Runners.end(); ++rit) { + bool needTime = true; + if (rit->isRemoved()) + continue; + + if (rit->Class) { + if (rit->Class->getNumStages() > 0 && rit->Class->getStartType(rit->tLeg) != STDrawn) + needTime = false; + } + if (rit->tStartTime==0 && needTime) + undrawn.insert(rit->getClassId()); + hasRunner.insert(rit->getClassId()); + } + } + else if (extended == extraNumMaps) + calculateNumRemainingMaps(); + + oClassList::iterator it; + synchronizeList(oLClassId); + + + reinitializeClasses(); + Classes.sort();//Sort by Id + + for (it=Classes.begin(); it != Classes.end(); ++it){ + if (!it->Removed) { + + if (filter==filterOnlyMulti && it->getNumStages()<=1) + continue; + else if (filter==filterOnlySingle && it->getNumStages()>1) + continue; + else if (filter==filterOnlyDirect && !it->getAllowQuickEntry()) + continue; + + if (extended == extraNone) + out.push_back(make_pair(it->Name, it->Id)); + //gdi.addItem(name, it->Name, it->Id); + else if (extended == extraDrawn) { + char bf[256]; + + if (it->MultiCourse.size() > 0 && it->getStartType(0) == STTime) + sprintf_s(bf, "%s\t%s", it->Name.c_str(), it->getStartDataS(0).c_str()); + else if (undrawn.count(it->getId()) || !hasRunner.count(it->getId())) + sprintf_s(bf, "%s", it->Name.c_str()); + else { + sprintf_s(bf, "%s\t[S]", it->Name.c_str()); + } + out.push_back(make_pair(string(bf), it->Id)); + //gdi.addItem(name, bf, it->Id); + } + else if (extended == extraNumMaps) { + char bf[256]; + int nmaps = it->getNumRemainingMaps(false); + if (nmaps != numeric_limits::min()) + sprintf_s(bf, "%s (%d %s)", it->Name.c_str(), nmaps, lang.tl("kartor").c_str()); + else + sprintf_s(bf, "%s ( - %s)", it->Name.c_str(), lang.tl("kartor").c_str()); + + out.push_back(make_pair(string(bf), it->Id)); + //gdi.addItem(name, bf, it->Id); + } + } + } + return out; +} + +void oEvent::getNotDrawnClasses(set &classes, bool someMissing) +{ + set drawn; + classes.clear(); + + oRunnerList::iterator rit; + + synchronizeList(oLRunnerId); + for (rit=Runners.begin(); rit != Runners.end(); ++rit) { + if (rit->tStartTime>0) + drawn.insert(rit->getClassId()); + else if (someMissing) + classes.insert(rit->getClassId()); + } + + // Return all classe where some runner has no start time + if (someMissing) + return; + + oClassList::iterator it; + synchronizeList(oLClassId); + + // Return classes where no runner has a start time + for (it=Classes.begin(); it != Classes.end(); ++it) { + if (drawn.count(it->getId())==0) + classes.insert(it->getId()); + } +} + + +void oEvent::getAllClasses(set &classes) +{ + classes.clear(); + + oClassList::const_iterator it; + synchronizeList(oLClassId); + + for (it=Classes.begin(); it != Classes.end(); ++it){ + if (!it->Removed){ + classes.insert(it->getId()); + } + } +} + +bool oEvent::fillClassesTB(gdioutput &gdi)//Table mode +{ + oClassList::iterator it; + synchronizeList(oLClassId); + + reinitializeClasses(); + Classes.sort();//Sort by Id + + int dx[4]={100, 100, 50, 100}; + int y=gdi.getCY(); + int x=gdi.getCX(); + int lh=gdi.getLineHeight(); + + y+=lh/2; + + int xp=x; + gdi.addString("", y, xp, 0, "Klass"); xp+=dx[0]; + gdi.addString("", y, xp, 0, "Bana"); xp+=dx[1]; + gdi.addString("", y, xp, 0, "Deltagare"); xp+=dx[2]; + y+=(3*lh)/2; + + for (it = Classes.begin(); it != Classes.end(); ++it){ + if (!it->Removed){ + int xp=x; + + gdi.addString("", y, xp, 0, it->getName(), dx[0]); xp+=dx[0]; + + pCourse pc=it->getCourse(); + if (pc) gdi.addString("", y, xp, 0, pc->getName(), dx[1]); + else gdi.addString("", y, xp, 0, "-", dx[1]); + xp+=dx[1]; + + char num[10]; + _itoa_s(it->getNumRunners(false, false, false), num, 10); + + gdi.addString("", y, xp, 0, num, dx[2]); + xp+=dx[2]; + + y+=lh; + } + } + return true; +} + +bool oClass::isCourseUsed(int Id) const +{ + if (Course && Course->getId()==Id) + return true; + + if (hasMultiCourse()){ + for(unsigned i=0;i &pv=MultiCourse[i]; + for(unsigned j=0; jgetId()==Id) return true; + } + } + + return false; +} + +string oClass::getClassResultStatus() const +{ + list::iterator it; + + int nrunner=0; + int nrunner_finish=0; + + for (it=oe->Runners.begin(); it!=oe->Runners.end();++it) { + if (it->getClassId()==Id){ + nrunner++; + + if (it->getStatus()) + nrunner_finish++; + } + } + + char bf[128]; + sprintf_s(bf, "%d/%d", nrunner_finish, nrunner); + + return bf; +} + +bool oClass::hasTrueMultiCourse() const { + if (MultiCourse.empty()) + return false; + return MultiCourse.size()>1 || hasCoursePool() || tShowMultiDialog || + (MultiCourse.size()==1 && MultiCourse[0].size()>1); +} + + +string oClass::getLength(int leg) const +{ + char bf[64]; + if (hasMultiCourse()){ + int minlen=1000000; + int maxlen=0; + + for(unsigned i=0;i &pv=MultiCourse[i]; + for(unsigned j=0; jgetLength(); + minlen=min(l, minlen); + maxlen=max(l, maxlen); + } + } + } + + if (maxlen==0) + return string(); + else if (minlen==0) + minlen=maxlen; + + if ( (maxlen-minlen)<100 ) + sprintf_s(bf, "%d", maxlen); + else + sprintf_s(bf, "%d - %d", minlen, maxlen); + + return MakeDash(bf); + } + else if (Course && Course->getLength()>0) { + return Course->getLengthS(); + } + return string(); +} + +bool oClass::hasUnorderedLegs() const { + return getDCI().getInt("Unordered") != 0; +} + +void oClass::setUnorderedLegs(bool order) { + getDI().setInt("Unordered", order); +} + +void oClass::getParallelRange(int leg, int &parLegRangeMin, int &parLegRangeMax) const { + parLegRangeMin = leg; + while (parLegRangeMin > 0 && size_t(parLegRangeMin) < legInfo.size()) { + if (legInfo[parLegRangeMin].isParallel()) + parLegRangeMin--; + else + break; + } + parLegRangeMax = leg; + while (size_t(parLegRangeMax+1) < legInfo.size()) { + if (legInfo[parLegRangeMax+1].isParallel() || legInfo[parLegRangeMax+1].isOptional()) + parLegRangeMax++; + else + break; + } +} + +void oClass::getParallelCourseGroup(int leg, int startNo, vector< pair > &group) const { + group.clear(); + // Assume hasUnorderedLegs + /*if (!hasUnorderedLegs()) { + pCourse crs = Course; + if (leg < MultiCourse.size()) { + int size = MultiCourse[leg].size(); + if (size > 0) { + crs = MultiCourse[leg][startNo%leg]; + } + } + group.push_back(make_pair(leg, crs)); + return; + } + else*/ { + // Find first leg in group + while (leg > 0 && size_t(leg) < legInfo.size()) { + if (legInfo[leg].isParallel()) + leg--; + else + break; + } + if (startNo <= 0) + startNo = 1; // Use first course + + // Fill in all legs in the group + do { + if (size_t(leg) < MultiCourse.size()) { + int size = MultiCourse[leg].size(); + if (size > 0) { + pCourse crs = MultiCourse[leg][(startNo-1)%size]; + group.push_back(make_pair(leg, crs)); + } + } + leg++; + } + while (size_t(leg) < legInfo.size() && + legInfo[leg].isParallel()); + } +} + +pCourse oClass::selectParallelCourse(const oRunner &r, const SICard &sic) { + synchronize(); + pCourse rc = 0; //Best match course + vector< pair > group; + getParallelCourseGroup(r.getLegNumber(), r.getStartNo(), group); + cTeam t = r.getTeam(); + if (t && group.size() > 1) { + for (size_t k = 0; k < group.size(); k++) { + pRunner tr = t->getRunner(group[k].first); + if (!tr) + continue; + + tr->synchronize(); + if (tr->Course) { + // The course is assigned. Remove from group + for (size_t j = 0; j < group.size(); j++) { + if (group[j].second == tr->Course) { + group[j].second = 0; + break; + } + } + } + } + + // Select best match of available courses + int distance=-1000; + for (size_t k = 0; k < group.size(); k++) { + if (group[k].second) { + int d = group[k].second->distance(sic); + if (d >= 0) { + if (distance < 0) + distance = 1000; + + if (d distance) { + distance=d; + rc = group[k].second; + } + } + } + } + + return rc; +} + + +pCourse oClass::getCourse(int leg, unsigned fork, bool getSampleFromRunner) const +{ + if (size_t(leg) < MultiCourse.size()) { + const vector &courses=MultiCourse[leg]; + if (courses.size()>0) { + int index = fork; + if (index>0) + index = (index-1) % courses.size(); + + return courses[index]; + } + } + + if (!getSampleFromRunner) + return 0; + else { + pCourse res = 0; + for (oRunnerList::iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->Class == this && it->Course) { + if (it->tLeg == leg) + return it->Course; + else + res = it->Course; // Might find better candidate later + } + } + return res; + } +} + +pCourse oClass::getCourse(bool getSampleFromRunner) const { + pCourse res; + if (MultiCourse.size() == 1 && MultiCourse[0].size() == 1) + res = MultiCourse[0][0]; + else + res = Course; + + if (!res && getSampleFromRunner) + res = getCourse(0,0, true); + + return res; +} + +void oClass::getCourses(int leg, vector &courses) const { + //leg == -1 -> all courses + courses.clear(); + if (leg <= 0 && Course) + courses.push_back(Course); + + for (size_t cl = 0; cl < MultiCourse.size(); cl++) { + if (leg>= 0 && cl != leg) + continue; + const vector &mc = MultiCourse[cl]; + for (size_t k = 0; k < mc.size(); k++) + if (find(courses.begin(), courses.end(), mc[k]) == courses.end()) + courses.push_back(mc[k]); + } + + // Add shortened versions + for (size_t k = 0; k < courses.size(); k++) { + pCourse sht = courses[k]->getShorterVersion(); + int maxIter = 10; + while (sht && --maxIter >= 0 ) { + if (find(courses.begin(), courses.end(), sht) == courses.end()) + courses.push_back(sht); + sht = sht->getShorterVersion(); + } + } +} + +ClassType oClass::getClassType() const +{ + if (legInfo.size()==2 && (legInfo[1].isParallel() || + legInfo[1].legMethod==LTIgnore) ) + return oClassPatrol; + else if (legInfo.size()>=2) { + + for(size_t k=1;kgetClassType(); + if (ct==oClassIndividual || ct==oClassIndividRelay) { + oRunnerList::const_iterator it; + int maxleg = pc->getLastStageIndex(); + + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (!it->skip() && it->getClassId()==id && it->getStatus() != StatusNotCompetiting) { + if (leg==0) { + total++; + + if (it->tStatus != StatusUnknown) + finished++; + else if (it->tStatus==StatusDNS) + dns++; + } + else { + int tleg = leg>0 ? leg : maxleg; + const pRunner r=it->getMultiRunner(tleg); + if (r) { + total++; + if (r->tStatus!=StatusUnknown) + finished++; + else if (it->tStatus==StatusDNS) + dns++; + } + } + } + } + } + else { + oTeamList::const_iterator it; + + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (it->getClassId()==id) { + total++; + + if (it->tStatus!=StatusUnknown || + it->getLegStatus(leg, false)!=StatusUnknown) + finished++; + } + } + } +} + +int oClass::getNumMultiRunners(int leg) const +{ + int ndup=0; + for (size_t k=0;k=nleg) + return 1; + + int nP = 1; + int i = leg; + while (++i=0 && legInfo[i--].isParallel()) + nP++; + return nP; +} + +int oClass::getNumDistinctRunners() const +{ + if (legInfo.empty()) + return 1; + + int ndist=0; + for (size_t k=0;k=MultiCourse.size()) + return Course; + + // First = course to check, second = course to assign. First could be a shortened version. + vector > layer(MultiCourse[leg].size()); + + for (size_t k = 0; k < layer.size(); k++) { + layer[k].first = MultiCourse[leg][k]; + layer[k].second = MultiCourse[leg][k]; + } + + while (Distance < 0 && !layer.empty()) { + + for (size_t k=0;k < layer.size(); k++) { + + if (layer[k].first) { + int d = layer[k].first->distance(card); + + if (d>=0) { + if (Distance<0) Distance=1000; + + if (dDistance) { + Distance=d; + rc = layer[k].second; + } + } + } + } + + if (Distance < 0) { + // If we have found no acceptable match, try the shortened courses, if any + vector< pair > shortenedLayer; + for (size_t k=0;k < layer.size(); k++) { + if (layer[k].first) { + pCourse sw = layer[k].first->getShorterVersion(); + if (sw) + shortenedLayer.push_back(make_pair(sw, layer[k].second)); + } + } + swap(layer, shortenedLayer); + } + } + + return const_cast(rc); +} + +void oClass::updateChangedCoursePool() { + if (!tCoursesChanged) + return; + + bool hasPool = hasCoursePool(); + vector< set > crs; + for (size_t k = 0; k < MultiCourse.size(); k++) { + crs.push_back(set()); + for (size_t j = 0; j < MultiCourse[k].size(); j++) { + if (MultiCourse[k][j]) + crs.back().insert(MultiCourse[k][j]); + } + } + + SICard card; + oRunnerList::iterator it; + for (it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->isRemoved() || it->Class != this) + continue; + + if (size_t(it->tLeg) >= crs.size() || crs[it->tLeg].empty()) + continue; + + if (!hasPool) { + if (it->Course) { + it->setCourseId(0); + it->synchronize(); + } + } + else { + bool correctCourse = crs[it->tLeg].count(it->Course) > 0; + if ((!correctCourse || (correctCourse && it->tStatus == StatusMP)) && it->Card) { + it->Card->getSICard(card); + pCourse crs = selectCourseFromPool(it->tLeg, card); + if (crs != it->Course) { + it->setCourseId(crs->getId()); + it->synchronize(); + } + } + } + } + tCoursesChanged = false; +} + +int oClass::getBestLegTime(int leg) const +{ + if (leg > 0 && tLeaderTime.size() == 1) + leg = 0; // The case with different class for team/runner. Leg is an index in another class. + + if (unsigned(leg)>=tLeaderTime.size()) + return 0; + else + return tLeaderTime[leg].bestTimeOnLeg; +} + +int oClass::getBestTimeCourse(int courseId) const +{ + map::const_iterator res = tBestTimePerCourse.find(courseId); + if (res == tBestTimePerCourse.end()) + return 0; + else + return res->second; +} + + +int oClass::getBestInputTime(int leg) const +{ + if (unsigned(leg)>=tLeaderTime.size()) + return 0; + else return + tLeaderTime[leg].inputTime; +} + + +int oClass::getTotalLegLeaderTime(int leg, bool includeInput) const +{ + if (unsigned(leg)>=tLeaderTime.size()) + return 0; + else { + if (includeInput) + return tLeaderTime[leg].totalLeaderTimeInput; + else + return tLeaderTime[leg].totalLeaderTime; + + } +} + +void oClass::mergeClass(int classIdSec) { + vector t; + vector r; + vector rThis; + + oe->getRunners(classIdSec, 0, rThis, true); + + // Update teams + oe->getTeams(classIdSec, t, true); + + for (size_t k = 0; k < t.size(); k++) { + pTeam it = t[k]; + it->Class = this; + it->updateChanged(); + for (size_t k=0;kRunners.size();k++) { + if (it->Runners[k]) { + it->Runners[k]->Class = this; + it->Runners[k]->updateChanged(); + } + } + it->synchronize(); //Synchronizes runners also + } + + oe->getRunners(classIdSec, 0, r, false); + // Update runners + for (size_t k = 0; k < r.size(); k++) { + pRunner it = r[k]; + it->Class = this; + it->updateChanged(); + it->synchronize(); + } + + // Check heats + + int maxHeatThis = 0; + bool missingHeatThis = false, uniqueHeatThis = true; + for (size_t k = 0; k < rThis.size(); k++) { + int heat = rThis[k]->getDCI().getInt("Heat"); + if (heat == 0) + missingHeatThis = true; + if (maxHeatThis != 0 && heat != maxHeatThis) + uniqueHeatThis = false; + maxHeatThis = max(maxHeatThis, heat); + } + + int maxHeatOther = 0; + bool missingHeatOther = false, uniqueHeatOther = true; + for (size_t k = 0; k < r.size(); k++) { + int heat = r[k]->getDCI().getInt("Heat"); + if (heat == 0) + missingHeatOther = true; + if (maxHeatOther != 0 && heat != maxHeatOther) + uniqueHeatOther = false; + maxHeatOther = max(maxHeatOther, heat); + } + int heatForNext = 1; + if (missingHeatThis) { + for (size_t k = 0; k < rThis.size(); k++) { + int heat = rThis[k]->getDCI().getInt("Heat"); + if (heat == 0) { + if (uniqueHeatThis && maxHeatThis > 0) + heat = maxHeatThis; // Some runners are missing the heat info. Fill in. + else { + // If maxHeatthis> 0, data somehow corrupted: + // Some runners have heat, but not unqiue, + // others are missing. Heats not well defined. + heat = maxHeatThis + 1; + } + } + heatForNext = max(heatForNext, heat+1); + rThis[k]->getDI().setInt("Heat", heat); + } + } + + if (missingHeatOther) { + for (size_t k = 0; k < r.size(); k++) { + int heat = r[k]->getDCI().getInt("Heat"); + if (heat == 0) { + if (maxHeatOther == 0) + heat = heatForNext; // No runner had a heat, set to next heat + else if (uniqueHeatOther) + heat = maxHeatOther; // Some runner missing the heat. Use the defined heat. + else + heat = maxHeatOther + 1; // Data corrupted, see above. Make a unique heat. + } + r[k]->getDI().setInt("Heat", heat); + } + } + // Write back + for (size_t k = 0; k < t.size(); k++) { + t[k]->synchronize(true); //Synchronizes runners also + } + for (size_t k = 0; k < r.size(); k++) { + r[k]->synchronize(true); + } + for (size_t k = 0; k < rThis.size(); k++) { + rThis[k]->synchronize(true); + } + + oe->removeClass(classIdSec); +} + +void oClass::getSplitMethods(vector< pair > &methods) { + methods.clear(); + methods.push_back(make_pair(lang.tl("Dela klubbvis"), SplitClub)); + methods.push_back(make_pair(lang.tl("Dela slumpmässigt"), SplitRandom)); + methods.push_back(make_pair(lang.tl("Dela efter ranking"), SplitRank)); + methods.push_back(make_pair(lang.tl("Dela efter placering"), SplitResult)); + methods.push_back(make_pair(lang.tl("Dela efter tid"), SplitTime)); + methods.push_back(make_pair(lang.tl("Jämna klasser (ranking)"), SplitRankEven)); + methods.push_back(make_pair(lang.tl("Jämna klasser (placering)"), SplitResultEven)); + methods.push_back(make_pair(lang.tl("Jämna klasser (tid)"), SplitTimeEven)); +} + +class ClassSplit { +private: + map clubSize; + map idSplit; + map clubSplit; + vector runners; + void splitClubs(const vector &parts); + void valueSplit(const vector &parts, vector< pair > &valueId); + void valueEvenSplit(const vector &parts, vector< pair > &valueId); + +public: + static int evaluateTime(const oAbstractRunner &r) { + if (r.getInputStatus() == StatusOK) { + int t = r.getInputTime(); + if (t > 0) + return t; + else + return 3600 * 24 * 8; + } + else { + return 3600 * 24 * 8 + r.getId(); + } + } + + static int evaluateResult(const oAbstractRunner &r) { + int baseRes; + if (r.getInputStatus() == StatusOK) { + int t = r.getInputPlace(); + if (t > 0) + baseRes = t; + else + baseRes = 99999; + } + else { + baseRes = 99999 + r.getInputStatus(); + } + return r.getDCI().getInt("Heat") + 1000 * baseRes; + } + + static int evaluatePoints(const oAbstractRunner &r) { + if (r.getInputStatus() == StatusOK) { + int p = r.getInputPoints(); + if (p > 0) + return 1000*1000*1000 - p; + else + return 1000*1000*1000; + } + else { + return 1000*1000*1000 + r.getInputStatus(); + } + } + +private: + int evaluate(const oAbstractRunner &r, ClassSplitMethod method) { + switch (method) { + case SplitRank: + case SplitRankEven: + return r.getRanking(); + case SplitTime: + case SplitTimeEven: + return evaluateTime(r); + case SplitResult: + case SplitResultEven: + return evaluateResult(r); + default: + throw meosException("Not yet implemented"); + } + } +public: + void addMember(const oAbstractRunner &r) { + ++clubSize[r.getClubId()]; + runners.push_back(&r); + } + + void split(const vector &parts, ClassSplitMethod method); + + int getClassIndex(const oAbstractRunner &r) { + if (clubSplit.count(r.getClubId())) + return clubSplit[r.getClubId()]; + else if (idSplit.count(r.getId())) + return idSplit[r.getId()]; + throw meosException("Internal split error"); + } +}; + +void ClassSplit::split(const vector &parts, ClassSplitMethod method) { + switch (method) { + case SplitClub: + splitClubs(parts); + break; + + case SplitRank: + case SplitTime: + case SplitResult: { + vector< pair > v(runners.size()); + for (size_t k = 0; k < v.size(); k++) { + v[k].second = runners[k]->getId(); + v[k].first = evaluate(*runners[k], method); + } + valueSplit(parts, v); + } break; + + case SplitRankEven: + case SplitTimeEven: + case SplitResultEven: { + vector< pair > v(runners.size()); + for (size_t k = 0; k < v.size(); k++) { + v[k].second = runners[k]->getId(); + v[k].first = evaluate(*runners[k], method); + } + valueEvenSplit(parts, v); + } break; + + + case SplitRandom: { + vector r(runners.size()); + for (size_t k = 0; k < r.size(); k++) { + r[k] = k; + } + permute(r); + vector< pair > v(runners.size()); + for (size_t k = 0; k < v.size(); k++) { + v[k].second = runners[k]->getId(); + v[k].first = r[k]; + } + valueEvenSplit(parts, v); + break; + } + default: + throw meosException("Not yet implemented"); + } +} + +void ClassSplit::splitClubs(const vector &parts) { + vector classSize(parts); + while ( !clubSize.empty() ) { + // Find largest club + int club=0; + int size=0; + for (map::iterator it=clubSize.begin(); it!=clubSize.end(); ++it) { + if (it->second>size) { + club = it->first; + size = it->second; + } + } + clubSize.erase(club); + // Find smallest class (e.g. highest number of remaining) + int nrunner = -1000000; + int cid = 0; + + for(size_t k = 0; k < parts.size(); k++) { + if (classSize[k]>nrunner) { + nrunner = classSize[k]; + cid = k; + } + } + + //Store result + clubSplit[club] = cid; + classSize[cid] -= size; + } +} + +void ClassSplit::valueSplit(const vector &parts, vector< pair > &valueId) { + sort(valueId.begin(), valueId.end()); + + int partIx = 0; + int partCount = 0; + for (size_t k = 0; k < valueId.size(); ) { + int refValue = valueId[k].first; + for (; k < valueId.size() && valueId[k].first == refValue; k++) { + idSplit[valueId[k].second] = partIx; + partCount++; + } + + if (k < valueId.size() && partCount >= parts[partIx] && size_t(partIx + 1) < parts.size()) { + partIx++; + partCount = 0; + } + } + + if (partIx == 0) { + throw meosException("error:invalidmethod"); + } +} + +void ClassSplit::valueEvenSplit(const vector &parts, vector< pair > &valueId) { + sort(valueId.begin(), valueId.end()); + if (valueId.empty() || valueId.front().first == valueId.back().first) { + throw meosException("error:invalidmethod"); + } + + vector count(parts.size()); + bool odd = true; + bool useRandomAssign = false; + + for (size_t k = 0; k < valueId.size(); ) { + vector distr; + + for (size_t j = 0; k < valueId.size() && j < parts.size(); j++) { + if (count[j] < parts[j]) { + distr.push_back(valueId[k++].second); + } + } + if (distr.empty()) { + idSplit[valueId[k++].second] = parts.size()-1; // Out of space, use last for rest + } + else { + if (useRandomAssign) { + permute(distr); //Random assignment to groups + } + else { + // Use reverse/forward distribution. Swedish SM rules + if (odd) + reverse(distr.begin(), distr.end()); + odd = !odd; + } + + for (size_t j = 0; j < parts.size(); j++) { + if (count[j] < parts[j]) { + ++count[j]; + idSplit[distr.back()] = j; + distr.pop_back(); + } + } + } + } +} + + +void oClass::splitClass(ClassSplitMethod method, const vector &parts, vector &outClassId) { + if (parts.size() <= 1) + return; + + bool defineHeats = method == SplitRankEven || method == SplitResultEven; + + ClassSplit cc; + vector t; + vector r; + + if ( oe->classHasTeams(getId()) ) { + oe->getTeams(getId(), t, true); + for (size_t k = 0; k < t.size(); k++) + cc.addMember(*t[k]); + } + else { + oe->getRunners(getId(), 0, r, true); + for (size_t k = 0; k < r.size(); k++) + cc.addMember(*r[k]); + } + // Split teams. + + cc.split(parts, method); + + vector pcv(parts.size()); + outClassId.resize(parts.size()); + pcv[0] = this; + outClassId[0] = getId(); + + pcv[0]->getDI().setInt("Heat", defineHeats ? 1 : 0); + pcv[0]->synchronize(true); + + int lastSI = getDI().getInt("SortIndex"); + for (size_t k=1; kaddClass(getName() + MakeDash(bf), getCourseId()); + if (pcv[k]) { + // Find suitable sort index + lastSI = pcv[k]->getSortIndex(lastSI + 1); + + memcpy(pcv[k]->oData, oData, sizeof(oData)); + + pcv[k]->getDI().setInt("SortIndex", lastSI); + pcv[k]->getDI().setInt("Heat", defineHeats ? k+1 : 0); + pcv[k]->synchronize(); + } + + outClassId[k] = pcv[k]->getId(); + } + + setName(getName() + MakeDash("-1")); + synchronize(); + + for (size_t k = 0; k < t.size(); k++) { + pTeam it = t[k]; + int clsIx = cc.getClassIndex(*it); + it->Class = pcv[clsIx]; + it->updateChanged(); + for (size_t k=0;kRunners.size();k++) { + if (it->Runners[k]) { + if (defineHeats) + it->getDI().setInt("Heat", clsIx+1); + it->Runners[k]->Class = it->Class; + it->Runners[k]->updateChanged(); + } + } + it->synchronize(); //Synchronizes runners also + } + + for (size_t k = 0; k < r.size(); k++) { + pRunner it = r[k]; + int clsIx = cc.getClassIndex(*it); + it->Class = pcv[clsIx]; + if (defineHeats) + it->getDI().setInt("Heat", clsIx+1); + it->updateChanged(); + it->synchronize(); + } +} + +void oClass::getAgeLimit(int &low, int &high) const +{ + low = getDCI().getInt("LowAge"); + high = getDCI().getInt("HighAge"); +} + +void oClass::setAgeLimit(int low, int high) +{ + getDI().setInt("LowAge", low); + getDI().setInt("HighAge", high); +} + +int oClass::getExpectedAge() const +{ + int low, high; + getAgeLimit(low, high); + + if (low>0 && high>0) + return (low+high)/2; + + if (low==0 && high>0) + return high-3; + + if (low>0 && high==0) + return low + 1; + + + // Try to guess age from class name + for (size_t k=0; k='0' && Name[k]<='9') { + int age = atoi(&Name[k]); + if (age>=10 && age<100) { + if (age>=10 && age<=20) + return age - 1; + else if (age==21) + return 28; + else if (age>=35) + return age + 2; + } + } + } + + return 0; +} + +void oClass::setSex(PersonSex sex) +{ + getDI().setString("Sex", encodeSex(sex)); +} + +PersonSex oClass::getSex() const +{ + return interpretSex(getDCI().getString("Sex")); +} + +void oClass::setStart(const string &start) +{ + getDI().setString("StartName", start); +} + +string oClass::getStart() const +{ + return getDCI().getString("StartName"); +} + +void oClass::setBlock(int block) +{ + getDI().setInt("StartBlock", block); +} + +int oClass::getBlock() const +{ + return getDCI().getInt("StartBlock"); +} + +void oClass::setAllowQuickEntry(bool quick) +{ + getDI().setInt("AllowQuickEntry", quick); +} + +bool oClass::getAllowQuickEntry() const +{ + return getDCI().getInt("AllowQuickEntry")!=0; +} + +void oClass::setNoTiming(bool quick) +{ + tNoTiming = quick ? 1 : 0; + getDI().setInt("NoTiming", quick); +} + +BibMode oClass::getBibMode() const { + const string &bm = getDCI().getString("BibMode"); + char b = bm.c_str()[0]; + if (b == 'A') + return BibAdd; + else if (b == 'F') + return BibFree; + else if (b == 'L') + return BibLeg; + else + return BibSame; +} + +void oClass::setBibMode(BibMode bibMode) { + string res; + switch (bibMode) { + case BibAdd: + res = "A"; + break; + case BibFree: + res = "F"; + break; + case BibLeg: + res = "L"; + break; + case BibSame: + res = ""; + break; + default: + throw meosException("Invalid bib mode"); + } + + getDI().setString("BibMode", res); +} + + +bool oClass::getNoTiming() const { + if (tNoTiming!=0 && tNoTiming!=1) + tNoTiming = getDCI().getInt("NoTiming")!=0 ? 1 : 0; + return tNoTiming!=0; +} + +void oClass::setIgnoreStartPunch(bool ignoreStartPunch) { + tIgnoreStartPunch = ignoreStartPunch; + getDI().setInt("IgnoreStart", ignoreStartPunch); +} + +bool oClass::ignoreStartPunch() const { + if (tIgnoreStartPunch!=0 && tIgnoreStartPunch!=1) + tIgnoreStartPunch = getDCI().getInt("IgnoreStart")!=0 ? 1 : 0; + return tIgnoreStartPunch != 0; +} + +void oClass::setFreeStart(bool quick) +{ + getDI().setInt("FreeStart", quick); +} + +bool oClass::hasFreeStart() const +{ + bool fs = getDCI().getInt("FreeStart") != 0; + return fs; +} + +void oClass::setDirectResult(bool quick) +{ + getDI().setInt("DirectResult", quick); +} + +bool oClass::hasDirectResult() const +{ + return getDCI().getInt("DirectResult") != 0; +} + + +void oClass::setType(const string &start) +{ + getDI().setString("ClassType", start); +} + +string oClass::getType() const +{ + return getDCI().getString("ClassType"); +} + +void oEvent::fillStarts(gdioutput &gdi, const string &id) +{ + vector< pair > d; + oe->fillStarts(d); + gdi.addItem(id, d); +} + +const vector< pair > &oEvent::fillStarts(vector< pair > &out) +{ + out.clear(); + set starts; + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (!it->getStart().empty()) + starts.insert(it->getStart()); + } + + if (starts.empty()) + starts.insert("Start 1"); + + for (set::iterator it = starts.begin(); it!=starts.end(); ++it) { + //gdi.addItem(id, *it); + out.push_back(make_pair(*it, 0)); + } + return out; +} + +void oEvent::fillClassTypes(gdioutput &gdi, const string &id) +{ + vector< pair > d; + oe->fillClassTypes(d); + gdi.addItem(id, d); +} + +ClassMetaType oClass::interpretClassType() const { + int lowAge; + int highAge; + getAgeLimit(lowAge, highAge); + + if (highAge>0 && highAge <= 16) + return ctYouth; + + map types; + oe->getPredefinedClassTypes(types); + + string type = getType(); + + for (map::iterator it = types.begin(); it != types.end(); ++it) { + if (type == it->first || type == lang.tl(it->first)) + return it->second; + } + + if (oe->classTypeNameToType.empty()) { + // Lazy readout of baseclasstypes + char path[_MAX_PATH]; + getUserFile(path, "baseclass.xml"); + xmlparser xml(0); + xml.read(path); + xmlobject cType = xml.getObject("BaseClassTypes"); + xmlList xtypes; + cType.getObjects("Type", xtypes); + for (size_t k = 0; kclassTypeNameToType[name] = mtype; + } + } + + if (oe->classTypeNameToType.count(type) == 1) + return oe->classTypeNameToType[type]; + + return ctUnknown; +} + +void oClass::assignTypeFromName(){ + string type = getType(); + if (type.empty()) { + string prefix, suffix; + int age = extractAnyNumber(Name, prefix, suffix); + + ClassMetaType mt = ctUnknown; + if (age>=18) { + if (stringMatch(suffix, lang.tl("Elit")) || strchr(suffix.c_str(), 'E')) + mt = ctElite; + else if (stringMatch(suffix, lang.tl("Motion")) || strchr(suffix.c_str(), 'M')) + mt = ctExercise; + else + mt = ctNormal; + } + else if (age>=10 && age<=16) { + mt = ctYouth; + } + else if (age<10) { + if (stringMatch(prefix, lang.tl("Ungdom")) || strchr(prefix.c_str(), 'U')) + mt = ctYouth; + else if (stringMatch(suffix, lang.tl("Motion")) || strchr(suffix.c_str(), 'M')) + mt = ctExercise; + else + mt = ctOpen; + } + + map types; + oe->getPredefinedClassTypes(types); + + for (map::iterator it = types.begin(); it != types.end(); ++it) { + if (it->second == mt) { + setType(lang.tl(it->first)); + return; + } + } + + + } +} + +void oEvent::getPredefinedClassTypes(map &types) const { + types.clear(); + types["Elit"] = ctElite; + types["Vuxen"] = ctNormal; + types["Ungdom"] = ctYouth; + types["Motion"] = ctExercise; + types["Öppen"] = ctOpen; + types["Träning"] = ctTraining; +} + +const vector< pair > &oEvent::fillClassTypes(vector< pair > &out) +{ + out.clear(); + set cls; + bool allHasType = !Classes.empty(); + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + if (!it->getType().empty()) + cls.insert(it->getType()); + else + allHasType = false; + } + + if (!allHasType) { + map types; + getPredefinedClassTypes(types); + + for (map::iterator it = types.begin(); it != types.end(); ++it) + cls.insert(lang.tl(it->first)); + } + + for (set::iterator it = cls.begin(); it!=cls.end(); ++it) { + //gdi.addItem(id, *it); + out.push_back(make_pair(*it, 0)); + } + return out; +} + + +int oClass::getNumRemainingMaps(bool recalculate) const +{ + if (recalculate) + oe->calculateNumRemainingMaps(); + + if (Course) + return Course->tMapsRemaining; + else + return numeric_limits::min(); +} + +void oEvent::getStartBlocks(vector &blocks, vector &starts) const +{ + oClassList::const_iterator it; + map bs; + for (it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + map::iterator v = bs.find(it->getBlock()); + + if (v!=bs.end() && v->first!=0 && v->second!=it->getStart()) { + string msg = "Ett startblock spänner över flera starter: X/Y#" + it->getStart() + "#" + v->second; + throw std::exception(msg.c_str()); + } + bs[it->getBlock()] = it->getStart(); + } + + blocks.clear(); + starts.clear(); + + if (bs.size() > 1) { + for (map::iterator v = bs.begin(); v != bs.end(); ++v) { + blocks.push_back(v->first); + starts.push_back(v->second); + } + } + else if (bs.size() == 1) { + set s; + for (it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + s.insert(it->getStart()); + } + for (set::iterator v = s.begin(); v != s.end(); ++v) { + blocks.push_back(bs.begin()->first); + starts.push_back(*v); + } + + } + + +} + +Table *oEvent::getClassTB()//Table mode +{ + if (tables.count("class") == 0) { + Table *table=new Table(this, 20, "Klasser", "classes"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 200, false); + oe->oClassData->buildTableCol(table); + tables["class"] = table; + table->addOwnership(); + } + + tables["class"]->update(); + return tables["class"]; +} + +void oEvent::generateClassTableData(Table &table, oClass *addClass) +{ + if (addClass) { + addClass->addTableRow(table); + return; + } + + synchronizeList(oLClassId); + oClassList::iterator it; + + for (it=Classes.begin(); it != Classes.end(); ++it){ + if (!it->isRemoved()) + it->addTableRow(table); + } +} + +void oClass::addTableRow(Table &table) const { + pClass it = pClass(this); + table.addRow(getId(), it); + + int row = 0; + table.set(row++, *it, TID_ID, itos(getId()), false); + table.set(row++, *it, TID_MODIFIED, getTimeStamp(), false); + + table.set(row++, *it, TID_CLASSNAME, getName(), true); + oe->oClassData->fillTableCol(*this, table, true); +} + + + +bool oClass::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + synchronize(false); + + if (id>1000) { + return oe->oClassData->inputData(this, id, input, + inputId, output, noUpdate); + } + switch(id) { + case TID_CLASSNAME: + setName(input); + synchronize(); + output=getName(); + return true; + break; + } + + return false; +} + +void oClass::fillInput(int id, vector< pair > &out, size_t &selected) +{ + if (id>1000) { + oe->oClassData->fillInput(oData, id, 0, out, selected); + return; + } + + if (id==TID_COURSE) { + out.clear(); + oe->fillCourses(out, true); + out.push_back(make_pair(lang.tl("Ingen bana"), 0)); + //gdi.selectItemByData(controlId.c_str(), Course ? Course->getId() : 0); + selected = Course ? Course->getId() : 0; + } +} + + +void oClass::getStatistics(const set &feeLock, int &entries, int &started) const +{ + oRunnerList::const_iterator it; + entries = 0; + started = 0; + for (it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->skip() || it->isVacant()) + continue; + if (it->getStatus() == StatusNotCompetiting) + continue; + + if (it->getClassId()==Id) { + if (feeLock.empty() || feeLock.count(it->getDCI().getInt("Fee"))) { + entries++; + if (it->getStatus()!= StatusUnknown && it->getStatus()!= StatusDNS) + started++; + } + } + } +} + +bool oClass::isSingleRunnerMultiStage() const +{ + return getNumStages()>1 && getNumDistinctRunnersMinimal()==1; +} + +int oClass::getEntryFee(const string &date, int age) const +{ + oDataConstInterface odc = oe->getDCI(); + string oentry = odc.getDate("OrdinaryEntry"); + bool late = date > oentry && oentry>="2010-01-01"; + bool reduced = false; + + if (age > 0) { + int low = odc.getInt("YouthAge"); + int high = odc.getInt("SeniorAge"); + reduced = age <= low || (high > 0 && age >= high); + } + + if (reduced) { + int high = getDCI().getInt("HighClassFeeRed"); + int normal = getDCI().getInt("ClassFeeRed"); + + // Only return these fees if set + if (high>0 && late) + return high; + else if (normal>0) + return normal; + } + + if (late) + return getDCI().getInt("HighClassFee"); + else + return getDCI().getInt("ClassFee"); +} + +void oClass::addClassDefaultFee(bool resetFee) { + int fee = getDCI().getInt("ClassFee"); + + if (fee == 0 || resetFee) { + assignTypeFromName(); + ClassMetaType type = interpretClassType(); + // if (type.empty()) + switch (type) { + case ctElite: + fee = oe->getDCI().getInt("EliteFee"); + break; + case ctYouth: + fee = oe->getDCI().getInt("YouthFee"); + break; + default: + fee = oe->getDCI().getInt("EntryFee"); + } + + int reducedFee = oe->getDCI().getInt("YouthFee"); + + double factor = 1.0 + 0.01 * atof(oe->getDCI().getString("LateEntryFactor").c_str()); + int lateFee = fee; + int lateReducedFee = reducedFee; + + if (factor > 1) { + lateFee = int(fee*factor + 0.5); + lateReducedFee = int(reducedFee*factor + 0.5); + } + getDI().setInt("ClassFee", fee); + getDI().setInt("HighClassFee", lateFee); + getDI().setInt("ClassFeeRed", reducedFee); + getDI().setInt("HighClassFeeRed", lateReducedFee); + } +} + +void oClass::reinitialize() +{ + int ix = getDI().getInt("SortIndex"); + if (ix == 0) { + ix = getSortIndex(getId()*10); + getDI().setInt("SortIndex", ix); + } + tSortIndex = ix; + + tMaxTime = getDI().getInt("MaxTime"); + if (tMaxTime == 0 && oe) { + tMaxTime = oe->getMaximalTime(); + } + + tNoTiming = -1; + tIgnoreStartPunch = -1; +} + +void oEvent::reinitializeClasses() +{ + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) + it->reinitialize(); +} + +int oClass::getSortIndex(int candidate) +{ + int major = numeric_limits::max(); + int minor = 0; + + for (oClassList::iterator it = oe->Classes.begin(); it != oe->Classes.end(); ++it) { + int ix = it->getDCI().getInt("SortIndex"); + if (ix>0) { + if (ix>candidate && ixminor) + minor = ix; + } + } + + // If the gap is less than 10 (which is the default), optimize + if (major < numeric_limits::max() && minor>0 && ((major-candidate)<10 || (candidate-minor)<10)) + return (major+minor)/2; + else + return candidate; +} + +void oClass::apply() { + int trueLeg = 0; + int trueSubLeg = 0; + + for (size_t k = 0; kclassChanged(this, false); +} + +void oClass::insertLegPlace(int from, int to, int time, int place) +{ + if (tLegTimeToPlace) { + int key = time + (to + from*256)*8013; + tLegTimeToPlace->insert(key, place); + } +} + +int oClass::getLegPlace(int ifrom, int ito, int time) const +{ + if (tLegTimeToPlace) { + int key = time + (ito + ifrom*256)*8013; + int place; + if (tLegTimeToPlace->lookup(key, place)) + return place; + } + return 0; +} + +void oClass::insertAccLegPlace(int courseId, int controlNo, int time, int place) +{ /* + char bf[256]; + sprintf_s(bf, "Insert to %d, %d, time %d\n", courseId, controlNo, time); + OutputDebugString(bf); + */ + if (tLegAccTimeToPlace) { + int key = time + (controlNo + courseId*128)*16013; + tLegAccTimeToPlace->insert(key, place); + } +} + +void oClass::getStartRange(int leg, int &firstStart, int &lastStart) const { + if (tFirstStart.empty()) { + size_t s = getLastStageIndex() + 1; + assert(s>0); + vector lFirstStart, lLastStart; + lFirstStart.resize(s, 3600 * 24 * 365); + lLastStart.resize(s, 0); + for (oRunnerList::iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->isRemoved() || it->Class != this) + continue; + if (it->needNoCard()) + continue; + size_t tleg = it->tLeg; + if (tleg < s) { + lFirstStart[tleg] = min(lFirstStart[tleg], it->tStartTime); + lLastStart[tleg] = max(lLastStart[tleg], it->tStartTime); + } + } + swap(tLastStart, lLastStart); + swap(tFirstStart, lFirstStart); + } + if (size_t(leg) < tFirstStart.size()) { + firstStart = tFirstStart[leg]; + lastStart = tLastStart[leg]; + } + else if (!tFirstStart.empty()) { + firstStart = tFirstStart[0]; + lastStart = tLastStart[0]; + for (size_t k = 1; k < tFirstStart.size(); k++) { + if (lastStart > 0) { + firstStart = min(tFirstStart[k], firstStart); + lastStart = max(tLastStart[k], lastStart); + } + } + } + else { + firstStart = 0; + lastStart = 0; + } +} + +int oClass::getAccLegPlace(int courseId, int controlNo, int time) const +{/* + char bf[256]; + sprintf_s(bf, "Get from %d, %d, time %d\n", courseId, controlNo, time); + OutputDebugString(bf); + */ + if (tLegAccTimeToPlace) { + int key = time + (controlNo + courseId*128)*16013; + int place; + if (tLegAccTimeToPlace->lookup(key, place)) + return place; + } + return 0; +} + + +void oClass::calculateSplits() { + clearSplitAnalysis(); + set cSet; + map > legToTime; + + for (size_t k=0;k::iterator cit = cSet.begin(); cit!= cSet.end(); ++cit) { + pCourse pc = *cit; + // Store all split times in a matrix + const unsigned nc = pc->getNumControls(); + if (nc == 0) + return; + + vector< vector > splits(nc+1); + vector< vector > splitsAcc(nc+1); + vector acceptMissingPunch(nc+1, true); + + for (oRunnerList::iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->isRemoved() || it->Class != this) + continue; + pCourse tpc = it->getCourse(false); + if (tpc != pc || tpc == 0) + continue; + + const vector &sp = it->getSplitTimes(true); + const int s = min(nc, sp.size()); + + for (int k = 0; k < s; k++) { + if (sp[k].time > 0 && acceptMissingPunch[k]) { + pControl ctrl = tpc->getControl(k); + // If there is a + if (ctrl && ctrl->getStatus() != oControl::StatusBad && ctrl->getStatus() != oControl::StatusOptional) + acceptMissingPunch[k] = false; + } + } + } + for (oRunnerList::iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->isRemoved() || it->Class != this) + continue; + + pCourse tpc = it->getCourse(false); + + if (tpc != pc) + continue; + + const vector &sp = it->getSplitTimes(true); + const int s = min(nc, sp.size()); + + vector &tLegTimes = it->tLegTimes; + tLegTimes.resize(nc + 1); + bool ok = true; + + for (int k = 0; k < s; k++) { + if (sp[k].time > 0) { + if (ok) { + // Store accumulated times + int t = sp[k].time - it->tStartTime; + if (it->tStartTime>0 && t>0) + splitsAcc[k].push_back(t); + } + + if (k == 0) { // start -> first + int t = sp[0].time - it->tStartTime; + if (it->tStartTime>0 && t>0) { + splits[k].push_back(t); + tLegTimes[k] = t; + } + else + tLegTimes[k] = 0; + } + else { // control -> control + int t = sp[k].time - sp[k-1].time; + if (sp[k-1].time>0 && t>0) { + splits[k].push_back(t); + tLegTimes[k] = t; + } + else + tLegTimes[k] = 0; + } + } + else + ok = acceptMissingPunch[k]; + } + + // last -> finish + if (sp.size() == nc && sp[nc-1].time>0 && it->FinishTime > 0) { + int t = it->FinishTime - sp[nc-1].time; + if (t>0) { + splits[nc].push_back(t); + tLegTimes[nc] = t; + if (it->statusOK() && (it->FinishTime - it->tStartTime) > 0) { + splitsAcc[nc].push_back(it->FinishTime - it->tStartTime); + } + } + else + tLegTimes[nc] = 0; + } + } + + if (splits.size()>0 && tLegTimeToPlace == 0) { + tLegTimeToPlace = new inthashmap(splits.size() * splits[0].size()); + tLegAccTimeToPlace = new inthashmap(splits.size() * splits[0].size()); + } + + vector &accLeaderTime = tCourseAccLegLeaderTime[pc->getId()]; + + for (size_t k = 0; k < splits.size(); k++) { + + // Calculate accumulated best times and places + if (!splitsAcc[k].empty()) { + sort(splitsAcc[k].begin(), splitsAcc[k].end()); + accLeaderTime.push_back(splitsAcc[k].front()); // Store best time + + int place = 1; + for (size_t j = 0; j < splitsAcc[k].size(); j++) { + if (j>0 && splitsAcc[k][j-1]getId(), k, splitsAcc[k][j], place); + } + } + else { + // Bad control / missing times + int t = 0; + if (!accLeaderTime.empty()) + t = accLeaderTime.back(); + accLeaderTime.push_back(t); // Store time from previous leg + } + + sort(splits[k].begin(), splits[k].end()); + const size_t ntimes = splits[k].size(); + if (ntimes == 0) + continue; + + int from = pc->getCommonControl(), to = pc->getCommonControl(); // Represents start/finish + if (k < nc && pc->getControl(k)) + to = pc->getControl(k)->getId(); + if (k>0 && pc->getControl(k-1)) + from = pc->getControl(k-1)->getId(); + + for (size_t j = 0; j < ntimes; j++) + legToTime[256*from + to].push_back(splits[k][j]); + + int time = 0; + if (ntimes < 5) + time = splits[k][0]; // Best time + else if (ntimes < 12) + time = (splits[k][0]+splits[k][1]) / 2; //Average best time + else { + int nval = ntimes/6; + for (int r = 1; r <= nval; r++)// "Best fraction", skip winner + time += splits[k][r]; + time /= nval; + } + + legRes.addTime(from, to, time); + legBestTime.addTime(from, to, splits[k][0]); // Add leader time + } + } + + // Loop and sort times for each leg run in this class + for (map >::iterator cit = legToTime.begin(); cit != legToTime.end(); ++cit) { + int key = cit->first; + vector × = cit->second; + sort(times.begin(), times.end()); + int jsiz = times.size(); + for (int j = 0; j::iterator cit = cSet.begin(); cit != cSet.end(); ++cit) { + pCourse pc = *cit; + const unsigned nc = pc->getNumControls(); + vector normRes(nc+1); + vector bestRes(nc+1); + int cc = pc->getCommonControl(); + for (size_t k = 0; k <= nc; k++) { + int from = cc, to = cc; // Represents start/finish + if (k < nc && pc->getControl(k)) + to = pc->getControl(k)->getId(); + if (k>0 && pc->getControl(k-1)) + from = pc->getControl(k-1)->getId(); + normRes[k] = legRes.getTime(from, to); + bestRes[k] = legBestTime.getTime(from, to); + } + + swap(tSplitAnalysisData[pc->getId()], normRes); + swap(tCourseLegLeaderTime[pc->getId()], bestRes); + } +} + +bool oClass::isRogaining() const { + if (Course) + return Course->getMaximumRogainingTime() > 0; + + for (size_t k = 0;kgetMaximumRogainingTime() > 0; + + return false; +} + +void oClass::remove() +{ + if (oe) + oe->removeClass(Id); +} + +bool oClass::canRemove() const +{ + return !oe->isClassUsed(Id); +} + +int oClass::getMaximumRunnerTime() const { + return tMaxTime; +} + +int oClass::getNumLegNoParallel() const { + int nl = 1; + for (size_t k = 1; k < legInfo.size(); k++) { + if (!legInfo[k].isParallel()) + nl++; + } + return nl; +} + +bool oClass::splitLegNumberParallel(int leg, int &legNumber, int &legOrder) const { + legNumber = 0; + legOrder = 0; + if (legInfo.empty()) + return false; + + int stop = min(leg, legInfo.size() - 1); + int k; + for (k = 0; k < stop; k++) { + if (legInfo[k+1].isParallel() || legInfo[k+1].isOptional()) + legOrder++; + else { + legOrder = 0; + legNumber++; + } + } + if (legOrder == 0) { + if (k+1 < int(legInfo.size()) && (legInfo[k+1].isParallel() || legInfo[k+1].isOptional())) + return true; + if (!(legInfo[k].isParallel() || legInfo[k].isOptional())) + return false; + } + return true; +} + +int oClass::getLegNumberLinear(int legNumberIn, int legOrderIn) const { + if (legNumberIn == 0 && legOrderIn == 0) + return 0; + + int legNumber = 0; + int legOrder = 0; + for (size_t k = 1; k < legInfo.size(); k++) { + if (legInfo[k].isParallel() || legInfo[k].isOptional()) + legOrder++; + else { + legOrder = 0; + legNumber++; + } + if (legNumberIn == legNumber && legOrderIn == legOrder) + return k; + } + + return -1; +} + +/** Return an actual linear index for this class. */ +int oClass::getLinearIndex(int index, bool isLinear) const { + if (legInfo.empty()) + return 0; + if (size_t(index) >= legInfo.size()) + return legInfo.size() - 1; // -1 to last leg + + return isLinear ? index : getLegNumberLinear(index, 0); +} + +string oClass::getLegNumber(int leg) const { + int legNumber, legOrder; + bool par = splitLegNumberParallel(leg, legNumber, legOrder); + char bf[16]; + if (par) { + char symb = 'a' + legOrder; + sprintf_s(bf, "%d%c", legNumber + 1, symb); + } + else { + sprintf_s(bf, "%d", legNumber + 1); + } + return bf; +} + +oClass::ClassStatus oClass::getClassStatus() const { + if (tStatusRevision != oe->dataRevision) { + string s = getDCI().getString("Status"); + if (s == "I") + tStatus = Invalid; + else if (s == "IR") + tStatus = InvalidRefund; + else + tStatus = Normal; + + tStatusRevision = oe->dataRevision; + } + return tStatus; +} + +void oClass::clearCache(bool recalculate) { + if (recalculate) + oe->reCalculateLeaderTimes(getId()); + clearSplitAnalysis(); + tResultInfo.clear();//Do on competitor remove! +} + + +bool oClass::wasSQLChanged(int leg, int control) const { + if (oe->globalModification) + return true; + + map >::const_iterator res = sqlChangedControlLeg.find(-1); + if (res != sqlChangedControlLeg.end()) { + if (leg == -1 || res->second.count(-1) || res->second.count(leg)) + return true; + } + + if (control != -1) { + res = sqlChangedControlLeg.find(control); + if (res != sqlChangedControlLeg.end()) { + if (leg == -1 || res->second.count(-1) || res->second.count(leg)) + return true; + } + } + + res = sqlChangedLegControl.find(leg); + if (res != sqlChangedLegControl.end()) { + if (control == -1 || res->second.count(-1) || res->second.count(control)) + return true; + } + + return false; +} + +void oClass::markSQLChanged(int leg, int control) { + sqlChangedControlLeg[control].insert(leg); + sqlChangedLegControl[leg].insert(control); + oe->classChanged(this, false); +} + +void oClass::changedObject() { + markSQLChanged(-1,-1); + tNoTiming = -1; + tIgnoreStartPunch = -1; +} + +static void checkMissing(const map< pair, int > &master, + const map< pair, int > &check, + set< pair > &controlProblems) { + assert(master.size() >= check.size()); + + for ( map< pair, int >::const_iterator it = master.begin(); + it != master.end(); ++it) { + map< pair, int >::const_iterator res = check.find(it->first); + if (res == check.end() || res->second != it->second) + controlProblems.insert(it->first); + } +} + +// Check if forking is fair +bool oClass::checkForking(vector< vector > &legOrder, + vector< vector > &forks, + set< pair > &unfairLegs) const { + legOrder.clear(); + forks.clear(); + map hashes; + int max = 1; + set factors; + for (size_t k = 0; k < MultiCourse.size(); k++) { + if (MultiCourse[k].size() > 1 && factors.count(MultiCourse[k].size()) == 0) { + max *= MultiCourse[k].size(); + factors.insert(MultiCourse[k].size()); // This is an over estimate. Should consider prime factors to get it exact + } + } + + legOrder.reserve(max); + for (int k = 0; k < max; k++) { + vector order; + long long hash = 0; + for (size_t j = 0; j< MultiCourse.size(); j++) { + if (!MultiCourse[j].empty()) { + int ix = k % MultiCourse[j].size(); + int cid = MultiCourse[j][ix]->getId(); + order.push_back(cid); + hash = hash * 997 + cid; + } + } + if (order.empty()) + continue; + + if (hashes.count(hash) == 0) { + hashes[hash] = legOrder.size(); + legOrder.push_back(order); + } + else { + int test = hashes[hash]; + if (legOrder[test] != order) { + // Test for hash collition. Will not happen... + bool exist = false; + for (size_t i = 0; i < legOrder.size(); i++) { + if (legOrder[i] == order) { + exist = true; + break; + } + } + if (!exist) { + legOrder.push_back(order); + } + } + } + } + + + for (oTeamList::const_iterator it = oe->Teams.begin(); it != oe->Teams.end(); ++it) { + if (it->skip() || it->Class != this) + continue; + vector order; + bool valid = true; + long long hash = 0; + for (size_t j = 0; j < it->Runners.size(); j++) { + pCourse crs; + if (it->Runners[j] && (crs = it->Runners[j]->getCourse(false)) != 0) { + if (it->Runners[j]->getNumShortening() > 0) { + valid = false; + break; + } + int cid = crs->getId(); + order.push_back(cid); + hash = hash * 997 + cid; + } + else { + valid = false; + break; + } + } + if (!valid) + continue; + if (hashes.count(hash) == 0) { + hashes[hash] = legOrder.size(); + legOrder.push_back(order); + } + else { + int test = hashes[hash]; + if (legOrder[test] != order) { + // Test for hash collition. Will not happen... + bool exist = false; + for (size_t i = 0; i < legOrder.size(); i++) { + if (legOrder[i] == order) { + exist = true; + break; + } + } + if (!exist) { + legOrder.push_back(order); + } + } + } + } + + vector< vector > controlOrder(legOrder.size()); + vector< map< pair, int > > countLegsPerFork(legOrder.size()); + + for(size_t k = 0; k < legOrder.size(); k++) { + for (size_t j = 0; j < legOrder[k].size(); j++) { + pCourse pc = oe->getCourse(legOrder[k][j]); + if (pc) { + controlOrder[k].push_back(-1); // Finish/start + for (int i = 0; i < pc->nControls; i++) { + int id = pc->Controls[i]->nNumbers == 1 ? pc->Controls[i]->Numbers[0] : pc->Controls[i]->getId(); + controlOrder[k].push_back(id); + } + } + } + if (controlOrder[k].size() > 0) + controlOrder[k].push_back(-1); // Finish + + for (size_t j = 1; j < controlOrder[k].size(); j++) { + int s = controlOrder[k][j-1]; + int e = controlOrder[k][j]; + ++countLegsPerFork[k][make_pair(s, e)]; + } + } + + unfairLegs.clear(); + for (size_t k = 1; k < countLegsPerFork.size(); k++) { + if (countLegsPerFork[0].size() >= countLegsPerFork[k].size()) + checkMissing(countLegsPerFork[0], countLegsPerFork[k], unfairLegs); + else + checkMissing(countLegsPerFork[k], countLegsPerFork[0], unfairLegs); + } + + forks = controlOrder; + + return unfairLegs.empty(); +} + +long long oClass::setupForkKey(const vector indices, const vector< vector< vector > > &courseKeys, vector &legs) { + size_t sr = 0; + int mergeIx[maxRunnersTeam]; + const vector *pCrs[maxRunnersTeam]; + int npar = indices.size(); + for (int k = 0; k < npar; k++) { + if (indices[k]>=0) { + pCrs[k] = &courseKeys[k][indices[k]]; + sr += pCrs[k]->size(); + } + else + pCrs[k] = 0; + + mergeIx[k] = 0; + } + if (legs.size() <= sr) + legs.resize(sr+1); + + + size_t nleg = 0; + while (nleg < sr) { + int best = -1; + for (int i = 0; i < npar; i++) { + if (!pCrs[i]) + continue; + int s = pCrs[i]->size(); + if (mergeIx[i] < s && (best == -1 || (*pCrs[i])[mergeIx[i]] < (*pCrs[best])[mergeIx[best]]) ) + best = i; + } + if (best == -1) + break; + legs[nleg++] = (*pCrs[best])[mergeIx[best]]; + ++mergeIx[best]; + } + + /*for (size_t k = 0; k < indices.size(); k++) { + if (indices[k]>=0) { + const vector &crs = courseKeys[k][indices[k]]; + for (size_t j = 0; j < crs.size(); j++) + legs[nleg++] = crs[j]; + //legs.insert(crs.begin(), crs.end()); + //vector tl; + //tl.resize(legs.size() + crs.size()); + //merge(legs.begin(), legs.end(), crs.begin(), crs.end(), tl.begin()); + //tl.swap(legs); + } + }*/ + + /*for (size_t k = 0; k < indices.size(); k++) { + if (indices[k]>=0) { + const vector &crs = courseKeys[k][indices[k]]; + //legs.insert(crs.begin(), crs.end()); + vector tl; + tl.resize(legs.size() + crs.size()); + merge(legs.begin(), legs.end(), crs.begin(), crs.end(), tl.begin()); + tl.swap(legs); + } + }*/ + unsigned long long key = 0; + for (size_t k = 0; k < nleg; k++) + key = key * 1057 + legs[k]; + + return key; +} + +pair oClass::autoForking(const vector< vector > &inputCourses) { + if (inputCourses.size() != getNumStages()) + throw meosException("Internal error"); + int legs = inputCourses.size(); + vector nf(legs); + vector prod(legs); + vector ix(legs); + vector< vector< vector > > courseKeys(legs); + vector< vector > pCourses(legs); + + unsigned long long N = 1; + for (int k = 0; k < legs; k++) { + prod[k] = N; + if (!inputCourses[k].empty()) { + N *= inputCourses[k].size(); + nf[k] = inputCourses[k].size(); + } + + // Setup course keys + courseKeys[k].resize(inputCourses[k].size()); + for (size_t j = 0; j < inputCourses[k].size(); j++) { + pCourse pc = oe->getCourse(inputCourses[k][j]); + pCourses[k].push_back(pc); + if (pc) { + for (int c = 0; c <= pc->getNumControls(); c++) { + int from = c == 0 ? 1 : pc->getControl(c-1)->getId(); + int to = c == pc->getNumControls() ? 2 : pc->getControl(c)->getId(); + int key = from + to*997; + courseKeys[k][j].push_back(key); + } + sort(courseKeys[k][j].begin(), courseKeys[k][j].end()); + } + } + } + + // Sample if there are very many combinations. + int sampleFactor = 1; + while(N > 10000000) { + sampleFactor *= 13; + N /= 13; + } + size_t Ns = size_t(N); + map count; + vector ws; + for (size_t k = 0; k < Ns; k ++) { + for (int j = 0; j < legs; j++) { + unsigned long long D = k * sampleFactor; + if (nf[j]>0) { + ix[j] = int((D/prod[j] + j) % nf[j]); + } + else ix[j] = -1; + } + unsigned long long key = setupForkKey(ix, courseKeys, ws); + ++count[key]; + } + + // Select the key generating best forking + long long keyToUse = -1; + int mv = 0; + for (map::iterator it = count.begin(); it != count.end(); ++it) { + if (it->second > mv) { + keyToUse = it->first; + mv = it->second; + } + } + count.clear(); + + // Clear old forking + for (int j = 0; j < legs; j++) { + if (nf[j]>0) { + clearStageCourses(j); + } + } + set coursesUsed; + set generatedForkKeys; + + vector< vector > courseMatrix(legs); + for (size_t k = 0; k < Ns; k++) { + long long forkKey = 0; + for (int j = 0; j < legs; j++) { + unsigned long long D = (k * 997)%Ns * sampleFactor; + if (nf[j]>0) { + ix[j] = int((D/prod[j] + j) % nf[j]); + forkKey = forkKey * 997 + ix[j]; + } + else ix[j] = -1; + } + unsigned long long key = setupForkKey(ix, courseKeys, ws); + if (key == keyToUse && generatedForkKeys.count(forkKey) == 0) { + generatedForkKeys.insert(forkKey); + for (int j = 0; j < legs; j++) { + if (nf[j] > 0) { + coursesUsed.insert(pCourses[j][ix[j]]->getId()); + courseMatrix[j].push_back(pCourses[j][ix[j]]); + //addStageCourse(j, pCourses[j][ix[j]]); + } + } + } + if (generatedForkKeys.size() > 200) + break; + } + vector fperm; + for (size_t j = 0; j < courseMatrix.size(); j++) { + if (courseMatrix[j].empty()) + continue; + + // Take the first used course. + fperm.resize(courseMatrix[j].size()); + for (size_t i = 0; i < fperm.size(); i++) + fperm[i] = i; + break; + } + permute(fperm); + + for (int j = 0; j < legs; j++) { + if (nf[j] > 0) { + for (size_t k = 0; k < courseMatrix[j].size(); k++) { + if (k < fperm.size()) { + addStageCourse(j, courseMatrix[j][fperm[k]]); + } + else { + addStageCourse(j, courseMatrix[j][k]); + } + } + } + } + + return make_pair(generatedForkKeys.size(), coursesUsed.size()); +} + +int oClass::extractBibPattern(const string &bibInfo, char pattern[32]) { + int number = 0; + + if (bibInfo.empty()) + pattern[0] = 0; + else { + number = 0; + int pIndex = 0; + bool hasNC = false; + + for (size_t j = 0; j < bibInfo.size() && j < 10; j++) { + if (bibInfo[j]>='0' && bibInfo[j]<='9') { + if (!hasNC) { + pattern[pIndex++] = '%'; + pattern[pIndex++] = 'd'; + hasNC = true; + } + number = 10 * number + bibInfo[j]-'0'; + } + else if (bibInfo[j] != '%' && bibInfo[j] > 32) + pattern[pIndex++] = bibInfo[j]; + } + if (!hasNC) { + pattern[pIndex++] = '%'; + pattern[pIndex++] = 'd'; + number = 1; + } + pattern[pIndex] = 0; + } + return number; +} + +AutoBibType oClass::getAutoBibType() const { + string bib = getDCI().getString("Bib"); + if (bib.empty()) // Manual + return AutoBibManual; + else if (bib == "*") // Consecutive + return AutoBibConsecutive; + else if (bib == "-") // No bib + return AutoBibNone; + else + return AutoBibExplicit; +} + +bool oClass::hasAnyCourse(const set &crsId) const { + if (Course && crsId.count(Course->getId())) + return true; + + for (size_t j = 0; j < MultiCourse.size(); j++) { + for (size_t k = 0; k < MultiCourse[j].size(); k++) { + if (MultiCourse[j][k] && crsId.count(MultiCourse[j][k]->getId())) + return true; + } + } + + return false; +} + +bool oClass::usesCourse(const oCourse &crs) const { + if (Course == &crs) + return true; + + for (size_t j = 0; j < MultiCourse.size(); j++) { + for (size_t k = 0; k < MultiCourse[j].size(); k++) { + if (MultiCourse[j][k] == &crs) + return true; + } + } + + return false; +} + +void oClass::extractBibPatterns(oEvent &oe, map > &patterns) { + vector t; + oe.getTeams(0, t, true); + vector r; + oe.getRunners(0, 0, r, true); + patterns.clear(); + char pattern[32]; + for (size_t k = t.size(); k > 0; k--) { + int cls = t[k-1]->getClassId(); + if (cls == 0) + continue; + const string &bib = t[k-1]->getBib(); + if (!bib.empty()) { + int num = extractBibPattern(bib, pattern); + if (num > 0) { + pair &val = patterns[cls]; + if (num > val.second) { + val.second = num; + val.first = pattern; + } + } + } + } + + for (size_t k = r.size(); k > 0; k--) { + if (r[k-1]->getTeam() != 0) + continue; + int cls = r[k-1]->getClassId(); + if (cls == 0) + continue; + const string &bib = r[k-1]->getBib(); + if (!bib.empty()) { + int num = extractBibPattern(bib, pattern); + if (num > 0) { + pair &val = patterns[cls]; + if (num < val.second) { + val.second = num; + val.first = pattern; + } + } + } + } +} + +pair oClass::getNextBib(map > &patterns) { + map >::iterator it = patterns.find(Id); + if (it != patterns.end() && it->second.second > 0) { + char bib[32]; + sprintf_s(bib, it->second.first.c_str(), ++it->second.second); + return make_pair(it->second.second, bib); + } + return make_pair(0, _EmptyString); +} + +pair oClass::getNextBib() { + vector t; + oe->getTeams(Id, t, true); + set bibs; + char pattern[32]; + + if (!t.empty()) { + for (size_t k = 0; k < t.size(); k++) { + const string &bib = t[k]->getBib(); + if (!bib.empty()) { + int num = extractBibPattern(bib, pattern); + if (num > 0) { + bibs.insert(num); + } + } + } + } + else { + vector r; + oe->getRunners(Id, 0, r, true); + + for (size_t k = 0; k < r.size(); k++) { + if (r[k]->getTeam() != 0) + continue; + const string &bib = r[k]->getBib(); + if (!bib.empty()) { + int num = extractBibPattern(bib, pattern); + if (num > 0) { + bibs.insert(num); + } + } + } + } + + if (bibs.empty()) + return make_pair(0, _EmptyString); + int candidate = -1; + for (set::iterator it = bibs.begin(); it != bibs.end(); ++it) { + if (candidate > 0 && *it != candidate) { + break; + } + candidate = *it + 1; + } + + char bib[32]; + sprintf_s(bib, pattern, candidate); + return make_pair(candidate, bib); +} + +int oClass::getNumForks() const { + set factors; + for (size_t k = 0; k < MultiCourse.size(); k++) { + int f = MultiCourse[k].size(); + if (f <= 1) + continue; + bool skip = false; + for (set::iterator it = factors.begin(); it != factors.end(); ++it) { + int of = *it; + if (of == f) { + skip = true; + break; + } + else if (f < of && (of % f) == 0) { + skip = true; + break; + } + else if (of < f && (f % of) == 0) { + factors.erase(it); + it = factors.begin(); + continue; + } + } + if (!skip) + factors.insert(f); + } + int res = 1; + for (set::iterator it = factors.begin(); it != factors.end(); ++it) { + res *= *it; + } + return res; +} + +void oClass::getSeedingMethods(vector< pair > &methods) { + methods.clear(); + methods.push_back(make_pair(lang.tl("Resultat"), SeedResult)); + methods.push_back(make_pair(lang.tl("Tid"), SeedTime)); + methods.push_back(make_pair(lang.tl("Ranking"), SeedRank)); + methods.push_back(make_pair(lang.tl("Poäng"), SeedPoints)); +} + +void oClass::drawSeeded(ClassSeedMethod seed, int leg, int firstStart, + int interval, const vector &groups, + bool noClubNb, bool reverseOrder, int pairSize) { + vector r; + oe->getRunners(Id, 0, r, true); + vector< pair > seedIx; + + for (size_t k = 0; k < r.size(); k++) { + if (r[k]->tLeg != leg) + continue; + + pair sx; + sx.second = k; + if (seed == SeedRank) + sx.first = r[k]->getRanking(); + else if (seed == SeedResult) + sx.first = ClassSplit::evaluateResult(*r[k]); + else if (seed == SeedTime) + sx.first = ClassSplit::evaluateTime(*r[k]); + else if (seed == SeedPoints) + sx.first = ClassSplit::evaluatePoints(*r[k]); + else + throw meosException("Not yet implemented"); + + seedIx.push_back(sx); + } + + sort(seedIx.begin(), seedIx.end()); + + if (seedIx.empty() || seedIx.front().first == seedIx.back().first) { + throw meosException("error:invalidmethod"); + } + + vector seedSpec; + if (groups.size() == 1) { + size_t added = 0; + if (groups[0] <= 0) + throw meosException("Internal error"); + while (added < seedIx.size()) { + seedSpec.push_back(groups[0]); + added += groups[0]; + } + } + else { + size_t added = 0; + for (size_t k = 0; k < groups.size(); k++) { + if (groups[k] <= 0) + throw meosException("Internal error"); + + seedSpec.push_back(groups[k]); + added += groups[k]; + } + if (added < seedIx.size()) + seedSpec.push_back(seedIx.size() - added); + } + + list< vector > seedGroups(1); + size_t groupIx = 0; + for (size_t k = 0; k < seedIx.size(); ) { + if (groupIx < seedSpec.size() && seedGroups.back().size() >= seedSpec[groupIx]) { + groupIx++; + seedGroups.push_back(vector()); + } + + int value = seedIx[k].first; + while (k < seedIx.size() && seedIx[k].first == value) { + seedGroups.back().push_back(seedIx[k].second); + k++; + } + } + + vector startOrder; + + for (list< vector >::iterator it = seedGroups.begin(); + it != seedGroups.end(); ++it) { + vector &g = *it; + permute(g); + for (size_t k = 0; k < g.size(); k++) { + startOrder.push_back(r[g[k]]); + } + } + + if (noClubNb) { + for (size_t k = 1; k < startOrder.size(); k++) { + int idMe = startOrder[k]->getClubId(); + if (idMe != 0 && idMe == startOrder[k-1]->getClubId()) { + // Make sure the runner with worst ranking is moved back. (Swedish SM rules) + if (startOrder[k-1]->getRanking() > startOrder[k]->getRanking()) + swap(startOrder[k-1], startOrder[k]); + + vector > rqueue; + rqueue.push_back(make_pair(k, startOrder[k])); + for (size_t j = k + 1; j < startOrder.size(); j++) { + if (idMe != startOrder[j]->getClubId()) { + swap(startOrder[j], startOrder[k]); // k-1 now has a non-club nb behind + rqueue.push_back(make_pair(j, pRunner(0))); + // Shift the queue + for (size_t q = 1; q < rqueue.size(); q++) { + startOrder[rqueue[q].first] = rqueue[q-1].second; + } + break; + } + else { + rqueue.push_back(make_pair(j, startOrder[j])); + } + + } + /*for (size_t j = k + 1; j < startOrder.size(); j++) { + swap(startOrder[j], startOrder[j-1]); + if (idMe != startOrder[j]->getClubId() && j+1 < startOrder.size() && + idMe != startOrder[j+1]->getClubId()) { + break; + } + }*/ + } + } + // Handle special case where the two last have same club. + int last = startOrder.size() - 1; + if (last >= 3) { + int lastClub = startOrder[last]->getClubId(); + if ( lastClub == startOrder[last-1]->getClubId() && + lastClub != startOrder[last-2]->getClubId() && + lastClub != startOrder[last-3]->getClubId() ) { + swap(startOrder[last-1], startOrder[last-2]); + } + } + } + + if (!reverseOrder) + reverse(startOrder.begin(), startOrder.end()); + + for (size_t k = 0; k < startOrder.size(); k++) { + int kx = k/pairSize; + startOrder[k]->setStartTime(firstStart + interval * kx, true, false, true); + startOrder[k]->synchronize(true); + } +} + +bool oClass::hasClassGlobalDependance() const { + for (size_t k = 0; k < legInfo.size(); k++) { + if (legInfo[k].startMethod == STHunting) + return true; + } + return false; +} + +int oClass::getDrawFirstStart() const { + return getDCI().getInt("FirstStart"); +} + +void oClass::setDrawFirstStart(int st) { + getDI().setInt("FirstStart", st); +} + +int oClass::getDrawInterval() const { + return getDCI().getInt("StartInterval"); +} + +void oClass::setDrawInterval(int st) { + getDI().setInt("StartInterval", st); +} + +int oClass::getDrawVacant() const { + return getDCI().getInt("Vacant"); +} + +void oClass::setDrawVacant(int st) { + getDI().setInt("Vacant", st); +} + +int oClass::getDrawNumReserved() const { + return getDCI().getInt("Reserved"); +} + +void oClass::setDrawNumReserved(int st) { + getDI().setInt("Reserved", st); +} + + +void oClass::initClassId(oEvent &oe) { + vector cls; + oe.getClasses(cls, true); + map id2Cls; + for (size_t k = 0; k < cls.size(); k++) { + long long extId = cls[k]->getExtIdentifier(); + if (extId > 0) { + if (id2Cls.count(extId)) { + throw meosException("Klasserna X och Y har samma externa id. Använd tabelläget för att ändra id.#" + + id2Cls[extId] + "#" + cls[k]->getName()); + } + id2Cls[extId] = cls[k]->getName(); + } + } + // Generate external identifiers when not set + for (size_t k = 0; k < cls.size(); k++) { + long long extId = cls[k]->getExtIdentifier(); + if (extId <= 0) { + long long id = cls[k]->getId(); + while (id2Cls.count(id)) { + id += 100000; + } + id2Cls[id] = cls[k]->getName(); + cls[k]->setExtIdentifier(id); + } + } +} + +int oClass::getNextBaseLeg(int leg) const { + for (size_t k = leg + 1; k < legInfo.size(); k++) { + if (!(legInfo[k].isParallel() || legInfo[k].isOptional())) + return k; + } + return -1; // No next leg +} + +int oClass::getPreceedingLeg(int leg) const { + for (int k = leg; k > 0; k--) { + if (!(legInfo[k].isParallel() || legInfo[k].isOptional())) + return k-1; + } + return -1; +} diff --git a/code/oClass.h b/code/oClass.h new file mode 100644 index 0000000..57b2513 --- /dev/null +++ b/code/oClass.h @@ -0,0 +1,571 @@ +// oClass.h: interface for the oClass class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OCLASS_H__63E948E3_3C06_4404_8E72_2185582FF30F__INCLUDED_) +#define AFX_OCLASS_H__63E948E3_3C06_4404_8E72_2185582FF30F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "oCourse.h" +#include +#include +#include +#include "inthashmap.h" +class oClass; +typedef oClass* pClass; +class oDataInterface; + +enum PersonSex; + +enum StartTypes { + STTime=0, + STChange, + STDrawn, + STHunting, + ST_max +}; +enum { nStartTypes = ST_max }; + +enum LegTypes { + LTNormal=0, + LTParallel, + LTExtra, + LTSum, + LTIgnore, + LTParallelOptional, + LTGroup, + LT_max, +}; +enum { nLegTypes = LT_max }; + + +enum BibMode { + BibSame, + BibAdd, + BibFree, + BibLeg, +}; + +enum AutoBibType { + AutoBibManual = 0, + AutoBibConsecutive = 1, + AutoBibNone = 2, + AutoBibExplicit = 3 +}; + +enum ClassSplitMethod { + SplitRandom, + SplitClub, + SplitRank, + SplitRankEven, + SplitResult, + SplitTime, + SplitResultEven, + SplitTimeEven, +}; + +enum ClassSeedMethod { + SeedRank, + SeedResult, + SeedTime, + SeedPoints +}; + +#ifdef DODECLARETYPESYMBOLS + const char *StartTypeNames[4]={"ST", "CH", "DR", "HU"}; + const char *LegTypeNames[7]={"NO", "PA", "EX", "SM", "IG", "PO", "GP"}; +#endif + +struct oLegInfo { + StartTypes startMethod; + LegTypes legMethod; + bool isParallel() const {return legMethod == LTParallel || legMethod == LTParallelOptional;} + bool isOptional() const {return legMethod == LTParallelOptional || legMethod == LTExtra || legMethod == LTIgnore;} + //Interpreteation depends. Can be starttime/first start + //or number of earlier legs to consider. + int legStartData; + int legRestartTime; + int legRopeTime; + int duplicateRunner; + + // Transient, deducable data + int trueSubLeg; + int trueLeg; + string displayLeg; + + oLegInfo():startMethod(STTime), legMethod(LTNormal), legStartData(0), + legRestartTime(0), legRopeTime(0), duplicateRunner(-1) {} + string codeLegMethod() const; + void importLegMethod(const string &courses); +}; + +struct ClassResultInfo { + ClassResultInfo() : nUnknown(0), nFinished(0), lastStartTime(0) {} + + int nUnknown; + int nFinished; + int lastStartTime; +}; + + +enum ClassType {oClassIndividual=1, oClassPatrol=2, + oClassRelay=3, oClassIndividRelay=4}; + +enum ClassMetaType {ctElite, ctNormal, ctYouth, ctTraining, + ctExercise, ctOpen, ctUnknown}; + +class Table; +class oClass : public oBase +{ +public: + enum ClassStatus {Normal, Invalid, InvalidRefund}; + + static void getSplitMethods(vector< pair > &methods); + static void getSeedingMethods(vector< pair > &methods); + +protected: + string Name; + pCourse Course; + + vector< vector > MultiCourse; + vector< oLegInfo > legInfo; + + //First: best time on leg + //Second: Total leader time (total leader) + struct LeaderInfo { + LeaderInfo() {bestTimeOnLeg = 0; totalLeaderTime = 0; inputTime = 0; totalLeaderTimeInput = 0;} + void reset() {bestTimeOnLeg = 0; totalLeaderTime = 0; inputTime = 0; totalLeaderTimeInput = 0;} + int bestTimeOnLeg; + int totalLeaderTime; + int totalLeaderTimeInput; //Team total including input + int inputTime; + }; + + vector tLeaderTime; + map tBestTimePerCourse; + + int tSplitRevision; + map > tSplitAnalysisData; + map > tCourseLegLeaderTime; + map > tCourseAccLegLeaderTime; + mutable vector tFirstStart; + mutable vector tLastStart; + + mutable ClassStatus tStatus; + mutable int tStatusRevision; + + // A map with places for given times on given legs + inthashmap *tLegTimeToPlace; + inthashmap *tLegAccTimeToPlace; + + void insertLegPlace(int from, int to, int time, int place); + void insertAccLegPlace(int courseId, int controlNo, int time, int place); + + // For sub split times + int tLegLeaderTime; + mutable int tNoTiming; + mutable int tIgnoreStartPunch; + + // Sort classes for this index + int tSortIndex; + int tMaxTime; + + // True when courses was changed on this client. Used to update course pool bindings + bool tCoursesChanged; + + // Used to force show of full multi course dialog + bool tShowMultiDialog; + + static const int dataSize = 256; + int getDISize() const {return dataSize;} + + BYTE oData[256]; + BYTE oDataOld[256]; + + //Multicourse data + string codeMultiCourse() const; + //Fill courseId with id:s of used courses. + void importCourses(const vector< vector > &multi); + static void parseCourses(const string &courses, vector< vector > &multi, set &courseId); + set &getMCourseIdSet(set &in) const; + + //Multicourse leg methods + string codeLegMethod() const; + void importLegMethod(const string &courses); + + //bool sqlChanged; + /** Pairs of changed entities. (Leg number, control id (or PunchFinish)) + (-1,-1) means all (leg, -1) means all on leg. + */ + map< int, set > sqlChangedControlLeg; + map< int, set > sqlChangedLegControl; + + void markSQLChanged(int leg, int control); + + void addTableRow(Table &table) const; + bool inputData(int id, const string &input, int inputId, + string &output, bool noUpdate); + + void fillInput(int id, vector< pair > &elements, size_t &selected); + + void exportIOFStart(xmlparser &xml); + + /** Setup transient data */ + void reinitialize(); + + /** Recalculate derived data */ + void apply(); + + void calculateSplits(); + void clearSplitAnalysis(); + + /** Info about the result in the class for each leg. + Use oEvent::analyseClassResultStatus to setup */ + mutable vector tResultInfo; + + /** Get/calculate sort index from candidate */ + int getSortIndex(int candidate); + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + void changedObject(); + + static long long setupForkKey(const vector indices, const vector< vector< vector > > &courseKeys, vector &ws); + +public: + + static void initClassId(oEvent &oe); + + // Draw data + int getDrawFirstStart() const; + void setDrawFirstStart(int st); + int getDrawInterval() const; + void setDrawInterval(int st); + int getDrawVacant() const; + void setDrawVacant(int st); + int getDrawNumReserved() const; + void setDrawNumReserved(int st); + + /** Return an actual linear index for this class. */ + int getLinearIndex(int index, bool isLinear) const; + + /** Split class into subclasses. */ + void splitClass(ClassSplitMethod method, const vector &parts, vector &outClassId); + void mergeClass(int classIdSec); + + void drawSeeded(ClassSeedMethod seed, int leg, int firstStart, int interval, const vector &groups, + bool noClubNb, bool reverse, int pairSize); + /** Returns true if the class is setup so that changeing one runner can effect all others. (Pursuit)*/ + bool hasClassGlobalDependance() const; + // Autoassign new bibs + static void extractBibPatterns(oEvent &oe, map > &patterns); + pair getNextBib(map > &patterns); // Version that calculates next free bib from cached data (fast, no gap usage) + pair oClass::getNextBib(); // Version that calculates next free bib (slow, but reuses gaps) + + bool usesCourse(const oCourse &crs) const; + + /** Returns an (overestimate) of the actual number of forks.*/ + int getNumForks() const; + + bool checkStartMethod(); + + static int extractBibPattern(const string &bibInfo, char pattern[32]); + + bool isParallel(size_t leg) const { + if (leg < legInfo.size()) + return legInfo[leg].isParallel(); + else + return false; + } + + bool isOptional(size_t leg) const { + if (leg < legInfo.size()) + return legInfo[leg].isOptional(); + else + return false; + } + + ClassStatus getClassStatus() const; + + ClassMetaType interpretClassType() const; + + int getMaximumRunnerTime() const; + + void remove(); + bool canRemove() const; + + void forceShowMultiDialog(bool force) {tShowMultiDialog = force;} + + /// Return first and last start of runners in class + void getStartRange(int leg, int &firstStart, int &lastStart) const; + + /** Return true if pure rogaining class, with time limit (sort results by points) */ + bool isRogaining() const; + + /** Get the place for the specified leg (CommonControl of course == start/finish) and time. 0 if not found */ + int getLegPlace(int from, int to, int time) const; + + /** Get accumulated leg place */ + int getAccLegPlace(int courseId, int controlNo, int time) const; + + /** Get cached sort index */ + int getSortIndex() const {return tSortIndex;}; + + /// Guess type from class name + void assignTypeFromName(); + + bool isSingleRunnerMultiStage() const; + + bool wasSQLChanged(int leg, int control) const;// {return sqlChanged;} + + void getStatistics(const set &feeLock, int &entries, int &started) const; + + int getBestInputTime(int leg) const; + int getBestLegTime(int leg) const; + int getBestTimeCourse(int courseId) const; + + int getTotalLegLeaderTime(int leg, bool includeInput) const; + + string getInfo() const; + // Returns true if the class has a pool of courses + bool hasCoursePool() const; + // Set whether to use a pool or not + void setCoursePool(bool p); + // Get the best matching course from a pool + pCourse selectCourseFromPool(int leg, const SICard &card) const; + // Update changed course pool + void updateChangedCoursePool(); + + void resetLeaderTime(); + + ClassType getClassType() const; + + bool startdataIgnored(int i) const; + bool restartIgnored(int i) const; + + StartTypes getStartType(int leg) const; + LegTypes getLegType(int leg) const; + int getStartData(int leg) const; + int getRestartTime(int leg) const; + int getRopeTime(int leg) const; + string getStartDataS(int leg) const; + string getRestartTimeS(int leg) const; + string getRopeTimeS(int leg) const; + + // Get the index of the base leg for this leg (=first race of leg's runner) + int getLegRunner(int leg) const; + // Get the index of this leg for its runner. + int getLegRunnerIndex(int leg) const; + // Set the runner index for the specified leg. (Used when several legs are run be the same person) + void setLegRunner(int leg, int runnerNo); + + // Get number of races run by the runner of given leg + int getNumMultiRunners(int leg) const; + + // Get number of legs, not counting parallel legs + int getNumLegNoParallel() const; + + // Split a linear leg index into non-parallel leg number and order + // number on the leg (zero-indexed). Returns true if the legNumber is parallel + bool splitLegNumberParallel(int leg, int &legNumber, int &legOrder) const; + + // The inverse of splitLegNumberParallel. Return -1 on invalid input. + int getLegNumberLinear(int legNumber, int legOrder) const; + + //Get the number of parallel runners on a given leg (before and after) + int getNumParallel(int leg) const; + + // Get the linear leg number of the next (non-parallel with this) leg + int getNextBaseLeg(int leg) const; + + // Get the linear leg number of the preceeding leg + int getPreceedingLeg(int leg) const; + + /// Get a string 1, 2a, etc describing the number of the leg + string getLegNumber(int leg) const; + + // Return the number of distinct runners for one + // "team" in this class. + int getNumDistinctRunners() const; + + // Return the minimal number of runners in team + int getNumDistinctRunnersMinimal() const; + void setStartType(int leg, StartTypes st, bool noThrow); + void setLegType(int leg, LegTypes lt); + + bool setStartData(int leg, const string &s); + bool setStartData(int leg, int value); + + void setRestartTime(int leg, const string &t); + void setRopeTime(int leg, const string &t); + + void setNoTiming(bool noResult); + bool getNoTiming() const; + + void setIgnoreStartPunch(bool ignoreStartPunch); + bool ignoreStartPunch() const; + + void setFreeStart(bool freeStart); + bool hasFreeStart() const; + + void setDirectResult(bool directResult); + bool hasDirectResult() const; + + + string getClassResultStatus() const; + + bool isCourseUsed(int Id) const; + string getLength(int leg) const; + + // True if the multicourse structure is in use + bool hasMultiCourse() const {return MultiCourse.size()>0;} + + // True if there is a true multicourse usage. + bool hasTrueMultiCourse() const; + + unsigned getNumStages() const {return MultiCourse.size();} + /** Get the set of true legs, identifying parallell legs etc. Returns indecs into + legInfo of the last leg of the true leg (first), and true leg (second).*/ + struct TrueLegInfo { + protected: + TrueLegInfo(int first_, int second_) : first(first_), second(second_) {} + friend class oClass; + public: + int first; + int second; + int nonOptional; // Index of a leg with a non-optional runner of that leg (which e.g. defines the course) + }; + + void getTrueStages(vector &stages) const; + + unsigned getLastStageIndex() const {return max(MultiCourse.size(), 1)-1;} + + void setNumStages(int no); + + bool operator<(const oClass &b){return tSortIndex &courses) const; + + pCourse getCourse(int leg, unsigned fork=0, bool getSampleFromRunner = false) const; + int getCourseId() const {if (Course) return Course->getId(); else return 0;} + void setCourse(pCourse c); + + bool addStageCourse(int stage, int courseId); + bool addStageCourse(int stage, pCourse pc); + void clearStageCourses(int stage); + + bool removeStageCourse(int stage, int courseId, int position); + + void getAgeLimit(int &low, int &high) const; + void setAgeLimit(int low, int high); + + int getExpectedAge() const; + + PersonSex getSex() const; + void setSex(PersonSex sex); + + string getStart() const; + void setStart(const string &start); + + int getBlock() const; + void setBlock(int block); + + bool getAllowQuickEntry() const; + void setAllowQuickEntry(bool quick); + + AutoBibType getAutoBibType() const; + BibMode getBibMode() const; + void setBibMode(BibMode bibMode); + + string getType() const; + void setType(const string &type); + + // Get class default fee from competition, depending on type(?) + // a non-zero fee is changed only if resetFee is true + void addClassDefaultFee(bool resetFee); + + // Get entry fee depending on date and age + int getEntryFee(const string &date, int age) const; + + // Clear cached data + void clearCache(bool recalculate); + + // Check if forking is fair + bool checkForking(vector< vector > &legOrder, + vector< vector > &forks, + set< pair > &unfairLegs) const; + + // Automatically setup forkings using the specified courses. + // Returns + pair autoForking(const vector< vector > &inputCourses); + + bool hasUnorderedLegs() const; + void setUnorderedLegs(bool order); + void getParallelCourseGroup(int leg, int startNo, vector< pair > &group) const; + // Returns 0 for no parallel selection (= normal mode) + pCourse selectParallelCourse(const oRunner &r, const SICard &sic); + + void getParallelRange(int leg, int &parLegRangeMin, int &parLegRangeMax) const; + + bool hasAnyCourse(const set &crsId) const; + + oClass(oEvent *poe); + oClass(oEvent *poe, int id); + virtual ~oClass(); + + friend class oAbstractRunner; + friend class oEvent; + friend class oRunner; + friend class oTeam; + friend class MeosSQL; + friend class TabSpeaker; +}; + +#endif // !defined(AFX_OCLASS_H__63E948E3_3C06_4404_8E72_2185582FF30F__INCLUDED_) diff --git a/code/oClub.cpp b/code/oClub.cpp new file mode 100644 index 0000000..5535d50 --- /dev/null +++ b/code/oClub.cpp @@ -0,0 +1,1152 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oClub.cpp: implementation of the oClub class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "oClub.h" +#include "meos_util.h" + +#include "oEvent.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "RunnerDB.h" +#include +#include "Table.h" +#include "localizer.h" +#include "pdfwriter.h" + +#include "intkeymapimpl.hpp" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +oClub::oClub(oEvent *poe): oBase(poe) +{ + getDI().initData(); + Id=oe->getFreeClubId(); +} + +oClub::oClub(oEvent *poe, int id): oBase(poe) +{ + getDI().initData(); + Id=id; + if (id != cVacantId) + oe->qFreeClubId = max(id, oe->qFreeClubId); +} + + +oClub::~oClub() +{ + +} + +bool oClub::write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Club"); + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.write("Name", name); + for (size_t k=0;kis("Id")){ + Id=it->getInt(); + } + else if (it->is("Name")){ + internalSetName(it->get()); + } + else if (it->is("oData")){ + getDI().set(*it); + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + else if (it->is("AltName")) { + altNames.push_back(it->get()); + } + } +} + +void oClub::internalSetName(const string &n) +{ + if (name != n) { + name = n; + const char *bf = name.c_str(); + int len = name.length(); + int ix = -1; + for (int k=0;k <= len-9; k++) { + if (bf[k] == 'S') { + if (strcmp(bf+k, "Skid o OK")==0) { + ix = k; + break; + } + if (strcmp(bf+k, "Skid o OL")==0) { + ix = k; + break; + } + } + } + if (ix >= 0) { + tPrettyName = name; + if (strcmp(bf+ix, "Skid o OK")==0) + tPrettyName.replace(ix, 9, "SOK", 3); + else if (strcmp(bf+ix, "Skid o OL")==0) + tPrettyName.replace(ix, 9, "SOL", 3); + } + } +} + +void oClub::setName(const string &n) +{ + if (n != name) { + internalSetName(n); + updateChanged(); + } +} + +oDataContainer &oClub::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = 0; + return *oe->oClubData; +} + +pClub oEvent::getClub(int Id) const +{ + if (Id<=0) + return 0; + + //map::const_iterator mit=clubIdIndex.find(Id); + //if (mit!=clubIdIndex.end()) + // return mit->second; + + pClub value; + if (clubIdIndex.lookup(Id, value)) + return value; + return 0; +} + +pClub oEvent::getClub(const string &pname) const +{ + oClubList::const_iterator it; + + for (it=Clubs.begin(); it != Clubs.end(); ++it) + if (it->name==pname) + return pClub(&*it); + + return 0; +} + +pClub oEvent::getClubCreate(int Id, const string &CreateName) +{ + if (Id > 0) { + //map::iterator mit=clubIdIndex.find(Id); + //if (mit!=clubIdIndex.end()) { + pClub value; + if (clubIdIndex.lookup(Id, value)) { + if (!trim(CreateName).empty() && _stricmp(value->getName().c_str(), trim(CreateName).c_str())!=0) + Id = 0; //Bad, used Id. + if (trim(CreateName).empty() || Id>0) + return value; + } + } + if (CreateName.empty()) { + //Not found. Auto add... + return getClubCreate(Id, lang.tl("Klubblös")); + } + else { + oClubList::iterator it; + string tname = trim(CreateName); + + //Maybe club exist under different ID + for (it=Clubs.begin(); it != Clubs.end(); ++it) + if (_stricmp(it->name.c_str(), tname.c_str())==0) + return &*it; + + //Else, create club. + return addClub(tname, Id); + } +} + +pClub oEvent::addClub(const string &pname, int createId) +{ + if (createId>0) { + pClub pc = getClub(createId); + if (pc) + return pc; + } + + pClub dbClub = oe->useRunnerDb() ? oe->runnerDB->getClub(pname) : 0; + + if (dbClub) { + if (dbClub->getName() != pname) { + pClub pc = getClub(dbClub->getName()); + if (pc) + return pc; + } + + if (createId<=0) + if (getClub(dbClub->Id)) + createId = getFreeClubId(); //We found a db club, but Id is taken. + else + createId = dbClub->Id; + + oClub c(this, createId); + c = *dbClub; + c.Id = createId; + Clubs.push_back(c); + } + else { + if (createId==0) + createId = getFreeClubId(); + + oClub c(this, createId); + c.setName(pname); + Clubs.push_back(c); + } + Clubs.back().synchronize(); + clubIdIndex[Clubs.back().Id]=&Clubs.back(); + return &Clubs.back(); +} + +pClub oEvent::addClub(const oClub &oc) +{ + if (clubIdIndex.count(oc.Id)!=0) + return clubIdIndex[oc.Id]; + + Clubs.push_back(oc); + if (!oc.existInDB()) + Clubs.back().synchronize(); + + clubIdIndex[Clubs.back().Id]=&Clubs.back(); + return &Clubs.back(); +} + +void oEvent::fillClubs(gdioutput &gdi, const string &id) +{ + vector< pair > d; + oe->fillClubs(d); + gdi.addItem(id, d); +} + + +const vector< pair > & oEvent::fillClubs(vector< pair > &out) +{ + out.clear(); + //gdi.clearList(name); + synchronizeList(oLClubId); + Clubs.sort(); + + oClubList::iterator it; + + for (it=Clubs.begin(); it != Clubs.end(); ++it){ + if (!it->Removed) + out.push_back(make_pair(it->name, it->Id)); + //gdi.addItem(name, it->name, it->Id); + } + + return out; +} + +void oClub::buildTableCol(oEvent *oe, Table *table) { + oe->oClubData->buildTableCol(table); +} + +#define TB_CLUBS "clubs" +Table *oEvent::getClubsTB()//Table mode +{ + if (tables.count("club") == 0) { + Table *table=new Table(this, 20, "Klubbar", TB_CLUBS); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 200, false); + oe->oClubData->buildTableCol(table); + + table->addColumn("Deltagare", 70, true); + table->addColumn("Avgift", 70, true); + table->addColumn("Betalat", 70, true); + + tables["club"] = table; + table->addOwnership(); + } + + tables["club"]->update(); + return tables["club"]; + +} + +void oEvent::generateClubTableData(Table &table, oClub *addClub) +{ + oe->setupClubInfoData(); + if (addClub) { + addClub->addTableRow(table); + return; + } + synchronizeList(oLClubId); + oClubList::iterator it; + + for (it=Clubs.begin(); it != Clubs.end(); ++it){ + if (!it->isRemoved()){ + it->addTableRow(table); + } + } +} + +int oClub::getTableId() const { + return Id; +} + +void oClub::addTableRow(Table &table) const { + table.addRow(getTableId(), pClass(this)); + + bool dbClub = table.getInternalName() != TB_CLUBS; + bool canEdit = dbClub ? !oe->isClient() : true; + + pClub it = pClub(this); + int row = 0; + table.set(row++, *it, TID_ID, itos(getId()), false); + table.set(row++, *it, TID_MODIFIED, getTimeStamp(), false); + + table.set(row++, *it, TID_CLUB, getName(), canEdit); + row = oe->oClubData->fillTableCol(*this, table, canEdit); + + if (!dbClub) { + table.set(row++, *it, TID_NUM, itos(tNumRunners), false); + table.set(row++, *it, TID_FEE, oe->formatCurrency(tFee), false); + table.set(row++, *it, TID_PAID, oe->formatCurrency(tPaid), false); + } +} + +bool oClub::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + synchronize(false); + + if (id>1000) { + return oe->oClubData->inputData(this, id, input, inputId, output, noUpdate); + } + + switch(id) { + case TID_CLUB: + setName(input); + synchronize(); + output=getName(); + return true; + break; + } + + return false; +} + +void oClub::fillInput(int id, vector< pair > &out, size_t &selected) +{ + if (id>1000) { + oe->oClubData->fillInput(oData, id, 0, out, selected); + return; + } +} + +void oEvent::mergeClub(int clubIdPri, int clubIdSec) +{ + if (clubIdPri==clubIdSec) + return; + + pClub pc = getClub(clubIdPri); + if (!pc) + return; + + // Update teams + for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) { + if (it->getClubId() == clubIdSec) { + it->Club = pc; + it->updateChanged(); + it->synchronize(); + } + } + + // Update runners + for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { + if (it->getClubId() == clubIdSec) { + it->Club = pc; + it->updateChanged(); + it->synchronize(); + } + } + oe->removeClub(clubIdSec); +} + +void oEvent::getClubs(vector &c, bool sort) { + if (sort) { + synchronizeList(oLClubId); + Clubs.sort(); + } + c.clear(); + c.reserve(Clubs.size()); + + for (oClubList::iterator it = Clubs.begin(); it != Clubs.end(); ++it) { + if (!it->isRemoved()) + c.push_back(&*it); + } +} + + +void oEvent::viewClubMembers(gdioutput &gdi, int clubId) +{ + sortRunners(ClassStartTime); + sortTeams(ClassStartTime, 0, true); + + gdi.fillDown(); + gdi.dropLine(); + int nr = 0; + int nt = 0; + // Update teams + for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) { + if (it->getClubId() == clubId) { + if (nt==0) + gdi.addString("", 1, "Lag(flera)"); + gdi.addStringUT(0, it->getName() + ", " + it->getClass() ); + nt++; + } + } + + gdi.dropLine(); + // Update runners + for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { + if (it->getClubId() == clubId) { + if (nr==0) + gdi.addString("", 1, "Löpare:"); + gdi.addStringUT(0, it->getName() + ", " + it->getClass() ); + nr++; + } + } +} + +void oClub::addInvoiceLine(gdioutput &gdi, const InvoiceLine &line, InvoiceData &data) const { + int &yp = data.yp; + for (size_t k = 0; k < line.xposAndString.size(); k++) { + const pair > &entry = line.xposAndString[k]; + int xp = entry.first; + bool right = entry.second.first; + const string &str = entry.second.second; + if (right) + gdi.addStringUT(yp, xp, normalText|textRight, str); + else + gdi.addStringUT(yp, xp, normalText, str); + } + + data.total_fee_amount += line.fee; + data.total_rent_amount += line.rent; + data.total_paid_amount += line.paid; + if (line.paid > 0) + data.paidPerMode[line.payMode] += line.paid; + yp += data.lh; +} + +void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam, + const map &definedPayModes, + const InvoiceData &data, + list &lines) const { + int xs = data.xs; + lines.push_back(InvoiceLine()); + InvoiceLine &line = lines.back(); + + if (r->getTeam() && !inTeam && !r->isPatrolMember()) + line.addString(xs, r->getName() + " (" + r->getTeam()->getName() + ")"); + else + line.addString(xs + (inTeam ? 10 : 0), r->getName()); + + string ts; + if (!inTeam) + line.addString(xs+data.clsPos, r->getClass()); + + if (r->getStatus() == StatusUnknown) + ts = "-"; + else if (!data.multiDay) { + if (r->getStatus()==StatusOK) { + ClassType type = oClassIndividual; + cTeam t = r->getTeam(); + if (t && r->getClassRef()) + type = r->getClassRef()->getClassType(); + + if (type == oClassIndividRelay || type == oClassRelay) { + int leg = r->getLegNumber(); + if (t->getLegStatus(leg, false) == StatusOK) + ts = t->getLegPlaceS(leg, false)+ " (" + r->getRunningTimeS() + ")"; + else + ts = t->getLegStatusS(leg, false)+ " (" + r->getRunningTimeS() + ")"; + } + else + ts = r->getPrintPlaceS(true)+ " (" + r->getRunningTimeS() + ")"; + } + else + ts = r->getStatusS(); + } + else { + if (r->getTotalStatus()==StatusOK) { + ts = r->getPrintTotalPlaceS(true)+ " (" + r->getTotalRunningTimeS() + ")"; + } + else if (r->getTotalStatus()!=StatusNotCompetiting) + ts = r->getStatusS(); + else { + ts = r->getInputStatusS(); + } + } + + int fee = r->getDCI().getInt("Fee"); + int card = r->getDCI().getInt("CardFee"); + int paid = r->getDCI().getInt("Paid"); + int pm = r->getPaymentMode(); + + /*string payMode = ""; + map::const_iterator res = definedPayModes.find(pm); + if (res != definedPayModes.end()) + payMode = ", " + res->second; + */ + if (r->getClassRef() && r->getClassRef()->getClassStatus() == oClass::InvalidRefund) { + fee = 0; + card = 0; + } + + if (fee>0) + line.addString(xs+data.feePos, oe->formatCurrency(fee), true); + if (card > 0) + line.addString(xs+data.cardPos, oe->formatCurrency(card), true); + if (paid>0) + line.addString(xs+data.paidPos, oe->formatCurrency(paid), true); + line.fee= fee; + if (card > 0) + line.rent = card; + line.paid = paid; + line.payMode = pm; + line.addString(xs+data.resPos, ts); +} + +void oClub::addTeamInvoiceLine(const pTeam t, const map &definedPayModes, + const InvoiceData &data, list &lines) const { + lines.push_back(InvoiceLine()); + InvoiceLine &line = lines.back(); + + int xs = data.xs; + + int fee = t->getDCI().getInt("Fee"); + int paid = t->getDCI().getInt("Paid"); + + if (fee <= 0) + return; + + line.addString(xs, t->getName()); + line.addString(xs+data.clsPos, t->getClass()); + string ts; + + if (t->getStatus() == StatusUnknown) + ts = "-"; + else { + if (t->getStatus()==StatusOK) { + ts = t->getPrintPlaceS(true)+ " (" + t->getRunningTimeS() + ")"; + } + else + ts = t->getStatusS(); + } + + + if (t->getClassRef() && t->getClassRef()->getClassStatus() == oClass::InvalidRefund) { + fee = 0; + } + + line.addString(xs+data.feePos, oe->formatCurrency(fee), true); + line.addString(xs+data.paidPos, oe->formatCurrency(paid), true); + line.fee = fee; + line.paid = paid; + line.payMode = t->getPaymentMode(); + line.addString(xs+data.resPos, ts); + + for (int j = 0; j < t->getNumRunners(); j++) { + pRunner r = t->getRunner(j); + if (r && r->getClubId() == t->getClubId()) { + addRunnerInvoiceLine(r, true, definedPayModes, data, lines); + } + } +} + +void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid, + const map &definedPayModes, + map &paidPerMode) { + string account = oe->getDI().getString("Account"); + string pdate = oe->getDI().getDate("PaymentDue"); + int pdateI = oe->getDI().getInt("PaymentDue"); + string organizer = oe->getDI().getString("Organizer"); + int number = getDCI().getInt("InvoiceNo"); + if (number == 0) { + assignInvoiceNumber(*oe, false); + number = getDCI().getInt("InvoiceNo"); + } + gdi.fillDown(); + + if (account.empty()) + gdi.addString("", 0, "Varning: Inget kontonummer angivet (Se tävlingsinställningar).").setColor(colorRed); + + if (pdateI == 0) + gdi.addString("", 0, "Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar).").setColor(colorRed); + + if (organizer.empty()) + gdi.addString("", 0, "Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar).").setColor(colorRed); + + vector runners; + oe->getClubRunners(getId(), runners); + vector teams; + oe->getClubTeams(getId(), teams); + + toPay = 0; + hasPaid = 0; + + if (runners.empty() && teams.empty()) + return; + + int ys = gdi.getCY(); + int lh = gdi.getLineHeight(); + + InvoiceData data(lh); + + data.xs = 30; + const int &xs = data.xs; + data.adrPos = gdi.scaleLength(350); + data.clsPos = gdi.scaleLength(270); + + data.feePos = gdi.scaleLength(390); + data.cardPos = gdi.scaleLength(440); + data.paidPos = gdi.scaleLength(490); + data.resPos = gdi.scaleLength(550); + + gdi.addString("", ys, xs+data.adrPos, boldHuge, "FAKTURA"); + if (number>0) + gdi.addStringUT(ys+lh*3, xs+data.adrPos, fontMedium, lang.tl("Faktura nr")+ ": " + itos(number)); + int &yp = data.yp; + + yp = ys+lh; + string ostreet = oe->getDI().getString("Street"); + string oaddress = oe->getDI().getString("Address"); + string oco = oe->getDI().getString("CareOf"); + + if (!organizer.empty()) + gdi.addStringUT(yp, xs, fontMedium, organizer), yp+=lh; + if (!oco.empty()) + gdi.addStringUT(yp, xs, fontMedium, oco), yp+=lh; + if (!ostreet.empty()) + gdi.addStringUT(yp, xs, fontMedium, ostreet), yp+=lh; + if (!oaddress.empty()) + gdi.addStringUT(yp, xs, fontMedium, oaddress), yp+=lh; + + yp+=lh; + + gdi.addStringUT(yp, xs, fontLarge, oe->getName()); + gdi.addStringUT(yp+lh*2, xs, fontMedium, oe->getDate()); + + string co = getDCI().getString("CareOf"); + string address = getDCI().getString("Street"); + string city = getDCI().getString("ZIP") + " " + getDCI().getString("City"); + string country = getDCI().getString("Country"); + + int ayp = ys + 122; + + const int absX = oe->getPropertyInt("addressxpos", 125); + int absY = oe->getPropertyInt("addressypos", 50); + + const int absYL = 5; + gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, getName()).setAbsPrintPos(absX,absY); + ayp+=lh; + absY+=absYL; + + if (!co.empty()) + gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, co).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; + + if (!address.empty()) + gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, address).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; + + if (!city.empty()) + gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, city).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; + + if (!country.empty()) + gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, country).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; + + yp = ayp+30; + + gdi.addString("", yp, xs, boldSmall, "Deltagare"); + gdi.addString("", yp, xs+data.clsPos, boldSmall, "Klass"); + + gdi.addString("", yp, xs+data.feePos, boldSmall|textRight, "Avgift"); + gdi.addString("", yp, xs+data.cardPos, boldSmall|textRight, "Brickhyra"); + gdi.addString("", yp, xs+data.paidPos, boldSmall|textRight, "Betalat"); + + gdi.addString("", yp, xs+data.resPos, boldSmall, "Resultat"); + + yp += lh; + data.multiDay = oe->hasPrevStage(); + + list lines; + for (size_t k=0;kgetTeam(); + if (team && team->getDCI().getInt("Fee") > 0 + && team->getClubId() == runners[k]->getClubId()) + continue; // Show this line under the team. + addRunnerInvoiceLine(runners[k], false, definedPayModes, data, lines); + } + + for (size_t k=0;k::iterator it = lines.begin(); it != lines.end(); ++it) { + addInvoiceLine(gdi, *it, data); + } + + yp += lh; + gdi.addStringUT(yp, xs+data.feePos, boldText|textRight, oe->formatCurrency(data.total_fee_amount)); + gdi.addStringUT(yp, xs+data.cardPos, boldText|textRight, oe->formatCurrency(data.total_rent_amount)); + gdi.addStringUT(yp, xs+data.paidPos, boldText|textRight, oe->formatCurrency(data.total_paid_amount)); + + yp+=lh*2; + toPay = data.total_fee_amount+data.total_rent_amount-data.total_paid_amount; + hasPaid = data.total_paid_amount; + for (map::iterator it = data.paidPerMode.begin(); it != data.paidPerMode.end(); ++it) { + paidPerMode[it->first] += it->second; + } + gdi.addString("", yp, xs, boldText, "Att betala: X#" + oe->formatCurrency(toPay)); + + gdi.updatePos(gdi.scaleLength(710),0,0,0); + + yp+=lh*2; + + gdi.addStringUT(yp, xs, normalText, lang.tl("Vänligen betala senast") + + " " + pdate + " " + lang.tl("till") + " " + account + "."); + gdi.dropLine(2); + //gdi.addStringUT(gdi.getCY()-1, 1, pageNewPage, blank, 0, 0); + + vector< pair > mlines; + oe->getExtraLines("IVExtra", mlines); + for (size_t k = 0; k < mlines.size(); k++) { + gdi.addStringUT(mlines[k].second, mlines[k].first); + } + if (mlines.size()>0) + gdi.dropLine(0.5); + + gdi.addStringUT(gdi.getCY()-1, xs, pageNewPage, "", 0, 0).setExtra(START_YP); + gdi.dropLine(); +} + +void oEvent::getClubRunners(int clubId, vector &runners) const +{ + oRunnerList::const_iterator rit; + runners.clear(); + + for (rit=Runners.begin(); rit != Runners.end(); ++rit) { + if (!rit->skip() && rit->getClubId() == clubId) + runners.push_back(pRunner(&*rit)); + } +} + +void oEvent::getClubTeams(int clubId, vector &teams) const +{ + oTeamList::const_iterator rit; + teams.clear(); + + for (rit=Teams.begin(); rit != Teams.end(); ++rit) { + if (!rit->skip() && rit->getClubId() == clubId) + teams.push_back(pTeam(&*rit)); + } +} + +void oClub::definedPayModes(oEvent &oe, map &definedPayModes) { + vector< pair > modes; + oe.getPayModes(modes); + if (modes.size() > 1) { + for (size_t k = 0; k < modes.size(); k++) { + definedPayModes[modes[k].second] = modes[k].first; + } + } +} + +void oEvent::printInvoices(gdioutput &gdi, InvoicePrintType type, + const string &basePath, bool onlySummary) { + + map definedPayModes; + oClub::definedPayModes(*this, definedPayModes); + map paidPerMode; + + oClub::assignInvoiceNumber(*this, false); + oClubList::iterator it; + oe->calculateTeamResults(false); + oe->sortTeams(ClassStartTime, 0, true); + oe->calculateResults(RTClassResult); + oe->sortRunners(ClassStartTime); + int pay, paid; + vector fees, vpaid; + set clubId; + fees.reserve(Clubs.size()); + int k=0; + + bool toFile = type > 10; + + string path = basePath; + if (basePath.size() > 0 && *basePath.rbegin() != '\\' && *basePath.rbegin() != '/') + path.push_back('\\'); + + if (toFile) { + ofstream fout; + + if (type == IPTElectronincHTML) + fout.open((path + "invoices.txt").c_str()); + + + for (it=Clubs.begin(); it != Clubs.end(); ++it) { + if (!it->isRemoved()) { + gdi.clearPage(false); + int nr = it->getDCI().getInt("InvoiceNo"); + string filename; + if (type == IPTElectronincHTML) + filename = "invoice" + itos(nr*197) + ".html"; + else if (type == IPTAllPDF) + filename = lang.tl("Faktura") + " " + makeValidFileName(it->getDisplayName(), false) + " (" + itos(nr) + ").pdf"; + else + filename = lang.tl("Faktura") + " " + makeValidFileName(it->getDisplayName(), false) + " (" + itos(nr) + ").html"; + string email = it->getDCI().getString("EMail"); + bool hasEmail = !(email.empty() || email.find_first_of('@') == email.npos); + + if (type == IPTElectronincHTML) { + if (!hasEmail) + continue; + } + + it->generateInvoice(gdi, pay, paid, definedPayModes, paidPerMode); + + if (type == IPTElectronincHTML && pay > 0) { + fout << it->getId() << ";" << it->getName() << ";" << + nr << ";" << filename << ";" << email << ";" + << formatCurrency(pay) <getId()); + fees.push_back(pay); + vpaid.push_back(paid); + } + gdi.clearPage(true); + } + } + else { + for (it=Clubs.begin(); it != Clubs.end(); ++it) { + if (!it->isRemoved()) { + + string email = it->getDCI().getString("EMail"); + bool hasEmail = !(email.empty() || email.find_first_of('@') == email.npos); + if (type == IPTNoMailPrint && hasEmail) + continue; + + it->generateInvoice(gdi, pay, paid, definedPayModes, paidPerMode); + clubId.insert(it->getId()); + fees.push_back(pay); + vpaid.push_back(paid); + } + } + } + + if (onlySummary) + gdi.clearPage(true); + k=0; + gdi.dropLine(1); + gdi.addString("", boldLarge, "Sammanställning, ekonomi"); + int yp = gdi.getCY() + 10; + + gdi.addString("", yp, 50, boldText, "Faktura nr"); + gdi.addString("", yp, 240, boldText|textRight, "KlubbId"); + + gdi.addString("", yp, 250, boldText, "Klubb"); + gdi.addString("", yp, 550, boldText|textRight, "Faktura"); + gdi.addString("", yp, 620, boldText|textRight, "Kontant"); + + yp+=gdi.getLineHeight()+3; + + int sum = 0, psum = 0; + for (it=Clubs.begin(); it != Clubs.end(); ++it) { + if (!it->isRemoved() && clubId.count(it->getId()) > 0) { + + gdi.addStringUT(yp, 50, fontMedium, itos(it->getDCI().getInt("InvoiceNo"))); + gdi.addStringUT(yp, 240, textRight|fontMedium, itos(it->getId())); + gdi.addStringUT(yp, 250, fontMedium, it->getName()); + gdi.addStringUT(yp, 550, fontMedium|textRight, oe->formatCurrency(fees[k])); + gdi.addStringUT(yp, 620, fontMedium|textRight, oe->formatCurrency(vpaid[k])); + + sum+=fees[k]; + psum+=vpaid[k]; + k++; + yp+=gdi.getLineHeight(); + } + } + + yp+=gdi.getLineHeight(); + gdi.fillDown(); + gdi.addStringUT(yp, 550, boldText|textRight, lang.tl("Totalt faktureras: ") + oe->formatCurrency(sum)); + gdi.addStringUT(yp+gdi.getLineHeight(), 550, boldText|textRight, lang.tl("Totalt kontant: ") + oe->formatCurrency(psum)); + gdi.dropLine(0.5); + if (definedPayModes.size() > 1) { + vector< pair > modes; + oe->getPayModes(modes); + for (k = 0; k < int(modes.size()); k++) { + int ppm = paidPerMode[k]; + if (ppm > 0) { + gdi.addStringUT(gdi.getCY(), 550, normalText|textRight, modes[k].first + ": " + oe->formatCurrency(ppm)); + } + } + } +} + +void oClub::updateFromDB() +{ + if (!oe->useRunnerDb()) + return; + + pClub pc = oe->runnerDB->getClub(Id); + + if (pc && !pc->sameClub(*this)) + pc = 0; + + if (pc==0) + pc = oe->runnerDB->getClub(name); + + if (pc) { + memcpy(oData, pc->oData, sizeof (oData)); + updateChanged(); + } +} + +void oEvent::updateClubsFromDB() +{ + if (!oe->useRunnerDb()) + return; + + oClubList::iterator it; + + for (it=Clubs.begin();it!=Clubs.end();++it) { + it->updateFromDB(); + it->synchronize(); + } +} + +bool oClub::sameClub(const oClub &c) +{ + return _stricmp(name.c_str(), c.name.c_str())==0; +} + +void oClub::remove() +{ + if (oe) + oe->removeClub(Id); +} + +bool oClub::canRemove() const +{ + return !oe->isClubUsed(Id); +} + +void oEvent::setupClubInfoData() { + if (tClubDataRevision == dataRevision || Clubs.empty()) + return; + + inthashmap fee(Clubs.size()); + inthashmap paid(Clubs.size()); + inthashmap runners(Clubs.size()); + + // Individual fees + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + oRunner &r = *it; + if (r.Club) { + int id = r.Club->Id; + ++runners[id]; + oDataConstInterface di = r.getDCI(); + bool skip = r.Class && r.Class->getClassStatus() == oClass::InvalidRefund; + + if (!skip) { + int cardFee = di.getInt("CardFee"); + if (cardFee < 0) + cardFee = 0; + fee[id] += di.getInt("Fee") + cardFee; + } + paid[id] += di.getInt("Paid"); + } + } + + // Team fees + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved()) + continue; + oTeam &t = *it; + if (t.Club) { + int id = t.Club->Id; + oDataConstInterface di = t.getDCI(); + bool skip = t.Class && t.Class->getClassStatus() == oClass::InvalidRefund; + + if (!skip) { + fee[id] += di.getInt("Fee"); + } + paid[id] += di.getInt("Paid"); + } + } + + for (oClubList::iterator it = Clubs.begin(); it != Clubs.end(); ++it) { + int id = it->Id; + it->tFee = fee[id]; + it->tPaid = paid[id]; + it->tNumRunners = runners[id]; + } + + tClubDataRevision = dataRevision; +} + + +bool oClub::isVacant() const { + return getId() == oe->getVacantClubIfExist(); +} + +void oClub::changeId(int newId) { + pClub old = oe->clubIdIndex[Id]; + if (old == this) + oe->clubIdIndex.remove(Id); + + oBase::changeId(newId); + + oe->clubIdIndex[newId] = this; +} + +void oClub::clearClubs(oEvent &oe) { + vector r; + oe.getRunners(0, 0, r, false); + + for (size_t k = 0; ksetClubId(0); + r[k]->synchronize(true); + } + + vector t; + oe.getTeams(0, t, false); + + for (size_t k = 0; ksetClubId(0); + t[k]->synchronize(true); + } + + vector c; + oe.getClubs(c, false); + for (size_t k = 0; kgetId()); + } +} + +void oClub::assignInvoiceNumber(oEvent &oe, bool reset) { + oe.synchronizeList(oLClubId); + oe.Clubs.sort(); + int numberStored = oe.getPropertyInt("FirstInvoice", 100); + int number = numberStored; + if (!reset) { + int maxInvoice = 0; + for (oClubList::iterator it = oe.Clubs.begin(); it != oe.Clubs.end(); ++it) { + if (it->isRemoved()) + continue; + int no = it->getDCI().getInt("InvoiceNo"); + maxInvoice = max(maxInvoice, no); + } + + if (maxInvoice != 0) + number = maxInvoice + 1; + else + reset = true; // All zero + } + + for (oClubList::iterator it = oe.Clubs.begin(); it != oe.Clubs.end(); ++it) { + if (it->isRemoved()) + continue; + if (reset || it->getDCI().getInt("InvoiceNo") == 0) { + it->getDI().setInt("InvoiceNo", number++); + it->synchronize(true); + } + } + + if (number > numberStored) + oe.setProperty("FirstInvoice", number); +} + +int oClub::getFirstInvoiceNumber(oEvent &oe) { + oe.synchronizeList(oLClubId); + int number = 0; + for (oClubList::iterator it = oe.Clubs.begin(); it != oe.Clubs.end(); ++it) { + if (it->isRemoved()) + continue; + int no = it->getDCI().getInt("InvoiceNo"); + if (no > 0) { + if (number == 0) + number = no; + else + number = min(number, no); + } + } + return number; +} + +void oClub::changedObject() { + if (oe) + oe->globalModification = true; +} + +bool oClub::operator<(const oClub &c) const { + return CompareString(LOCALE_USER_DEFAULT, 0, + name.c_str(), name.length(), + c.name.c_str(), c.name.length()) == CSTR_LESS_THAN; +} \ No newline at end of file diff --git a/code/oClub.h b/code/oClub.h new file mode 100644 index 0000000..678fa83 --- /dev/null +++ b/code/oClub.h @@ -0,0 +1,193 @@ +// oClub.h: interface for the oClub class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OCLUB_H__8B2917E2_6A48_4E7F_82AD_4F8C64167439__INCLUDED_) +#define AFX_OCLUB_H__8B2917E2_6A48_4E7F_82AD_4F8C64167439__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include "xmlparser.h" +#include "oBase.h" +class oEvent; + +class oClub; +class oRunner; +typedef oRunner* pRunner; +class oTeam; +typedef oTeam* pTeam; + +typedef oClub* pClub; +class oDataInterface; +class oDataConstInterface; +class Table; + +class oClub : public oBase +{ +protected: + + struct InvoiceLine { + InvoiceLine() : fee(0), rent(0), paid(0), payMode(0) {} + vector< pair > > xposAndString; + int fee; + int rent; + int paid; + int payMode; + void addString(int xpos, const string &str, bool right = false) { + xposAndString.push_back(make_pair(xpos, make_pair(right, str))); + } + }; + + string name; + vector altNames; + string tPrettyName; + + static const int dataSize = 384; + int getDISize() const {return dataSize;} + BYTE oData[dataSize]; + BYTE oDataOld[dataSize]; + + int tNumRunners; + int tFee; + int tPaid; + + virtual int getTableId() const; + + bool inputData(int id, const string &input, int inputId, + string &output, bool noUpdate); + + void fillInput(int id, vector< pair > &elements, size_t &selected); + + void exportIOFClub(xmlparser &xml, bool compact) const; + + void exportClubOrId(xmlparser &xml) const; + + // Set name internally, and update pretty name + void internalSetName(const string &n); + + void changeId(int newId); + + struct InvoiceData { + int yp; + int xs; + int adrPos; + int clsPos; + bool multiDay; + int cardPos; + int feePos; + int paidPos; + int resPos; + int total_fee_amount; + int total_rent_amount; + int total_paid_amount; + map paidPerMode; + int lh;//lineheight + InvoiceData(int lh_) { + yp = 0; + xs = 0; + adrPos = 0; + clsPos = 0; + multiDay = 0; + cardPos = 0; + feePos = 0; + paidPos = 0; + resPos = 0; + total_fee_amount = 0; + total_rent_amount = 0; + total_paid_amount = 0; + paidPerMode.clear(); + lh = lh_; + } + }; + + void addInvoiceLine(gdioutput &gdi, const InvoiceLine &lines, InvoiceData &data) const; + + void addRunnerInvoiceLine(const pRunner r, bool inTeam, + const map &definedPayModes, + const InvoiceData &data, list &lines) const; + void addTeamInvoiceLine(const pTeam r, + const map &definedPayModes, + const InvoiceData &data, list &lines) const; + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + void changedObject(); + +public: + + /** Assign invoice numbers to all clubs. */ + static void assignInvoiceNumber(oEvent &oe, bool reset); + + static int getFirstInvoiceNumber(oEvent &oe); + + static void definedPayModes(oEvent &oe, map &definedPayModes); + + + /** Remove all clubs from a competion (and all belong to club relations)*/ + static void clearClubs(oEvent &oe); + + static void buildTableCol(oEvent *oe, Table *t); + void addTableRow(Table &table) const; + + void remove(); + bool canRemove() const; + + void updateFromDB(); + + bool operator<(const oClub &c) const; + void generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid, + const map &definedPayModes, + map &paidPerMode); + + string getInfo() const {return "Klubb " + name;} + bool sameClub(const oClub &c); + + const string &getName() const {return name;} + + const string &getDisplayName() const {return tPrettyName.empty() ? name : tPrettyName;} + + void setName(const string &n); + + void set(const xmlobject &xo); + bool write(xmlparser &xml); + + bool isVacant() const; + oClub(oEvent *poe); + oClub(oEvent *poe, int id); + virtual ~oClub(); + + friend class oAbstractRunner; + friend class oEvent; + friend class oRunner; + friend class oTeam; + friend class oClass; + friend class MeosSQL; +}; + +#endif // !defined(AFX_OCLUB_H__8B2917E2_6A48_4E7F_82AD_4F8C64167439__INCLUDED_) diff --git a/code/oControl.cpp b/code/oControl.cpp new file mode 100644 index 0000000..19f2fcc --- /dev/null +++ b/code/oControl.cpp @@ -0,0 +1,1000 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oControl.cpp: implementation of the oControl class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include + +#include "oControl.h" +#include "oEvent.h" +#include "gdioutput.h" +#include "meos_util.h" +#include +#include "Localizer.h" +#include "Table.h" +#include "MeOSFeatures.h" +#include +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +using namespace std; + +oControl::oControl(oEvent *poe): oBase(poe) +{ + getDI().initData(); + nNumbers=0; + Status=StatusOK; + tMissedTimeMax = 0; + tMissedTimeTotal = 0; + tNumVisitorsActual = 0; + tNumVisitorsExpected = 0; + tMissedTimeMedian = 0; + tMistakeQuotient = 0; + tNumRunnersRemaining = 0; + tStatDataRevision = -1; + + tHasFreePunchLabel = false; + tNumberDuplicates = 0; +} + +oControl::oControl(oEvent *poe, int id): oBase(poe) +{ + Id = id; + getDI().initData(); + nNumbers=0; + Status=StatusOK; + + tMissedTimeMax = 0; + tMissedTimeTotal = 0; + tNumVisitorsActual = 0; + tNumVisitorsExpected = 0; + tMistakeQuotient = 0; + tMissedTimeMedian = 0; + tNumRunnersRemaining = 0; + tStatDataRevision = -1; + + tHasFreePunchLabel = false; + tNumberDuplicates = 0; +} + +oControl::~oControl() +{ +} + +pair oControl::getIdIndexFromCourseControlId(int courseControlId) { + return make_pair(courseControlId % 100000, courseControlId / 100000); +} + +int oControl::getCourseControlIdFromIdIndex(int controlId, int index) { + assert(controlId < 100000); + return controlId + index * 100000; +} + + +bool oControl::write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Control"); + + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.write("Name", Name); + xml.write("Numbers", codeNumbers()); + xml.write("Status", Status); + + getDI().write(xml); + xml.endTag(); + + return true; +} + +void oControl::set(int pId, int pNumber, string pName) +{ + Id=pId; + Numbers[0]=pNumber; + nNumbers=1; + Name=pName; + + updateChanged(); +} + + +void oControl::setStatus(ControlStatus st){ + if (st!=Status){ + Status=st; + updateChanged(); + } +} + +void oControl::setName(string name) +{ + if (name!=getName()){ + Name=name; + updateChanged(); + } +} + + +void oControl::set(const xmlobject *xo) +{ + xmlList xl; + xo->getObjects(xl); + nNumbers=0; + Numbers[0]=0; + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Id")){ + Id=it->getInt(); + } + else if (it->is("Number")){ + Numbers[0]=it->getInt(); + nNumbers=1; + } + else if (it->is("Numbers")){ + decodeNumbers(it->get()); + } + else if (it->is("Status")){ + Status=(ControlStatus)it->getInt(); + } + else if (it->is("Name")){ + Name=it->get(); + if (Name.size() > 1 && Name.at(0) == '%') { + Name = lang.tl(Name.substr(1)); + } + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + else if (it->is("oData")){ + getDI().set(*it); + } + } +} + +int oControl::getFirstNumber() const { + if (nNumbers > 0) + return Numbers[0]; + else + return 0; +} + +string oControl::getString() { + char bf[32]; + if (Status==StatusOK || Status==StatusNoTiming) + return codeNumbers('|'); + else if (Status==StatusMultiple) + return codeNumbers('+'); + else if (Status==StatusRogaining) + return codeNumbers('|') + ", " + itos(getRogainingPoints()) + "p"; + else + sprintf_s(bf, 32, "~%s", codeNumbers().c_str()); + return bf; +} + +string oControl::getLongString() +{ + if (Status==StatusOK || Status==StatusNoTiming){ + if (nNumbers==1) + return codeNumbers('|'); + else + return string(lang.tl("VALFRI("))+codeNumbers(',')+")"; + } + else if (Status == StatusMultiple) { + return string(lang.tl("ALLA("))+codeNumbers(',')+")"; + } + else if (Status == StatusRogaining) + return string(lang.tl("RG("))+codeNumbers(',') + "|" + itos(getRogainingPoints()) +"p)"; + else + return string(lang.tl("TRASIG("))+codeNumbers(',')+")"; +} + +bool oControl::hasNumber(int i) +{ + for(int n=0;n0) + return false; + else return true; +} + +bool oControl::uncheckNumber(int i) +{ + for(int n=0;n0) + return false; + else return true; +} + + +int oControl::getNumMulti() +{ + if (Status==StatusMultiple) + return nNumbers; + else + return 1; +} + + +string oControl::codeNumbers(char sep) const +{ + string n; + char bf[16]; + + for(int i=0;i0 && cid<1024 && nNumbers<32) + Numbers[nNumbers++]=cid; + } + + if (Numbers==0){ + Numbers[0]=0; + nNumbers=1; + return false; + } + else return true; +} + +bool oControl::setNumbers(const string &numbers) +{ + int nn=nNumbers; + int bf[32]; + + if (unsigned(nNumbers)<32) + memcpy(bf, Numbers, sizeof(int)*nNumbers); + + bool success=decodeNumbers(numbers); + + if (!success) { + memcpy(Numbers, bf, sizeof(int)*nn); + nNumbers = nn; + } + + if (nNumbers!=nn || memcmp(bf, Numbers, sizeof(int)*nNumbers)!=0) { + updateChanged(); + oe->punchIndex.clear(); + } + + return success; +} + +string oControl::getName() const +{ + if (!Name.empty()) + return Name; + else { + char bf[16]; + sprintf_s(bf, "[%d]", Id); + return bf; + } +} + +string oControl::getIdS() const +{ + if (!Name.empty()) + return Name; + else { + char bf[16]; + sprintf_s(bf, "%d", Id); + return bf; + } +} + +oDataContainer &oControl::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = 0; + return *oe->oControlData; +} + +const vector< pair > &oEvent::fillControls(vector< pair > &out, oEvent::ControlType type) +{ + out.clear(); + oControlList::iterator it; + synchronizeList(oLControlId); + Controls.sort(); + + if (type == oEvent::CTCourseControl) { + vector dmy; + getControls(dmy, true); + } + + string b; + char bf[256]; + for (it=Controls.begin(); it != Controls.end(); ++it) { + if (!it->Removed){ + b.clear(); + + if (type==oEvent::CTAll) { + if (it->Status == oControl::StatusFinish || it->Status == oControl::StatusStart) { + b += it->Name; + } + else { + if (it->Status == oControl::StatusOK || it->Status == oControl::StatusNoTiming) + b+="[OK]\t"; + else if (it->Status==oControl::StatusMultiple) + b+="[M]\t"; + else if (it->Status==oControl::StatusRogaining) + b+="[R]\t"; + else if (it->Status==oControl::StatusBad) + b += MakeDash("[-]\t"); + else if (it->Status==oControl::StatusOptional) + b += MakeDash("[O]\t"); + else b+="[ ]\t"; + + sprintf_s(bf, " %s", it->codeNumbers(' ').c_str()); + b+=bf; + + if (it->Status==oControl::StatusRogaining) + b+="\t(" + itos(it->getRogainingPoints()) + "p)"; + else if (it->Name.length()>0) { + b+="\t("+it->Name+")"; + } + } + out.push_back(make_pair(b, it->Id)); + } + else if (type==oEvent::CTRealControl) { + if (it->Status == oControl::StatusFinish || it->Status == oControl::StatusStart) + continue; + + sprintf_s(bf, lang.tl("Kontroll %s").c_str(), it->codeNumbers(' ').c_str()); + b=bf; + + if (!it->Name.empty()) + b+=" ("+it->Name+")"; + + out.push_back(make_pair(b, it->Id)); + } + else if (type==oEvent::CTCourseControl) { + if (it->Status == oControl::StatusFinish || it->Status == oControl::StatusStart) + continue; + + for (int i = 0; i < it->getNumberDuplicates(); i++) { + sprintf_s(bf, lang.tl("Kontroll %s").c_str(), it->codeNumbers(' ').c_str()); + b = bf; + + if (it->getNumberDuplicates() > 1) + b += "-" + itos(i+1); + + if (!it->Name.empty()) + b += " ("+it->Name+")"; + + out.push_back(make_pair(b, oControl::getCourseControlIdFromIdIndex(it->Id, i))); + } + } + } + } + return out; +} + +const vector< pair > &oEvent::fillControlTypes(vector< pair > &out) +{ + oControlList::iterator it; + synchronizeList(oLControlId); + out.clear(); + //gdi.clearList(name); + out.clear(); + set sicodes; + + for (it=Controls.begin(); it != Controls.end(); ++it){ + if (!it->Removed) { + for (int k=0;knNumbers;k++) + sicodes.insert(it->Numbers[k]); + } + } + + set::iterator sit; + char bf[32]; + /*gdi.addItem(name, lang.tl("Check"), oPunch::PunchCheck); + gdi.addItem(name, lang.tl("Start"), oPunch::PunchStart); + gdi.addItem(name, lang.tl("Mål"), oPunch::PunchFinish);*/ + out.push_back(make_pair(lang.tl("Check"), oPunch::PunchCheck)); + out.push_back(make_pair(lang.tl("Start"), oPunch::PunchStart)); + out.push_back(make_pair(lang.tl("Mål"), oPunch::PunchFinish)); + + for (sit = sicodes.begin(); sit!=sicodes.end(); ++sit) { + sprintf_s(bf, lang.tl("Kontroll %s").c_str(), itos(*sit).c_str()); + //gdi.addItem(name, bf, *sit); + out.push_back(make_pair(bf, *sit)); + } + return out; +} + +void oControl::setupCache() const { + if (tCache.dataRevision != oe->dataRevision) { + tCache.timeAdjust = getDCI().getInt("TimeAdjust"); + tCache.minTime = getDCI().getInt("MinTime"); + tCache.dataRevision = oe->dataRevision; + } +} + +int oControl::getMinTime() const +{ + if (Status == StatusNoTiming) + return 0; + setupCache(); + return tCache.minTime; +} + +int oControl::getTimeAdjust() const +{ + setupCache(); + return tCache.timeAdjust; +} + +string oControl::getTimeAdjustS() const +{ + return getTimeMS(getTimeAdjust()); +} + +string oControl::getMinTimeS() const +{ + if (getMinTime()>0) + return getTimeMS(getMinTime()); + else + return "-"; +} + +int oControl::getRogainingPoints() const +{ + return getDCI().getInt("Rogaining"); +} + +string oControl::getRogainingPointsS() const +{ + int pt = getRogainingPoints(); + return pt != 0 ? itos(pt) : ""; +} + +void oControl::setTimeAdjust(int v) +{ + getDI().setInt("TimeAdjust", v); +} + +void oControl::setRadio(bool r) +{ + // 1 means radio, 2 means no radio, 0 means default + getDI().setInt("Radio", r ? 1 : 2); +} + +bool oControl::isValidRadio() const +{ + int flag = getDCI().getInt("Radio"); + if (flag == 0) + return (tHasFreePunchLabel || hasName()) && getStatus() == oControl::StatusOK; + else + return flag == 1; +} + +void oControl::setTimeAdjust(const string &s) +{ + setTimeAdjust(convertAbsoluteTimeMS(s)); +} + +void oControl::setMinTime(int v) +{ + if (v<0 || v == NOTIME) + v = 0; + getDI().setInt("MinTime", v); +} + +void oControl::setMinTime(const string &s) +{ + setMinTime(convertAbsoluteTimeMS(s)); +} + +void oControl::setRogainingPoints(int v) +{ + getDI().setInt("Rogaining", v); +} + +void oControl::setRogainingPoints(const string &s) +{ + setRogainingPoints(atoi(s.c_str())); +} + +void oControl::startCheckControl() +{ + //Mark all numbers as unchecked. + for (int k=0;k &mp, bool supportRogaining) const +{ + if (controlCompleted(supportRogaining)) + return; + + for (int k=0;kgetRevision()) + oe->setupControlStatistics(); + + return tMissedTimeTotal; +} + +int oControl::getMissedTimeMax() const { + if (tStatDataRevision != oe->getRevision()) + oe->setupControlStatistics(); + + return tMissedTimeMax; +} + +int oControl::getMissedTimeMedian() const { + if (tStatDataRevision != oe->getRevision()) + oe->setupControlStatistics(); + + return tMissedTimeMedian; +} + +int oControl::getMistakeQuotient() const { + if (tStatDataRevision != oe->getRevision()) + oe->setupControlStatistics(); + + return tMistakeQuotient; +} + + +int oControl::getNumVisitors(bool actulaVisits) const { + if (tStatDataRevision != oe->getRevision()) + oe->setupControlStatistics(); + + if (actulaVisits) + return tNumVisitorsActual; + else + return tNumVisitorsExpected; +} + +int oControl::getNumRunnersRemaining() const { + if (tStatDataRevision != oe->getRevision()) + oe->setupControlStatistics(); + + return tNumRunnersRemaining; +} + +void oEvent::setupControlStatistics() const { + // Reset all times + for (oControlList::const_iterator it = Controls.begin(); it != Controls.end(); ++it) { + it->tMissedTimeMax = 0; + it->tMissedTimeTotal = 0; + it->tNumVisitorsActual = 0; + it->tNumVisitorsExpected = 0; + it->tNumRunnersRemaining = 0; + it->tMissedTimeMedian = 0; + it->tMistakeQuotient = 0; + it->tStatDataRevision = dataRevision; // Mark as up-to-date + } + + map > > lostPerControl; // First is "actual" misses, + vector delta; + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + pCourse pc = it->getCourse(true); + if (!pc) + continue; + it->getSplitAnalysis(delta); + + int nc = pc->getNumControls(); + if (delta.size()>unsigned(nc)) { + for (int i = 0; igetControl(i); + if (ctrl && delta[i]>0) { + if (delta[i] < 10 * 60) + ctrl->tMissedTimeTotal += delta[i]; + else + ctrl->tMissedTimeTotal += 10*60; // Use max 10 minutes + + ctrl->tMissedTimeMax = max(ctrl->tMissedTimeMax, delta[i]); + } + + if (delta[i] > 0) { + lostPerControl[ctrl->getId()].second.push_back(delta[i]); + ++lostPerControl[ctrl->getId()].first; + } + + ctrl->tNumVisitorsActual++; + } + } + + if (!it->isVacant() && it->getStatus() != StatusDNS + && it->getStatus() != StatusNotCompetiting) { + + for (int i = 0; i < nc; i++) { + pControl ctrl = pc->getControl(i); + ctrl->tNumVisitorsExpected++; + + if (it->getStatus() == StatusUnknown) + ctrl->tNumRunnersRemaining++; + } + + } + } + + for (oControlList::const_iterator it = Controls.begin(); it != Controls.end(); ++it) { + if (!it->isRemoved()) { + int id = it->getId(); + + map > >::iterator res = lostPerControl.find(id); + if (res != lostPerControl.end()) { + if (!res->second.second.empty()) { + sort(res->second.second.begin(), res->second.second.end()); + int avg = res->second.second[res->second.second.size() / 2]; + it->tMissedTimeMedian = avg; + } + it->tMistakeQuotient = (100 * res->second.first + 50) / it->tNumVisitorsActual; + } + } + } +} + +bool oEvent::hasRogaining() const +{ + oControlList::const_iterator it; + for (it=Controls.begin(); it != Controls.end(); ++it) { + if (!it->Removed && it->isRogaining(true)) + return true; + } + return false; +} + +const string oControl::getStatusS() const { + //enum ControlStatus {StatusOK=0, StatusBad=1, StatusMultiple=2, + // StatusStart = 4, StatusFinish = 5, StatusRogaining = 6}; + + switch (getStatus()) { + case StatusOK: + return lang.tl("OK"); + case StatusBad: + return lang.tl("Trasig"); + case StatusOptional: + return lang.tl("Valfri"); + case StatusMultiple: + return lang.tl("Multipel"); + case StatusRogaining: + return lang.tl("Rogaining"); + case StatusStart: + return lang.tl("Start"); + case StatusFinish: + return lang.tl("Mål"); + case StatusNoTiming: + return lang.tl("Utan tidtagning"); + default: + return lang.tl("Okänd"); + } +} + +void oEvent::fillControlStatus(gdioutput &gdi, const string& id) const +{ + vector< pair > d; + oe->fillControlStatus(d); + gdi.addItem(id, d); +} + + +const vector< pair > &oEvent::fillControlStatus(vector< pair > &out) const +{ + out.clear(); + out.push_back(make_pair(lang.tl("OK"), oControl::StatusOK)); + out.push_back(make_pair(lang.tl("Multipel"), oControl::StatusMultiple)); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining)) + out.push_back(make_pair(lang.tl("Rogaining"), oControl::StatusRogaining)); + out.push_back(make_pair(lang.tl("Utan tidtagning"), oControl::StatusNoTiming)); + out.push_back(make_pair(lang.tl("Trasig"), oControl::StatusBad)); + out.push_back(make_pair(lang.tl("Valfri"), oControl::StatusOptional)); + + return out; +} + +Table *oEvent::getControlTB()//Table mode +{ + if (tables.count("control") == 0) { + Table *table=new Table(this, 20, "Kontroller", "controls"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 150, false); + table->addColumn("Status", 70, false); + table->addColumn("Stämpelkoder", 100, true); + table->addColumn("Antal löpare", 70, true, true); + table->addColumn("Bomtid (max)", 70, true, true); + table->addColumn("Bomtid (medel)", 70, true, true); + table->addColumn("Bomtid (median)", 70, true, true); + + oe->oControlData->buildTableCol(table); + tables["control"] = table; + table->addOwnership(); + + table->setTableProp(Table::CAN_DELETE); + } + + tables["control"]->update(); + return tables["control"]; +} + +void oEvent::generateControlTableData(Table &table, oControl *addControl) +{ + if (addControl) { + addControl->addTableRow(table); + return; + } + + synchronizeList(oLControlId); + oControlList::iterator it; + + for (it=Controls.begin(); it != Controls.end(); ++it){ + if (!it->isRemoved()){ + it->addTableRow(table); + } + } +} + +void oControl::addTableRow(Table &table) const { + oControl &it = *pControl(this); + table.addRow(getId(), &it); + + int row = 0; + table.set(row++, it, TID_ID, itos(getId()), false); + table.set(row++, it, TID_MODIFIED, getTimeStamp(), false); + + table.set(row++, it, TID_CONTROL, getName(), true); + bool canEdit = getStatus() != oControl::StatusFinish && getStatus() != oControl::StatusStart; + table.set(row++, it, TID_STATUS, getStatusS(), canEdit, cellSelection); + table.set(row++, it, TID_CODES, codeNumbers(), true); + + int nv = getNumVisitors(true); + table.set(row++, it, 50, itos(nv), false); + table.set(row++, it, 51, nv > 0 ? formatTime(getMissedTimeMax()) : "-", false); + table.set(row++, it, 52, nv > 0 ? formatTime(getMissedTimeTotal()/nv) : "-", false); + table.set(row++, it, 53, nv > 0 ? formatTime(getMissedTimeMedian()) : "-", false); + + oe->oControlData->fillTableCol(it, table, true); +} + +bool oControl::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + synchronize(false); + + if (id>1000) { + return oe->oControlData->inputData(this, id, input, inputId, output, noUpdate); + } + switch(id) { + case TID_CONTROL: + setName(input); + synchronize(); + output=getName(); + return true; + case TID_STATUS: + setStatus(ControlStatus(inputId)); + synchronize(true); + output = getStatusS(); + return true; + case TID_CODES: + bool stat = setNumbers(input); + synchronize(true); + output = codeNumbers(); + return stat; + break; + } + + return false; +} + +void oControl::fillInput(int id, vector< pair > &out, size_t &selected) +{ + if (id>1000) { + oe->oControlData->fillInput(oData, id, 0, out, selected); + return; + } + + if (id==TID_STATUS) { + oe->fillControlStatus(out); + selected = getStatus(); + } +} + +void oControl::remove() +{ + if (oe) + oe->removeControl(Id); +} + +bool oControl::canRemove() const +{ + return !oe->isControlUsed(Id); +} + +void oEvent::getControls(vector &c, bool calculateCourseControls) const { + c.clear(); + + if (calculateCourseControls) { + stdext::hash_map cById; + for (oControlList::const_iterator it = Controls.begin(); it != Controls.end(); ++it) { + if (it->isRemoved()) + continue; + it->tNumberDuplicates = 0; + cById[it->getId()] = pControl(&*it); + } + for (oCourseList::const_iterator it = Courses.begin(); it != Courses.end(); ++it) { + map count; + for (int i = 0; i < it->nControls; i++) { + ++count[it->Controls[i]->getId()]; + } + for (map::iterator it = count.begin(); it != count.end(); ++it) { + stdext::hash_map::iterator res = cById.find(it->first); + if (res != cById.end()) { + res->second->tNumberDuplicates = max(res->second->tNumberDuplicates, it->second); + } + } + } + } + + for (oControlList::const_iterator it = Controls.begin(); it != Controls.end(); ++it) { + if (it->isRemoved()) + continue; + c.push_back(pControl(&*it)); + } +} + +void oControl::getNumbers(vector &numbers) const { + numbers.resize(nNumbers); + for (int i = 0; i < nNumbers; i++) { + numbers[i] = Numbers[i]; + } +} + +void oControl::changedObject() { + if (oe) + oe->globalModification = true; +} + +int oControl::getNumberDuplicates() const { + return tNumberDuplicates; +} + +void oControl::getCourseControls(vector &cc) const { + cc.resize(tNumberDuplicates); + for (int i = 0; i < tNumberDuplicates; i++) { + cc[i] = getCourseControlIdFromIdIndex(Id, i); + } +} + +void oControl::getCourses(vector &crs) const { + crs.clear(); + for (oCourseList::const_iterator it = oe->Courses.begin(); it != oe->Courses.end(); it++) { + if (it->isRemoved()) + continue; + + if (it->hasControl(this)) + crs.push_back(pCourse(&*it)); + } +} + +void oControl::getClasses(vector &cls) const { + vector crs; + getCourses(crs); + std::set cid; + for (size_t k = 0; k< crs.size(); k++) { + cid.insert(crs[k]->getId()); + } + + for (oClassList::const_iterator it = oe->Classes.begin(); it != oe->Classes.end(); it++) { + if (it->isRemoved()) + continue; + + if (it->hasAnyCourse(cid)) + cls.push_back(pClass(&*it)); + } +} diff --git a/code/oControl.h b/code/oControl.h new file mode 100644 index 0000000..d335155 --- /dev/null +++ b/code/oControl.h @@ -0,0 +1,236 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oControl.h: interface for the oControl class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OCONTROL_H__E86192B9_78D2_4EEF_AAE1_3BD4A8EB16F0__INCLUDED_) +#define AFX_OCONTROL_H__E86192B9_78D2_4EEF_AAE1_3BD4A8EB16F0__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include "xmlparser.h" +#include "oBase.h" +#include +#include + +class oControl; + +typedef oControl* pControl; +class oDataInterface; +class oDataConstInterface; +class Table; + +class oCourse; +class oClass; +typedef oCourse* pCourse; +typedef oClass* pClass; + +class oControl : public oBase +{ +public: + /** Returns the number of duplicates of this control in any course. Valid after a call to oEvent::getControls with + the calculate flags set to true. */ + int getNumberDuplicates() const; + + void getCourseControls(vector &cc) const; + + static pair getIdIndexFromCourseControlId(int courseControlId); + static int getCourseControlIdFromIdIndex(int controlId, int index); + + enum ControlStatus {StatusOK=0, StatusBad=1, StatusMultiple=2, + StatusStart = 4, StatusFinish = 5, StatusRogaining = 6, StatusNoTiming = 7, StatusOptional = 8}; + bool operator<(const oControl &b) const {return minNumber() > &elements, size_t &selected); + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + struct TCache { + TCache() : minTime(0), timeAdjust(0), dataRevision(-1) {} + int minTime; + int timeAdjust; + int dataRevision; + }; + + // Is set to true if there is a free punch tied to the control + bool tHasFreePunchLabel; + mutable int tNumberDuplicates; + mutable TCache tCache; + void setupCache() const; + + mutable int tStatDataRevision; + + mutable int tMissedTimeTotal; + mutable int tMissedTimeMax; + mutable int tMistakeQuotient; + mutable int tNumVisitorsActual; // Count actual punches + mutable int tNumVisitorsExpected; // Count expected visitors + mutable int tNumRunnersRemaining; // Number of remaining runners expected + + mutable int tMissedTimeMedian; + + void changedObject(); + +public: + + // Returns true if controls is considered a radio control. + bool isValidRadio() const; + // Specify true to mark the controls as a radio control, otherwise no radio + void setRadio(bool r); + + void remove(); + bool canRemove() const; + + string getInfo() const; + + bool isSingleStatusOK() const {return Status == StatusOK || Status == StatusNoTiming;} + + int getMissedTimeTotal() const; + int getMissedTimeMax() const; + int getMistakeQuotient() const; + int getMissedTimeMedian() const; + int getNumVisitors(bool actulaVisits) const; + int getNumRunnersRemaining() const; + + void getCourses(vector &crs) const; + void getClasses(vector &cls) const; + + inline int minNumber() const { + int m = numeric_limits::max(); + for (int k=0;k &mp, bool supportRogaining) const; + //Start checking if all punches needed for this control exist + void startCheckControl(); + //Get the number of a missing punch + int getMissingNumber() const; + /** Returns true if the check of this control is completed + @param supportRogaining true if rogaining controls are supported + */ + bool controlCompleted(bool supportRogaiing) const; + + string codeNumbers(char sep=';') const; + bool setNumbers(const string &numbers); + + ControlStatus getStatus() const {return Status;} + const string getStatusS() const; + + bool hasName() const {return !Name.empty();} + /// Get name or [id] + string getName() const; + /// Get name or id + string getIdS() const; + + bool isRogaining(bool useRogaining) const {return useRogaining && (Status == StatusRogaining);} + + void setStatus(ControlStatus st); + void setName(string name); + + //Returns true if control has number and checks it. + bool hasNumber(int i); + //Return true if it has number i and it is unchecked. + //Checks the number + bool hasNumberUnchecked(int i); + // Uncheck a given number + bool uncheckNumber(int i); + + string getString(); + string getLongString(); + + //For a control that requires several punches, + //return the number of required punches. + int getNumMulti(); + + int getTimeAdjust() const; + string getTimeAdjustS() const; + void setTimeAdjust(int v); + void setTimeAdjust(const string &t); + + int getMinTime() const; + string getMinTimeS() const; + void setMinTime(int v); + void setMinTime(const string &t); + + int getRogainingPoints() const; + string getRogainingPointsS() const; + void setRogainingPoints(int v); + void setRogainingPoints(const string &t); + + /// Return first code number (or zero) + int getFirstNumber() const; + void getNumbers(vector &numbers) const; + + void set(const xmlobject *xo); + void set(int pId, int pNumber, string pName); + bool write(xmlparser &xml); + oControl(oEvent *poe); + oControl(oEvent *poe, int id); + + virtual ~oControl(); + + friend class oRunner; + friend class oCourse; + friend class oEvent; + friend class oClass; + friend class MeosSQL; + friend class TabAuto; + friend class TabSpeaker; +}; + +#endif // !defined(AFX_OCONTROL_H__E86192B9_78D2_4EEF_AAE1_3BD4A8EB16F0__INCLUDED_) diff --git a/code/oCourse.cpp b/code/oCourse.cpp new file mode 100644 index 0000000..ed34658 --- /dev/null +++ b/code/oCourse.cpp @@ -0,0 +1,1389 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oCourse.cpp: implementation of the oCourse class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "oCourse.h" +#include "oEvent.h" +#include "SportIdent.h" +#include +#include "Localizer.h" +#include "meos_util.h" +#include "meosexception.h" +#include +#include "gdioutput.h" +#include + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#include "intkeymapimpl.hpp" + +oCourse::oCourse(oEvent *poe) : oBase(poe) +{ + getDI().initData(); + nControls=0; + Length=0; + clearCache(); + tMapsUsed = -1; + tMapsUsedNoVacant = -1; + Id=oe->getFreeCourseId(); +} + +oCourse::oCourse(oEvent *poe, int id) : oBase(poe) +{ + getDI().initData(); + nControls=0; + Length=0; + clearCache(); + if (id == 0) + id = oe->getFreeCourseId(); + Id=id; + tMapsUsed = -1; + tMapsUsedNoVacant = -1; + oe->qFreeCourseId = max(id, oe->qFreeCourseId); +} + +oCourse::~oCourse() +{ +} + +string oCourse::getInfo() const +{ + return "Bana " + Name; +} + +bool oCourse::Write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Course"); + + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.write("Name", Name); + xml.write("Length", Length); + xml.write("Controls", getControls()); + xml.write("Legs", getLegLengths()); + + getDI().write(xml); + xml.endTag(); + + return true; +} + +void oCourse::Set(const xmlobject *xo) +{ + xmlList xl; + xo->getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Id")){ + Id=it->getInt(); + } + else if (it->is("Length")){ + Length=it->getInt(); + } + else if (it->is("Name")){ + Name=it->get(); + } + else if (it->is("Controls")){ + importControls(it->get(), false); + } + else if (it->is("Legs")) { + importLegLengths(it->get(), false); + } + else if (it->is("oData")){ + getDI().set(*it); + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + } +} + +string oCourse::getLegLengths() const +{ + string str; + for(size_t m=0; m0) + str += ";"; + str+=itos(legLengths[m]); + } + return str; +} + +string oCourse::getControls() const +{ + string str=""; + char bf[16]; + for(int m=0;mId); + str+=bf; + } + + return str; +} + +string oCourse::getControlsUI() const +{ + string str=""; + char bf[16]; + int m; + + for(m=0;mId); + str+=bf; + } + + if (mId); + str+=bf; + } + + return str; +} + +vector oCourse::getCourseReadable(int limit) const +{ + vector res; + + string str; + if (!useFirstAsStart()) + str = lang.tl("Start").substr(0, 1); + int m; + + vector rg; + bool needFinish = false; + bool rogaining = hasRogaining(); + for (m=0; misRogaining(rogaining)) + rg.push_back(Controls[m]); + else { + if (!str.empty()) + str += "-"; + str += Controls[m]->getLongString(); + needFinish = true; + } + if (str.length() >= size_t(limit)) { + res.push_back(str); + str.clear(); + } + } + + if (needFinish && !useLastAsFinish()) { + if (!str.empty()) + str += "-"; + str += lang.tl("Mål").substr(0,1); + } + if (!str.empty()) { + if (str.length()<5 && !res.empty()) + res.back().append(str); + else + res.push_back(str); + str.clear(); + } + + if (!rg.empty()) { + str = lang.tl("Rogaining: "); + for (size_t k = 0; k0) + str += ", "; + + if (str.length() >= size_t(limit)) { + res.push_back(str); + str.clear(); + } + str += rg[k]->getLongString(); + } + if (!str.empty()) { + res.push_back(str); + } + } + + return res; +} + +pControl oCourse::addControl(int Id) +{ + pControl pc = doAddControl(Id); + updateChanged(); + return pc; +} + +pControl oCourse::doAddControl(int Id) +{ + if (nControlsgetControl(Id, true); + if (c==0) + throw meosException("Felaktig kontroll"); + Controls[nControls++]=c; + return c; + } + else + throw meosException("För många kontroller."); +} + +void oCourse::splitControls(const string &ctrls, vector &nr) { + const char *str=ctrls.c_str(); + + nr.clear(); + + while (*str) { + int cid=atoi(str); + + while(*str && (*str!=';' && *str!=',' && *str!=' ')) str++; + while(*str && (*str==';' || *str==',' || *str==' ')) str++; + + if (cid>0) + nr.push_back(cid); + } +} + +bool oCourse::importControls(const string &ctrls, bool updateLegLengths) { + int oldNC = nControls; + vector oldC; + for (int k = 0; kgetId() : 0); + + nControls = 0; + + vector newC; + splitControls(ctrls, newC); + + for (size_t k = 0; k< newC.size(); k++) + doAddControl(newC[k]); + + bool changed = nControls != oldNC; + + if (changed && updateLegLengths && legLengths.size() > 0) { + int oldIndex = 0; + int newIndex = 0; + vector newLen(nControls + 1); + bool lastOK = true; + while (newIndex < nControls) { + if (oldIndex < int(oldC.size())) { + if (oldC[oldIndex] == newC[newIndex]) { + if (lastOK && oldIndex < int(legLengths.size())) { + newLen[newIndex] = legLengths[oldIndex]; + } + lastOK = true; + oldIndex++; + } + else { + lastOK = false; + int forward = oldIndex + 1; + while(forward < int(oldC.size())) { + if (oldC[forward] == newC[newIndex]) { + oldIndex = forward + 1; + lastOK = true; + break; + } + forward++; + } + } + } + else { + lastOK = false; + } + newIndex++; + } + + if (lastOK) { + newLen.back() = legLengths.back(); + } + swap(newLen, legLengths); + } + + for (int k = 0; !changed && kgetId(); + + if (changed) { + updateChanged(); + + oe->punchIndex.clear(); + } + + return changed; +} + +void oCourse::importLegLengths(const string &legs, bool setChanged) +{ + vector splits; + split(legs, ";", splits); + + bool changed = false; + + if (legLengths.size() != splits.size()) { + legLengths.resize(splits.size()); + changed = true; + } + for (size_t k = 0; k=0 && indexgetString(); + if (c.length() > 32) + c= c.substr(0, 32) + "..."; + if (k == startIx) + c += " (" + lang.tl("Start") + ")"; + else if (k == finishIx) + c += " (" + lang.tl("Mål") + ")"; + + int multi = Controls[k]->getNumMulti(); + int submulti = 0; + char bf[256]; + if (Controls[k]->isRogaining(rogaining)) { + sprintf_s(bf, 64, "R\t%s", c.c_str()); + offset--; + } + else if (multi == 1) { + sprintf_s(bf, 64, "%d\t%s", k+offset, c.c_str()); + } + else + sprintf_s(bf, 64, "%d%c\t%s", k+offset, 'A', c.c_str()); + gdi.addItem(name, bf, k); + while (multi>1) { + submulti++; + sprintf_s(bf, 64, "%d%c\t-:-", k+offset, 'A'+submulti); + gdi.addItem(name, bf, -1); + multi--; + } + offset += submulti; + } + if (finishIx == -1) + gdi.addItem(name, lang.tl("Mål"), -1); + + return true; +} + +void oCourse::getControls(vector &pc) +{ + pc.clear(); + pc.reserve(nControls); + for(int k=0;k rogaining; + vector< map > allowedControls; + allowedControls.reserve(nControls); + set commonCode; + if (hasRogaining()) { + for (int k=0;kisRogaining(true)) { + for (int j = 0; j < Controls[k]->nNumbers; j++) + rogaining.insert(Controls[k]->Numbers[j]); + } + } + } + + int toMatch = 0; + size_t orderIndex = 0; + for (int k=0;kisRogaining(hasRogaining()) || + Controls[k]->getStatus() == oControl::StatusBad || + Controls[k]->getStatus() == oControl::StatusOptional) + continue; + + if (Controls[k]->getStatus() == oControl::StatusMultiple) { + for (int j = 0; j < Controls[k]->nNumbers; j++) { + if (allowedControls.size() <= orderIndex) + allowedControls.resize(orderIndex+1); + for (int i = 0; i < Controls[k]->nNumbers; i++) { + ++allowedControls[orderIndex][Controls[k]->Numbers[i]]; + } + orderIndex++; + toMatch++; + } + } + else { + if (allowedControls.size() <= orderIndex) + allowedControls.resize(orderIndex+1); + + for (int j = 0; j < Controls[k]->nNumbers; j++) { + ++allowedControls[orderIndex][Controls[k]->Numbers[j]]; + } + orderIndex++; + toMatch++; + } + + if (getCommonControl() == Controls[k]->getId()) { + orderIndex = 0; + commonCode.insert(Controls[k]->Numbers, Controls[k]->Numbers+Controls[k]->nNumbers); + } + } + + size_t matchIndex = 0; + for (unsigned k=0; k 0) { + --allowedControls[matchIndex][card.Punch[j].Code]; + k = j; + matches++; + break; + } + } + matchIndex++; + if (commonCode.count(card.Punch[k].Code)) + matchIndex = 0; + } + + if (matches==toMatch) { + //This course is OK. Extra controls? + return card.nPunch-toMatch; //Positive return + } + else { + return matches-toMatch; //Negative return; + } + return 0; +} + +string oCourse::getLengthS() const +{ + return itos(getLength()); +} + +void oCourse::setName(const string &n) +{ + if (Name!=n){ + Name=n; + updateChanged(); + } +} + +void oCourse::setLength(int le) +{ + if (le<0 || le > 1000000) + le = 0; + + if (Length!=le){ + Length=le; + updateChanged(); + } +} + +oDataContainer &oCourse::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = 0; + return *oe->oCourseData; +} + +pCourse oEvent::getCourseCreate(int Id) +{ + oCourseList::iterator it; + for (it=Courses.begin(); it != Courses.end(); ++it) { + if (it->Id==Id) + return &*it; + } + if (Id>0) { + oCourse c(this, Id); + c.setName(getAutoCourseName()); + return addCourse(c); + } + else { + return addCourse(getAutoCourseName()); + } +} + +pCourse oEvent::getCourse(int Id) const { + if (Id==0) + return 0; + + pCourse value; + if (courseIdIndex.lookup(Id,value)) + return value; + + return 0; +} + +pCourse oEvent::getCourse(const string &n) const { + oCourseList::const_iterator it; + + for (it=Courses.begin(); it != Courses.end(); ++it) { + if (it->Name==n) + return pCourse(&*it); + } + return 0; +} + +void oEvent::fillCourses(gdioutput &gdi, const string &id, bool simple) +{ + vector< pair > d; + oe->fillCourses(d, simple); + gdi.addItem(id, d); +} + +const vector< pair > &oEvent::fillCourses(vector< pair > &out, bool simple) +{ + out.clear(); + oCourseList::iterator it; + synchronizeList(oLCourseId); + + Courses.sort(); + + vector< pair> > ac; + ac.reserve(Courses.size()); + map id2ix; + for (it=Courses.begin(); it != Courses.end(); ++it) { + if (!it->Removed){ + id2ix[it->getId()] = ac.size(); + ac.push_back(make_pair(pCourse(&*it), make_pair(pCourse(0), false))); + } + } + + for (size_t k = 0; k < ac.size(); k++) { + pCourse sh = ac[k].first->getShorterVersion(); + if (sh != 0) { + int ix = id2ix[sh->getId()]; + if (!ac[ix].second.first) + ac[ix].second.first = ac[k].first; + else + ac[ix].second.second = true; + } + } + + string b; + for (size_t k = 0; k < ac.size(); k++) { + pCourse it = ac[k].first; + + if (simple) //gdi.addItem(name, it->Name, it->Id); + out.push_back(make_pair(it->Name, it->Id)); + else { + b = it->Name; + if (ac[k].second.first) { + b += " < " + ac[k].second.first->Name; + if (ac[k].second.second) + b += ", ..."; + } + b += "\t(" + itos(it->nControls) + ")"; + if (!it->getCourseProblems().empty()) + b = "[!] " + b; + out.push_back(make_pair(b, it->Id)); + } + } + return out; +} + +void oCourse::setNumberMaps(int block) +{ + getDI().setInt("NumberMaps", block); +} + +int oCourse::getNumberMaps() const +{ + return getDCI().getInt("NumberMaps"); +} + +int oCourse::getNumUsedMaps(bool noVacant) const { + if (tMapsUsed == -1) + oe->calculateNumRemainingMaps(); + + if (noVacant) + return tMapsUsedNoVacant; + else + return tMapsUsed; +} + + +void oCourse::setStart(const string &start, bool sync) +{ + if (getDI().setString("StartName", start)) { + if (sync) + synchronize(); + oClassList::iterator it; + for (it=oe->Classes.begin();it!=oe->Classes.end();++it) { + if (it->getCourse()==this) { + it->setStart(start); + if (sync) + it->synchronize(); + } + } + } +} + +string oCourse::getStart() const +{ + return getDCI().getString("StartName"); +} + +void oEvent::calculateNumRemainingMaps() +{ + synchronizeList(oLCourseId, true, false); + synchronizeList(oLTeamId, false, false); + synchronizeList(oLRunnerId, false, true); + + for (oCourseList::iterator cit=Courses.begin(); + cit!=Courses.end();++cit) { + int numMaps = cit->getNumberMaps(); + if (numMaps == 0) + cit->tMapsRemaining = numeric_limits::min(); + else + cit->tMapsRemaining = numMaps; + + cit->tMapsUsed = 0; + cit->tMapsUsedNoVacant = 0; + } + + + for (oRunnerList::const_iterator it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && it->getStatus() != StatusDNS) { + pCourse pc = it->getCourse(false); + if (pc) { + if (pc->tMapsRemaining != numeric_limits::min()) + pc->tMapsRemaining--; + + pc->tMapsUsed++; + if (!it->isVacant()) + pc->tMapsUsedNoVacant++; + } + } + } + + // Count maps used for vacant team positions + + for (oTeamList::const_iterator it=Teams.begin(); it != Teams.end(); ++it) { + if (!it->isRemoved()/* && it->getStatus() != StatusDNS*/) { + for (size_t j = 0; j < it->Runners.size(); j++) { + pRunner r = it->Runners[j]; + if (r) + continue; // Already included + + if (it->Class) { + const vector &courses = it->Class->MultiCourse[j]; + if (courses.size()>0) { + int index = it->StartNo; + if (index > 0) + index = (index-1) % courses.size(); + pCourse tCrs = courses[index]; + if (tCrs) { + tCrs->tMapsUsed++; + + if (tCrs->tMapsRemaining != numeric_limits::min()) + tCrs->tMapsRemaining--; + } + } + } + } + } + } +} + +int oCourse::getIdSum(int nC) { + + int id = 0; + for (int k = 0; kgetId() : 0); + + if (id == 0) + return getId(); + + return id; +} + +void oCourse::setLegLengths(const vector &legs) { + if (legs.size() == nControls +1 || legs.empty()) { + bool diff = legs.size() != legLengths.size(); + if (!diff) { + for (size_t k = 0; k= legLengths.size() || + unsigned(end) >= legLengths.size() || Length==0) + return 0.0; + + int dist = 0; + for (int k = start; kdataRevision != cacheDataRevision) + clearCache(); + + if (size_t(controlIndex) < cachedControlOrdinal.size() && !cachedControlOrdinal[controlIndex].empty()) + return cachedControlOrdinal[controlIndex]; + + if (controlIndex > nControls) + throw meosException("Invalid index"); + cachedControlOrdinal.resize(nControls); + + int o = useFirstAsStart() ? 0 : 1; + bool rogaining = hasRogaining(); + + for (int k = 0; kisRogaining(rogaining)) + o++; + } + cachedControlOrdinal[controlIndex] = itos(o); + return cachedControlOrdinal[controlIndex]; +} + +void oCourse::setRogainingPointsPerMinute(int p) +{ + getDI().setInt("RReduction", p); +} + +int oCourse::getRogainingPointsPerMinute() const +{ + return getDCI().getInt("RReduction"); +} + +int oCourse::calculateReduction(int overTime) const +{ + int reduction = 0; + if (overTime > 0) { + int method = getDCI().getInt("RReductionMethod"); + if (method == 0) // Linear model + reduction = (59 + overTime * getRogainingPointsPerMinute()) / 60; + else // Time (minute) discrete model + reduction = ((59 + overTime) / 60) * getRogainingPointsPerMinute(); + } + return reduction; +} + + +void oCourse::setMinimumRogainingPoints(int p) +{ + cachedHasRogaining = 0; + getDI().setInt("RPointLimit", p); +} + +int oCourse::getMinimumRogainingPoints() const +{ + return getDCI().getInt("RPointLimit"); +} + +void oCourse::setMaximumRogainingTime(int p) +{ + cachedHasRogaining = 0; + if (p == NOTIME) + p = 0; + getDI().setInt("RTimeLimit", p); +} + +int oCourse::getMaximumRogainingTime() const +{ + return getDCI().getInt("RTimeLimit"); +} + +bool oCourse::hasRogaining() const { + if (oe->dataRevision != cacheDataRevision) + clearCache(); + + if (cachedHasRogaining>0) + return cachedHasRogaining == 2; + + bool r = getMaximumRogainingTime() > 0 || getMinimumRogainingPoints() > 0; + cachedHasRogaining = r ? 2 : 1; + return r; +} + +void oCourse::clearCache() const { + cachedHasRogaining = 0; + cachedControlOrdinal.clear(); + cacheDataRevision = oe->dataRevision; + tMapsUsed = -1; + tMapsUsedNoVacant = -1; +} + +string oCourse::getCourseProblems() const +{ + int max_time = getMaximumRogainingTime(); + int min_point = getMinimumRogainingPoints(); + + if (max_time > 0) { + for (int k = 0; kisRogaining(true)) + return ""; + } + return "Banan saknar rogainingkontroller."; + } + else if (min_point > 0) { + int max_p = 0; + for (int k = 0; kisRogaining(true)) + max_p += Controls[k]->getRogainingPoints(); + } + + if (max_p < min_point) { + return "Banans kontroller ger för få poäng för att täcka poängkravet."; + } + } + return ""; +} + +void oCourse::remove() +{ + if (oe) + oe->removeCourse(Id); +} + +bool oCourse::canRemove() const +{ + return !oe->isCourseUsed(Id); +} + +void oCourse::changeId(int newId) { + pCourse old = oe->courseIdIndex[Id]; + if (old == this) + oe->courseIdIndex.remove(Id); + + oBase::changeId(newId); + + oe->courseIdIndex[newId] = this; +} + +bool oCourse::useFirstAsStart() const { + return getDCI().getInt("FirstAsStart") != 0; +} + +bool oCourse::useLastAsFinish() const { + return getDCI().getInt("LastAsFinish") != 0; +} + +void oCourse::firstAsStart(bool f) { + getDI().setInt("FirstAsStart", f ? 1:0); +} + +void oCourse::lastAsFinish(bool f) { + getDI().setInt("LastAsFinish", f ? 1:0); +} + +int oCourse::getFinishPunchType() const { + if (useLastAsFinish() && nControls > 0) + return Controls[nControls - 1]->Numbers[0]; + else + return oPunch::PunchFinish; +} + +int oCourse::getStartPunchType() const { + if (useFirstAsStart() && nControls > 0) + return Controls[0]->Numbers[0]; + else + return oPunch::PunchStart; +} + +void oEvent::getCourses(vector &crs) const{ + crs.clear(); + for (oCourseList::const_iterator it = Courses.begin(); it != Courses.end(); ++it) { + if (it->isRemoved()) + continue; + crs.push_back(pCourse(&*it)); + } +} + +int oCourse::getCommonControl() const { + return getDCI().getInt("CControl"); +} + +void oCourse::setCommonControl(int ctrlId) { + if (ctrlId != 0) { + int found = 0; + for (int k = 0; k < nControls; k++) { + if (Controls[k]->getId() == ctrlId) + found++; + } + if (found == 0) + throw meosException("Kontroll X finns inte på banan#" + itos(ctrlId)); + } + getDI().setInt("CControl", ctrlId); +} + +pCourse oCourse::getAdapetedCourse(const oCard &card, oCourse &tmpCourse) const { + /*adaptedToOriginalCardOrder.resize(nControls + 1); + for (int k = 0; k < nControls + 1; k++) + adaptedToOriginalCardOrder[k] = k;*/ + int cc = getCommonControl(); + if (cc == 0) + return pCourse(this); + + vector ccIndex; + vector< vector > loopKeys; + if (!constructLoopKeys(cc, loopKeys, ccIndex)) + return pCourse(this); + + bool firstAsStart = ccIndex[0] == 0; + + vector< vector > punchSequence; + + vector punches; + card.getPunches(punches); + + punchSequence.push_back(vector()); + for (size_t k = 0; k < punches.size(); k++) { + int code = punches[k]->getTypeCode(); + if (code < 10) + continue; // Start, Finish etc. + if (code == cc && !punchSequence.back().empty()) + punchSequence.push_back(vector()); + else { + if (code != cc) + punchSequence.back().push_back(code); + } + } + + + map > > preferences; + for (size_t k = 0; k < punchSequence.size(); k++) { + for (size_t j = 0; j < loopKeys.size(); j++) { + int v = matchLoopKey(punchSequence[k], loopKeys[j]); + if (v < 1000) + preferences[v].push_back(make_pair(k, j)); + } + } + + vector assignedKeys(loopKeys.size(), -1); + vector usedPunches(punchSequence.size()); + int assigned = 0; + for (map > >::iterator it = preferences.begin(); it != preferences.end(); ++it) { + vector< pair > &bestMatches = it->second; + map > sortedBestMatches; + vector< pair > sortKey(loopKeys.size()); + for (size_t j = 0; j < bestMatches.size(); j++) { + int loopIndex = bestMatches[j].second; + sortKey[loopIndex].second = loopIndex; + ++sortKey[loopIndex].first; + sortedBestMatches[loopIndex].push_back(bestMatches[j].first); + } + + sort(sortKey.begin(), sortKey.end()); + + for (size_t j = 0; j < sortKey.size(); j++) { + if (sortKey[j].first == 0) + continue; + int loopIndex = sortKey[j].second; + if (assignedKeys[loopIndex] != -1) + continue; + vector &bm = sortedBestMatches[loopIndex]; + for (size_t k = 0; k < bm.size(); k++) { + if (usedPunches[bm[k]] == 0) { + usedPunches[bm[k]] = 1; + assignedKeys[loopIndex] = bm[k]; + assigned++; + break; + } + } + if (assigned == assignedKeys.size()) + break; + } + if (assigned == assignedKeys.size()) + break; + } + + + /*for (size_t k = 0; k < punchSequence.size(); k++) { + bool done = false; + for (size_t j = 0; j < loopKeys.size(); j++) { + if (assignedKeys[j] == -1 && matchLoopKey(punchSequence[k], loopKeys[j])) { + assignedKeys[j] = k; + done = true; + break; + } + } + if (!done) { + // Check if an already assigned key matches the current loop + int undone = -1; + size_t start = loopKeys.size(); + for (size_t j = 0; j < loopKeys.size(); j++) { + if (matchLoopKey(punchSequence[k], loopKeys[j])) { + // Push that key away and try it somewhere else + undone = assignedKeys[j]; + start = j + 1; + assignedKeys[j] = k; + done = true; + break; + } + } + + // Try an already assigned key later + for (size_t j = start; undone != -1 && j < loopKeys.size(); j++) { + if (matchLoopKey(punchSequence[undone], loopKeys[j])) { + swap(assignedKeys[j], undone); + } + } + } + }*/ + + //set loops; + //for (size_t k = 0; k < ccIndex.size(); k++) + // loops.insert(k); + vector loopOrder; + map keyToIndex; + assert(ccIndex.size() == assignedKeys.size()); + for (size_t k = 0; k < assignedKeys.size(); k++) { + if (assignedKeys[k] != -1) { + keyToIndex[assignedKeys[k]] = k; + } + } + + for (map::iterator it = keyToIndex.begin(); it != keyToIndex.end(); ++it) { + loopOrder.push_back(it->second); + } + + int checksum = (ccIndex.size() * (ccIndex.size()-1))/2; + + // Add remaining, unmatched, loops in defined order + for (size_t k = 0; k < ccIndex.size(); k++) { + if (assignedKeys[k] == -1) + loopOrder.push_back(k); + checksum-=loopOrder[k]; + } + assert(checksum == 0 && loopOrder.size() == ccIndex.size()); + + tmpCourse.cacheDataRevision = cacheDataRevision; + tmpCourse.cachedControlOrdinal.clear(); + tmpCourse.cachedHasRogaining = cachedHasRogaining; + memcpy(tmpCourse.oData, oData, sizeof(oData)); + tmpCourse.nControls = 0; + tmpCourse.Length = Length; + tmpCourse.Name = Name; + tmpCourse.sqlUpdated = "TMP"; // Mark as tmp to prevent accidental write to DB + tmpCourse.tMapToOriginalOrder.clear(); + tmpCourse.tMapToOriginalOrder.reserve(nControls+1); + + if (firstAsStart) { + tmpCourse.tMapToOriginalOrder.push_back(0); + tmpCourse.Controls[tmpCourse.nControls++] = Controls[0]; + if (0 < legLengths.size()) + tmpCourse.legLengths.push_back(legLengths[0]); + } + + + bool lastAsFinish = useLastAsFinish() || Controls[nControls-1]->getId() == cc; + + int endIx = lastAsFinish ? nControls - 1 : nControls; + + for (size_t k = 0; k< loopOrder.size(); k++) { + int start = ccIndex[loopOrder[k]]; + int end = size_t(loopOrder[k] + 1) < ccIndex.size() ? ccIndex[loopOrder[k] + 1] : endIx; + for (int i = start + 1; i < end; i++) { + tmpCourse.tMapToOriginalOrder.push_back(i); + tmpCourse.Controls[tmpCourse.nControls++] = Controls[i]; + if (size_t(i) < legLengths.size()) + tmpCourse.legLengths.push_back(legLengths[i]); + } + tmpCourse.tMapToOriginalOrder.push_back(end); + if (k + 1 < loopOrder.size()) { + int currentCC = ccIndex[k+1]; + //tmpCourse.tMapToOriginalOrder.push_back(currentCC); + tmpCourse.Controls[tmpCourse.nControls++] = Controls[currentCC]; + if (size_t(end) < legLengths.size()) + tmpCourse.legLengths.push_back(legLengths[end]); + } + } + + if (lastAsFinish) { + //tmpCourse.tMapToOriginalOrder.push_back(nControls - 1); + tmpCourse.tMapToOriginalOrder.push_back(nControls); + tmpCourse.Controls[tmpCourse.nControls++] = Controls[nControls - 1]; + if (size_t(nControls-1) < legLengths.size()) + tmpCourse.legLengths.push_back(legLengths[nControls-1]); + } + + //tmpCourse.tMapToOriginalOrder.push_back(nControls); + + assert(tmpCourse.nControls == nControls); + assert(tmpCourse.tMapToOriginalOrder.size() == nControls + 1); + + if (!legLengths.empty()) { + tmpCourse.legLengths.push_back(legLengths.back()); + assert(tmpCourse.legLengths.size() == legLengths.size()); + } + tmpCourse.Id = Id; + return &tmpCourse; +} + +bool oCourse::isAdapted() const { + return tMapToOriginalOrder.size() > 0; +} + +int oCourse::getAdaptionId() const { + int key = 0; + for (size_t j = 0; j < tMapToOriginalOrder.size(); j++) + key = key * 97 + tMapToOriginalOrder[j]; + return key; +} + +int oCourse::matchLoopKey(const vector &punches, const vector &key) { + if (key.empty()) + return 999; + size_t ix = -1; + for (size_t k = 0; k < key.size(); k++) { + int code = key[k]->getFirstNumber(); + while (++ix < punches.size()) { + if (punches[ix] == code) { + code = -1; + break; + } + } + if (code != -1) + return 1000; + } + return ix; +} + +bool oCourse::constructLoopKeys(int cc, vector< vector > &loopKeys, vector &ccIndex) const { + bool firstAsStart = useFirstAsStart(); + if (firstAsStart) { // Only if it is a unique control + for (int k = 1; k < nControls; k++) { + if (Controls[k] == Controls[0]) { + firstAsStart = false; + break; + } + } + } + + if (Controls[0]->getId() == cc) + firstAsStart = true; // Handle a course that starts with the loop control + + bool lastAsFinish = useLastAsFinish(); + if (lastAsFinish) { // Only if it is a unique control + for (int k = 0; k < nControls - 1; k++) { + if (Controls[k] == Controls[nControls-1]) { + lastAsFinish = false; + break; + } + } + } + + int startIx = firstAsStart ? 1 : 0; + int endIx = lastAsFinish ? nControls : nControls-1; + + ccIndex.push_back(startIx-1); + for (int k = startIx; k < endIx; k++) { + if (Controls[k]->getId() == cc) + ccIndex.push_back(k); + } + if (ccIndex.size() <= 1) + return false; + + loopKeys.clear(); + loopKeys.resize(ccIndex.size()); + + int keyIndex = 1; + bool changed = true; + bool enough = false; + while(changed && !enough) { + changed = false; + for (size_t k = 0; k < ccIndex.size(); k++) { + int keyIx = ccIndex[k] + keyIndex; + int nextIx = (k + 1) < ccIndex.size() ? ccIndex[k+1] : nControls; + if (keyIx < nextIx && Controls[keyIx]->isSingleStatusOK() && Controls[keyIx]->nNumbers == 1) { + loopKeys[k].push_back(Controls[keyIx]); + changed = true; + } + } + keyIndex++; + if (changed) { + enough = false; + set<__int64> hashes; + for (size_t k = 0; k < loopKeys.size(); k++) { + __int64 h = loopKeys[k].size(); + for (size_t j = 0; j < loopKeys[k].size(); j++) { + h = h * 997 + loopKeys[k][j]->Numbers[0]; + } + hashes.insert(h); + } + enough = hashes.size() == loopKeys.size(); + } + } + + return enough; +} + +void oCourse::changedObject() { + if (oe) + oe->globalModification = true; +} + +int oCourse::getCourseControlId(int controlIx) const { + if (controlIx >= nControls) { + assert(false); + return -1; + } + + int id = Controls[controlIx] ? Controls[controlIx]->getId() : 0; + if (id == 0) + return 0; + + int count = 0; + for (int j = 0; j < controlIx; j++) { + if (Controls[j] && Controls[j]->Id == id) + count++; + } + + return oControl::getCourseControlIdFromIdIndex(id, count); +} + +string oCourse::getRadioName(int courseControlId) const { + pair idix = oControl::getIdIndexFromCourseControlId(courseControlId); + pControl pc = 0; + int numRadio = 0; + int clsix = 1; + for (int k = 0; k < nControls; k++) { + if (Controls[k]) { + if (Controls[k]->isValidRadio()) + numRadio++; + + if (Controls[k]->Id == idix.first) { + if (idix.second == 0) { + pc = Controls[k]; + break; + } + else { + clsix++; + idix.second--; + } + } + } + } + + if (pc == 0) + return "?"; + + string name; + if (pc->hasName()) { + name = pc->getName(); + if (pc->getNumberDuplicates() > 1) + name += MakeDash("-" + itos(clsix)); + } + else { + name = lang.tl("radio X#" + itos(numRadio)); + capitalize(name); + } + + return name; +} + +// Returns the next shorter course, if any, null otherwise +pCourse oCourse::getShorterVersion() const { + int ix = getDCI().getInt("Shorten"); + return oe->getCourse(ix); +} + +// Returns the next longer course, if any, null otherwise. Note that this method is slow. +pCourse oCourse::getLongerVersion() const { + oCourseList::const_iterator it; + for (it = oe->Courses.begin(); it != oe->Courses.end(); ++it) { + int ix = it->getDCI().getInt("Shorten"); + if (ix == Id) + return pCourse(&*it); + } + return 0; +} + +void oCourse::setShorterVersion(pCourse shorten) { + if (shorten != 0) + getDI().setInt("Shorten", shorten->getId()); + else + getDI().setInt("Shorten", 0); +} + +bool oCourse::hasControl(const oControl *ctrl) const { + for (int i = 0; i < nControls; i++) { + if (Controls[i] == ctrl) + return true; + } + return false; +} + +void oCourse::getClasses(vector &usageClass) const { + vector cls; + oe->getClasses(cls, false); + + for (size_t k = 0; k < cls.size(); k++) { + if (cls[k]->usesCourse(*this)) + usageClass.push_back(cls[k]); + } +} + diff --git a/code/oCourse.h b/code/oCourse.h new file mode 100644 index 0000000..b5490cb --- /dev/null +++ b/code/oCourse.h @@ -0,0 +1,239 @@ +// oCourse.h: interface for the oCourse class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OCOURSE_H__936E61C9_CDAC_490D_A475_E58190A2910C__INCLUDED_) +#define AFX_OCOURSE_H__936E61C9_CDAC_490D_A475_E58190A2910C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "oControl.h" +#include +class oEvent; +class oCourse; +class oClass; +typedef oCourse * pCourse; +typedef oClass * pClass; +class oCard; + +class gdioutput; +class oDataInterface; + +struct SICard; + +const int NControlsMax = 128; + +class oCourse : public oBase +{ +private: + // Return 1000 on no match. Lower return value means better match + static int matchLoopKey(const vector &punches, const vector &key); +protected: + pControl Controls[NControlsMax]; + + int nControls; + string Name; + int Length; + static const int dataSize = 128; + int getDISize() const {return dataSize;} + + BYTE oData[dataSize]; + BYTE oDataOld[dataSize]; + + // Length of each leg, Start-1, 1-2,... N-Finish. + vector legLengths; + + int tMapsRemaining; + mutable int tMapsUsed; + mutable int tMapsUsedNoVacant; + + // Get an identity sum based on controls + int getIdSum(int nControls); + + /// Add an control without update + pControl doAddControl(int Id); + + void changeId(int newId); + + // Caching. + mutable vector cachedControlOrdinal; + mutable int cachedHasRogaining; + mutable int cacheDataRevision; + void clearCache() const; + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + // For adapted courses; + vector tMapToOriginalOrder; + + void changedObject(); + +public: + + void getClasses(vector &usageClass) const; + + void remove(); + bool canRemove() const; + + string getRadioName(int courseControlId) const; + + bool hasControl(const oControl *ctrl) const; + + /// Returns course specific id for specified control (taking duplicats of the control into account) + int getCourseControlId(int controlIx) const; + + bool useFirstAsStart() const; + bool useLastAsFinish() const; + + void firstAsStart(bool f); + void lastAsFinish(bool f); + + int getFinishPunchType() const; + int getStartPunchType() const; + + int getCommonControl() const; + void setCommonControl(int ctrlId); + + bool operator<(const oCourse &b) const {return Name &getMapToOriginalOrder() const {return tMapToOriginalOrder;} + + // Returns a unique key for this variant + int getAdaptionId() const; + + // Constuct loop keys of controls. CC is the common control + bool constructLoopKeys(int commonControls, vector< vector > &loopKeys, vector &commonControlIndex) const; + + /// Check if course has problems + string getCourseProblems() const; + + int getNumControls() const {return nControls;} + void setLegLengths(const vector &legLengths); + + // Get/set the minimal number of rogaining points to pass + int getMinimumRogainingPoints() const; + void setMinimumRogainingPoints(int p); + + // Get/set the maximal time allowed for rogaining + int getMaximumRogainingTime() const; + void setMaximumRogainingTime(int t); + + // Rogaining: point lost per minute over maximal time + int getRogainingPointsPerMinute() const; + void setRogainingPointsPerMinute(int t); + + // Calculate point reduction given a over time (in seconds) + int calculateReduction(int overTime) const; + + /// Return true if the course has rogaining + bool hasRogaining() const; + + // Get the control number as "printed on map". Do not count + // rogaining controls + const string &getControlOrdinal(int controlIndex) const; + + /** Get the part of the course between the start and end. Use start = 0 for the + start of the course, and end = 0 for the finish. Returns 0 if fraction + cannot be determined */ + double getPartOfCourse(int start, int end) const; + + string getInfo() const; + + oControl *getControl(int index) const; + + /** Return the distance between the course and the card. + Positive return = extra controls + Negative return = missing controls + Zero return = exact match */ + int distance(const SICard &card); + + bool fillCourse(gdioutput &gdi, const string &name); + + /** Returns true if changed. */ + bool importControls(const string &cstring, bool updateLegLengths); + void importLegLengths(const string &legs, bool setChanged); + + /** Returns the length of the i:th leg (or 0 if unknown)*/ + int getLegLength(int i) const; + + static void splitControls(const string &ctrls, vector &nr); + + pControl addControl(int Id); + void Set(const xmlobject *xo); + + void getControls(vector &pc); + string getControls() const; + string getLegLengths() const; + + string getControlsUI() const; + vector getCourseReadable(int limit) const; + + const string &getName() const {return Name;} + int getLength() const {return Length;} + string getLengthS() const; + + void setName(const string &n); + void setLength(int l); + + string getStart() const; + void setStart(const string &start, bool sync); + + bool Write(xmlparser &xml); + + oCourse(oEvent *poe, int id); + oCourse(oEvent *poe); + virtual ~oCourse(); + + friend class oEvent; + friend class oClass; + friend class oRunner; + friend class MeosSQL; +}; + +#endif // !defined(AFX_OCOURSE_H__936E61C9_CDAC_490D_A475_E58190A2910C__INCLUDED_) diff --git a/code/oDataContainer.cpp b/code/oDataContainer.cpp new file mode 100644 index 0000000..6c74e8e --- /dev/null +++ b/code/oDataContainer.cpp @@ -0,0 +1,1323 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include +#include "oDataContainer.h" +#include "oEvent.h" + +#include "gdioutput.h" +#include "xmlparser.h" +#include "Table.h" +#include "meos_util.h" +#include "Localizer.h" +#include "meosException.h" + +oDataContainer::oDataContainer(int maxsize) { + dataPointer = 0; + dataMaxSize = maxsize; + stringIndexPointer = 0; + stringArrayIndexPointer = 2; +} + +oDataContainer::~oDataContainer(void) { +} + +oDataInfo::oDataInfo() { + memset(Name, 0, sizeof(Name)); + Index = 0; + Size = 0; + Type = 0; + SubType = 0; + tableIndex = 0; + decimalSize = 0; + decimalScale = 1; + dataDefiner = 0; + zeroSortPadding = 0; + memset(Description, 0, sizeof(Description)); +} + +oDataInfo::~oDataInfo() { +} + +oDataInfo &oDataContainer::addVariableInt(const char *name, + oIntSize isize, const char *description, + const oDataDefiner *dataDef) { + oDataInfo odi; + odi.dataDefiner = dataDef; + odi.Index=dataPointer; + strcpy_s(odi.Name, name); + strcpy_s(odi.Description, description); + + if (isize == oIS64) + odi.Size=sizeof(__int64); + else + odi.Size=sizeof(int); + + odi.Type=oDTInt; + odi.SubType=isize; + + if (dataPointer+odi.Size<=dataMaxSize){ + dataPointer+=odi.Size; + return addVariable(odi); + } + else + throw std::exception("oDataContainer: Out of bounds."); +} + +oDataInfo &oDataContainer::addVariableDecimal(const char *name, const char *descr, int fixedDeci) { + oDataInfo &odi = addVariableInt(name, oISDecimal, descr); + odi.decimalSize = fixedDeci; + int &s = odi.decimalScale; + s = 1; + for (int k = 0; k < fixedDeci; k++) + s*=10; + + return odi; +} + +oDataInfo &oDataContainer::addVariableString(const char *name, const char *descr, const oDataDefiner *dataDef) { + return addVariableString(name, -1, descr, dataDef); +} + +oDataInfo &oDataContainer::addVariableString(const char *name, int maxChar, + const char *descr, const oDataDefiner *dataDef) +{ + oDataInfo odi; + odi.dataDefiner = dataDef; + strcpy_s(odi.Name,name); + strcpy_s(odi.Description,descr); + if (maxChar > 0) { + odi.Index = dataPointer; + odi.Size = maxChar+1; + odi.Type = oDTString; + odi.SubType = oSSString; + + if (dataPointer+odi.Size<=dataMaxSize){ + dataPointer+=odi.Size; + return addVariable(odi); + } + else + throw std::exception("oDataContainer: Out of bounds."); + } + else { + odi.Index = stringIndexPointer++; + odi.Size = 0; + odi.Type = oDTStringDynamic; + odi.SubType = oSSString; + return addVariable(odi); + } +} + + + +oDataInfo &oDataContainer::addVariableEnum(const char *name, int maxChar, const char *descr, + const vector< pair > enumValues) { + oDataInfo &odi = addVariableString(name, maxChar, descr); + odi.SubType = oSSEnum; + for (size_t k = 0; k::iterator it=index.find(Name); + + if (it == index.end()) + return 0; + else return &(it->second); + + return 0;*/ + int res; + if (index.lookup(hash(name), res)) { + return &ordered[res]; + } + return 0; + +} + + + +const oDataInfo *oDataContainer::findVariable(const char *name) const +{ + if (name == 0) + return 0; + /*map::const_iterator it=index.find(Name); + + if (it == index.end()) + return 0; + else return &(it->second); + */ + int res; + if (index.lookup(hash(name), res)) { + return &ordered[res]; + } + return 0; +} + +void oDataContainer::initData(oBase *ob, int datasize) { + if (datasize > *strptr; + ob->getDataBuffers(data, oldData, strptr); + memset(data, 0, dataPointer); + memset(oldData, 0, dataPointer); + + if (stringIndexPointer > 0 || stringArrayIndexPointer>2) { + vector< vector > &str = *strptr; + str.clear(); + str.resize(stringArrayIndexPointer); + str[0].resize(stringIndexPointer); + str[1].resize(stringIndexPointer); + } +} + +bool oDataContainer::setInt(void *data, const char *Name, int V) +{ + oDataInfo *odi=findVariable(Name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type!=oDTInt) + throw std::exception("oDataContainer: Variable of wrong type."); + + if (odi->SubType == oIS64) + throw std::exception("oDataContainer: Variable to large."); + + LPBYTE vd=LPBYTE(data)+odi->Index; + if (*((int *)vd)!=V){ + *((int *)vd)=V; + return true; + } + else return false;//Not modified +} + +bool oDataContainer::setInt64(void *data, const char *Name, __int64 V) +{ + oDataInfo *odi=findVariable(Name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type!=oDTInt) + throw std::exception("oDataContainer: Variable of wrong type."); + + if (odi->SubType != oIS64) + throw std::exception("oDataContainer: Variable to large."); + + LPBYTE vd=LPBYTE(data)+odi->Index; + if (*((__int64 *)vd)!=V){ + *((__int64 *)vd)=V; + return true; + } + else return false;//Not modified +} + +int oDataContainer::getInt(const void *data, const char *Name) const +{ + const oDataInfo *odi=findVariable(Name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type!=oDTInt) + throw std::exception("oDataContainer: Variable of wrong type."); + + if (odi->SubType == oIS64) + throw std::exception("oDataContainer: Variable to large."); + + LPBYTE vd=LPBYTE(data)+odi->Index; + return *((int *)vd); +} + +__int64 oDataContainer::getInt64(const void *data, const char *Name) const +{ + const oDataInfo *odi=findVariable(Name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type!=oDTInt) + throw std::exception("oDataContainer: Variable of wrong type."); + + LPBYTE vd=LPBYTE(data)+odi->Index; + + if (odi->SubType == oIS64) + return *((__int64 *)vd); + else { + int tmp = *((int *)vd); + return tmp; + } +} + + +bool oDataContainer::setString(oBase *ob, const char *name, const string &V) +{ + oDataInfo *odi=findVariable(name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + if (odi->Type == oDTString) { + LPBYTE vd=LPBYTE(data)+odi->Index; + + if (strcmp((char *)vd, V.c_str())!=0){ + strncpy_s((char *)vd, odi->Size, V.c_str(), odi->Size-1); + return true; + } + else return false;//Not modified + } + else if (odi->Type == oDTStringDynamic) { + string &str = (*strptr)[0][odi->Index]; + if (str == V) + return false; // Same string + + str = V; + return true; + } + else + throw std::exception("oDataContainer: Variable of wrong type."); + +} + +const string &oDataContainer::getString(const oBase *ob, const char *Name) const { + const oDataInfo *odi=findVariable(Name); + + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type == oDTString) { + LPBYTE vd=LPBYTE(data)+odi->Index; + string &res = StringCache::getInstance().get(); + res = (char *) vd; + return res; + } + else if (odi->Type == oDTStringDynamic) { + string &str = (*strptr)[0][odi->Index]; + return str; + } + else + throw std::exception("oDataContainer: Variable of wrong type."); +} + + +bool oDataContainer::setDate(void *data, const char *Name, const string &V) +{ + oDataInfo *odi=findVariable(Name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type!=oDTInt) + throw std::exception("oDataContainer: Variable of wrong type."); + + int year=0,month=0,day=0; + + sscanf_s(V.c_str(), "%d-%d-%d", &year, &month, &day); + + int C=year*10000+month*100+day; + + + LPBYTE vd=LPBYTE(data)+odi->Index; + if (*((int *)vd)!=C){ + *((int *)vd)=C; + return true; + } + else return false;//Not modified +} + +const string &oDataContainer::getDate(const void *data, + const char *Name) const +{ + const oDataInfo *odi=findVariable(Name); + + if (!odi) + throw std::exception("oDataContainer: Variable not found."); + + if (odi->Type!=oDTInt) + throw std::exception("oDataContainer: Variable of wrong type."); + + LPBYTE vd=LPBYTE(data)+odi->Index; + int C=*((int *)vd); + + char bf[24]; + if (C%10000!=0 || C==0) + sprintf_s(bf, "%04d-%02d-%02d", C/10000, (C/100)%100, C%100); + else + sprintf_s(bf, "%04d", C/10000); + + string &res = StringCache::getInstance().get(); + res = bf; + return res; +} + +bool oDataContainer::write(const oBase *ob, xmlparser &xml) const { + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + xml.startTag("oData"); + + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + if (di.Type==oDTInt){ + LPBYTE vd=LPBYTE(data)+di.Index; + if (di.SubType != oIS64) { + int nr; + memcpy(&nr, vd, sizeof(int)); + xml.write(di.Name, nr); + } + else { + __int64 nr; + memcpy(&nr, vd, sizeof(__int64)); + xml.write64(di.Name, nr); + } + } + else if (di.Type == oDTString){ + LPBYTE vd=LPBYTE(data)+di.Index; + xml.write(di.Name, (char *)vd); + } + else if (di.Type == oDTStringDynamic) { + const string &str = (*strptr)[0][di.Index]; + xml.write(di.Name, str); + } + } + + xml.endTag(); + + return true; +} + +void oDataContainer::set(oBase *ob, const xmlobject &xo) { + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + + oDataInfo *odi=findVariable(it->getName()); + + if (odi) { + if (odi->Type == oDTInt){ + LPBYTE vd=LPBYTE(data)+odi->Index; + if (odi->SubType != oIS64) + *((int *)vd) = it->getInt(); + else + *((__int64 *)vd) = it->getInt64(); + } + else if (odi->Type == oDTString) { + LPBYTE vd=LPBYTE(data)+odi->Index; + strncpy_s((char *)vd, odi->Size, it->get(), odi->Size-1); + } + else if (odi->Type == oDTStringDynamic) { + string &str = (*strptr)[0][odi->Index]; + str = it->get(); + } + } + } + + allDataStored(ob); +} + +void oDataContainer::buildDataFields(gdioutput &gdi) const +{ + vector fields; + for (size_t k = 0; k < ordered.size(); k++) + fields.push_back(ordered[k].Name); + + buildDataFields(gdi, fields); +} + +void oDataContainer::buildDataFields(gdioutput &gdi, const vector &fields) const +{ + for (size_t k=0;k::const_iterator it=index.find(fields[k]); + const oDataInfo *odi = findVariable(fields[k].c_str()); + + //if (it==index.end()) + if (odi == 0) + throw std::exception( ("Bad key: " + fields[k]).c_str()); + + const oDataInfo &di=*odi; + string Id=di.Name+string("_odc"); + + if (di.Type==oDTInt){ + if (di.SubType == oISDate || di.SubType == oISTime) + gdi.addInput(Id, "", 10, 0, string(di.Description) + ":"); + else + gdi.addInput(Id, "", 6, 0, string(di.Description) + ":"); + } + else if (di.Type==oDTString){ + gdi.addInput(Id, "", min(di.Size+2, 30), 0, string(di.Description) +":"); + } + else if (di.Type==oDTStringDynamic){ + gdi.addInput(Id, "", 30, 0, string(di.Description) +":"); + } + } +} + +int oDataContainer::getDataAmountMeasure(const void *data) const +{ + int amount = 0; + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + if (di.Type==oDTInt) { + LPBYTE vd=LPBYTE(data)+di.Index; + int nr; + memcpy(&nr, vd, sizeof(int)); + if (nr != 0) + amount++; + } + else if (di.Type==oDTString) { + LPBYTE vd=LPBYTE(data)+di.Index; + amount += strlen((char *)vd); + } + + } + return amount; +} + +void oDataContainer::fillDataFields(const oBase *ob, gdioutput &gdi) const +{ + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + + string Id=di.Name+string("_odc"); + if (di.Type==oDTInt){ + LPBYTE vd=LPBYTE(data)+di.Index; + + if (di.SubType != oIS64) { + int nr; + memcpy(&nr, vd, sizeof(int)); + if (di.SubType == oISCurrency) { + if (strcmp(di.Name, "CardFee") == 0 && nr == -1) + nr = 0; //XXX CardFee hack. CardFee = 0 is coded as -1 + gdi.setText(Id.c_str(), ob->getEvent()->formatCurrency(nr)); + } + else { + char bf[64]; + formatNumber(nr, di, bf); + gdi.setText(Id.c_str(), bf); + } + } + else { + __int64 nr; + memcpy(&nr, vd, sizeof(__int64)); + char bf[16]; + oBase::converExtIdentifierString(nr, bf); + gdi.setText(Id.c_str(), bf); + } + } + else if (di.Type==oDTString){ + LPBYTE vd=LPBYTE(data)+di.Index; + gdi.setText(Id.c_str(), (char *)vd); + } + else if (di.Type==oDTStringDynamic){ + const string &str = (*strptr)[0][di.Index]; + gdi.setText(Id.c_str(), str); + } + } +} + +bool oDataContainer::saveDataFields(oBase *ob, gdioutput &gdi) { + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + + string Id=di.Name+string("_odc"); + + if (!gdi.hasField(Id)) { + continue; + } + if (di.Type==oDTInt){ + int no = 0; + if (di.SubType == oISCurrency) { + no = ob->getEvent()->interpretCurrency(gdi.getText(Id.c_str())); + } + else if (di.SubType == oISDate) { + no = convertDateYMS(gdi.getText(Id.c_str()), true); + } + else if (di.SubType == oISTime) { + no = convertAbsoluteTimeHMS(gdi.getText(Id.c_str()), -1); + } + else if (di.SubType == oISDecimal) { + string str = gdi.getText(Id.c_str()); + for (size_t k = 0; k < str.length(); k++) { + if (str[k] == ',') { + str[k] = '.'; + break; + } + } + double val = atof(str.c_str()); + no = int(di.decimalScale * val); + } + else { + no = gdi.getTextNo(Id.c_str()); + } + + LPBYTE vd=LPBYTE(data)+di.Index; + int oldNo = *((int *)vd); + if (oldNo != no) { + *((int *)vd)=no; + ob->updateChanged(); + } + } + else if (di.Type == oDTString) { + LPBYTE vd=LPBYTE(data)+di.Index; + string oldS = (char *)vd; + string newS = gdi.getText(Id.c_str()); + if (oldS != newS) { + strncpy_s((char *)vd, di.Size, newS.c_str(), di.Size-1); + ob->updateChanged(); + } + } + else if (di.Type == oDTStringDynamic) { + string &oldS = (*strptr)[0][di.Index]; + string newS = gdi.getText(Id.c_str()); + if (oldS != newS) { + oldS = newS; + ob->updateChanged(); + } + } + } + + return true; +} + +string oDataContainer::C_INT64(const string &name) +{ + return " "+name+" BIGINT NOT NULL DEFAULT 0, "; +} + +string oDataContainer::C_INT(const string &name) +{ + return " "+name+" INT NOT NULL DEFAULT 0, "; +} + +string oDataContainer::C_SMALLINT(const string &name) +{ + return " "+name+" SMALLINT NOT NULL DEFAULT 0, "; +} + +string oDataContainer::C_TINYINT(const string &name) +{ + return " "+name+" TINYINT NOT NULL DEFAULT 0, "; +} + +string oDataContainer::C_SMALLINTU(const string &name) +{ + return " "+name+" SMALLINT UNSIGNED NOT NULL DEFAULT 0, "; +} + +string oDataContainer::C_TINYINTU(const string &name) +{ + return " "+name+" TINYINT UNSIGNED NOT NULL DEFAULT 0, "; +} + +string oDataContainer::C_STRING(const string &name, int len) +{ + if (len>0) { + char bf[16]; + sprintf_s(bf, "%d", len); + return " "+name+" VARCHAR("+ bf +") NOT NULL DEFAULT '', "; + } + else { + return " "+name+" MEDIUMTEXT NOT NULL, "; + } +} + +string oDataContainer::SQL_quote(const char *in) +{ + char out[256]; + int o=0; + + while(*in && o<250){ + if (*in=='\'') + out[o++]='\''; + if (*in=='\\') + out[o++]='\\'; + out[o++]=*in; + + in++; + } + out[o]=0; + + return out; +} + +string oDataContainer::generateSQLDefinition(const std::set &exclude) const { + string sql; + bool addSyntx = !exclude.empty(); + + for (size_t k = 0; k < ordered.size(); k++) { + if (exclude.count(ordered[k].Name) == 0) { + if (addSyntx) + sql += "ADD COLUMN "; + + const oDataInfo &di = ordered[k]; + string name = di.Name; + if (di.Type==oDTInt){ + if (di.SubType==oIS32 || di.SubType==oISDate || di.SubType==oISCurrency || + di.SubType==oISTime || di.SubType==oISDecimal) + sql+=C_INT(name); + else if (di.SubType==oIS16) + sql+=C_SMALLINT(name); + else if (di.SubType==oIS8) + sql+=C_TINYINT(name); + else if (di.SubType==oIS64) + sql+=C_INT64(name); + else if (di.SubType==oIS16U) + sql+=C_SMALLINTU(name); + else if (di.SubType==oIS8U) + sql+=C_TINYINTU(name); + } + else if (di.Type==oDTString){ + sql+=C_STRING(name, di.Size-1); + } + else if (di.Type==oDTStringDynamic || di.Type==oDTStringArray){ + sql+=C_STRING(name, -1); + } + } + } + + if (addSyntx && !sql.empty()) + return sql.substr(0, sql.length() - 2); //Remove trailing comma-space + else + return sql; +} + +bool oDataContainer::isModified(const oDataInfo &di, + const void *data, + const void *oldData, + vector< vector > *strptr) const { + + if (di.Type == oDTInt) { + LPBYTE vd=LPBYTE(data)+di.Index; + LPBYTE vdOld=LPBYTE(oldData)+di.Index; + if (di.SubType != oIS64) { + return memcmp(vd, vdOld, 4) != 0; + } + else { + return memcmp(vd, vdOld, 8) != 0; + } + } + else if (di.Type == oDTString){ + char * vd=(char *)(data)+di.Index; + char * vdOld=(char *)(oldData)+di.Index; + return strcmp(vd, vdOld) != 0; + } + else if (di.Type == oDTStringDynamic){ + const string &newS = (*strptr)[0][di.Index]; + const string &oldS = (*strptr)[1][di.Index]; + return newS != oldS; + } + else if (di.Type == oDTStringArray){ + const vector &newS = (*strptr)[di.Index]; + const vector &oldS = (*strptr)[di.Index+1]; + return newS != oldS; + } + else + return true; +} + +void oDataContainer::allDataStored(const oBase *ob) { + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + memcpy(oldData, data, ob->getDISize()); + if (stringIndexPointer > 0 || stringArrayIndexPointer > 2) { + for (size_t k = 0; k < stringArrayIndexPointer; k+=2) { + (*strptr)[k+1] = (*strptr)[k]; + } + } +} + +string oDataContainer::generateSQLSet(const oBase *ob, bool forceSetAll) const { + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + string sql; + char bf[256]; + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + + if (!forceSetAll && !isModified(di, data, oldData, strptr)) { + continue; + } + + if (di.Type==oDTInt) { + LPBYTE vd=LPBYTE(data)+di.Index; + if (di.SubType == oIS8U) { + sprintf_s(bf, ", %s=%u", di.Name, (*((int *)vd))&0xFF); + sql+=bf; + } + else if (di.SubType == oIS16U) { + sprintf_s(bf, ", %s=%u", di.Name, (*((int *)vd))&0xFFFF); + sql+=bf; + } + else if (di.SubType == oIS8) { + char r = (*((int *)vd))&0xFF; + sprintf_s(bf, ", %s=%d", di.Name, (int)r); + sql+=bf; + } + else if (di.SubType == oIS16) { + short r = (*((int *)vd))&0xFFFF; + sprintf_s(bf, ", %s=%d", di.Name, (int)r); + sql+=bf; + } + else if (di.SubType != oIS64) { + sprintf_s(bf, ", %s=%d", di.Name, *((int *)vd)); + sql+=bf; + } + else { + char tmp[32]; + _i64toa_s(*((__int64 *)vd), tmp, 32, 10); + sprintf_s(bf, ", %s=%s", di.Name, tmp); + sql+=bf; + } + } + else if (di.Type==oDTString) { + LPBYTE vd=LPBYTE(data)+di.Index; + sprintf_s(bf, ", %s='%s'", di.Name, SQL_quote((char *)vd).c_str()); + sql+=bf; + } + else if (di.Type==oDTStringDynamic) { + const string &str = (*strptr)[0][di.Index]; + sprintf_s(bf, ", %s='%s'", di.Name, SQL_quote(str.c_str()).c_str()); + sql+=bf; + } + else if (di.Type==oDTStringArray) { + const string str = encodeArray((*strptr)[di.Index]); + sprintf_s(bf, ", %s='%s'", di.Name, SQL_quote(str.c_str()).c_str()); + sql+=bf; + } + } + return sql; +} + + +void oDataContainer::getVariableInt(const void *data, + list &var) const { + var.clear(); + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + + if (di.Type == oDTInt) { + LPBYTE vd=LPBYTE(data)+di.Index; + + oVariableInt vi; + memcpy(vi.name, di.Name, sizeof(vi.name)); + if (di.SubType != oIS64) + vi.data32 = (int *)vd; + else + vi.data64 = (__int64 *)vd; + var.push_back(vi); + } + } +} + + +void oDataContainer::getVariableString(const oBase *ob, + list &var) const +{ + void *data, *oldData; + vector< vector > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + var.clear(); + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + + if (di.Type == oDTString){ + char * vd=(char *)(data)+di.Index; + + oVariableString vs(vd, di.Size); + memcpy(vs.name, di.Name, sizeof(vs.name)); + var.push_back(vs); + } + else if (di.Type == oDTStringDynamic) { + oVariableString vs((*strptr)[0], di.Index); + memcpy(vs.name, di.Name, sizeof(vs.name)); + var.push_back(vs); + } + else if (di.Type == oDTStringArray) { + oVariableString vs((*strptr)[di.Index]); + memcpy(vs.name, di.Name, sizeof(vs.name)); + var.push_back(vs); + } + } +} + +oDataInterface oDataContainer::getInterface(void *data, int datasize, oBase *ob) +{ + if (datasizeaddTableColumn(table, di.Description, w); + } + else if (di.Type == oDTInt) { + bool right = di.SubType == oISCurrency; + bool numeric = di.SubType != oISDate && di.SubType != oISTime; + int w; + if (di.SubType == oISDecimal) + w = max( (di.decimalSize+4)*10, 70); + else + w = 70; + + w = max(int(strlen(di.Description))*6, w); + di.tableIndex = table->addColumn(di.Description, w, numeric, right); + } + else if (di.Type == oDTString) { + int w = max(max(di.Size+1, int(strlen(di.Description)))*6, 70); + + for (size_t k = 0; k < di.enumDescription.size(); k++) + w = max(w, lang.tl(di.enumDescription[k].second).length() * 6); + + if (di.zeroSortPadding) + di.tableIndex = table->addColumnPaddedSort(di.Description, w, di.zeroSortPadding, true); + + else + di.tableIndex = table->addColumn(di.Description, w, false); + + } + else if (di.Type == oDTStringDynamic) { + int w = 64*6; + di.tableIndex = table->addColumn(di.Description, w, false); + } + } +} + +bool oDataContainer::formatNumber(int nr, const oDataInfo &di, char bf[64]) const { + if (di.SubType == oISDate) { + if (nr>0) { + sprintf_s(bf, 64, "%d-%02d-%02d", nr/(100*100), (nr/100)%100, nr%100); + } + else { + bf[0] = '-'; + bf[1] = 0; + } + return true; + } + else if (di.SubType == oISTime) { + if (nr>0 && nr<(30*24*3600)) { + if (nr < 24*3600) + sprintf_s(bf, 64, "%02d:%02d:%02d", nr/3600, (nr/60)%60, nr%60); + else { + int days = nr / (24*3600); + nr = nr % (24*3600); + sprintf_s(bf, 64, "%d+%02d:%02d:%02d", days, nr/3600, (nr/60)%60, nr%60); + } + } + else { + bf[0] = '-'; + bf[1] = 0; + } + return true; + } + else if (di.SubType == oISDecimal) { + if (nr) { + int whole = nr / di.decimalScale; + int part = nr - whole * di.decimalScale; + string deci = ","; + string ptrn = "%d" + deci + "%0" + itos(di.decimalSize) + "d"; + sprintf_s(bf, 64, ptrn.c_str(), whole, abs(part)); + } + else + bf[0] = 0; + + return true; + } + else { + if (nr) + sprintf_s(bf, 64, "%d", nr); + else + bf[0] = 0; + return true; + } +} + +int oDataContainer::fillTableCol(const oBase &owner, Table &table, bool canEdit) const { + void *data, *oldData; + vector< vector > *strptr; + owner.getDataBuffers(data, oldData, strptr); + + int nextIndex = 0; + char bf[64]; + oBase &ob = *(oBase *)&owner; + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + if (di.dataDefiner != 0) { + table.set(di.tableIndex, ob, 1000+di.tableIndex, di.dataDefiner->formatData(&ob), canEdit); + } + else if (di.Type==oDTInt) { + LPBYTE vd=LPBYTE(data)+di.Index; + if (di.SubType != oIS64) { + int nr; + memcpy(&nr, vd, sizeof(int)); + if (di.SubType == oISCurrency) { + table.set(di.tableIndex, ob, 1000+di.tableIndex, ob.getEvent()->formatCurrency(nr), canEdit); + } + else { + formatNumber(nr, di, bf); + table.set(di.tableIndex, ob, 1000+di.tableIndex, bf, canEdit); + } + } + else { + __int64 nr; + memcpy(&nr, vd, sizeof(__int64)); + char bf[16]; + oBase::converExtIdentifierString(nr, bf); + table.set(di.tableIndex, ob, 1000+di.tableIndex, bf, canEdit); + } + } + else if (di.Type==oDTString) { + LPBYTE vd=LPBYTE(data)+di.Index; + if (di.SubType == oSSString || !canEdit) { + table.set(di.tableIndex, *((oBase*)&owner), 1000+di.tableIndex, (char *)vd, canEdit, cellEdit); + } + else { + string str((char *)vd); + for (size_t k = 0; k > *strptr; + ob->getDataBuffers(data, oldData, strptr); + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + + if (di.tableIndex+1000==id) { + if (di.dataDefiner) { + const string &src = di.dataDefiner->formatData(ob); + output = di.dataDefiner->setData(ob, input); + bool ch = output != src; + if (ch && noUpdate == false) + ob->synchronize(true); + return ch; + } + else if (di.Type==oDTInt) { + LPBYTE vd=LPBYTE(data)+di.Index; + + int no = 0; + if (di.SubType == oISCurrency) { + no = ob->getEvent()->interpretCurrency(input); + } + else if (di.SubType == oISDate) { + no = convertDateYMS(input, true); + } + else if (di.SubType == oISTime) { + no = convertAbsoluteTimeHMS(input, -1); + } + else if (di.SubType == oISDecimal) { + string str = input; + for (size_t k = 0; k < str.length(); k++) { + if (str[k] == ',') { + str[k] = '.'; + break; + } + } + double val = atof(str.c_str()); + no = int(di.decimalScale * val); + } + else if (di.SubType == oIS64) { + //__int64 no64 = _atoi64(input.c_str()); + __int64 k64; + memcpy(&k64, vd, sizeof(__int64)); + __int64 no64 = oBase::converExtIdentifierString(input); + + memcpy(vd, &no64, sizeof(__int64)); + __int64 out64 = no64; + if (k64 != no64) { + ob->updateChanged(); + if (noUpdate == false) + ob->synchronize(true); + + memcpy(&out64, vd, sizeof(__int64)); + } + //output = itos(out64); + char outbf[16]; + oBase::converExtIdentifierString(out64, outbf); + output = outbf; + + return k64 != no64; + } + else + no = atoi(input.c_str()); + + int k; + memcpy(&k, vd, sizeof(int)); + memcpy(vd, &no, sizeof(int)); + char bf[128]; + int outN = no; + + if (k != no) { + ob->updateChanged(); + if (noUpdate == false) + ob->synchronize(true); + + memcpy(&outN, vd, sizeof(int)); + } + + formatNumber(outN, di, bf); + output = bf; + return k != no; + } + else if (di.Type==oDTString) { + LPBYTE vd=LPBYTE(data)+di.Index; + const char *str = input.c_str(); + + if (di.SubType == oSSEnum) { + size_t ix = inputId-1; + if (ix < di.enumDescription.size()) { + str = di.enumDescription[ix].first.c_str(); + } + } + + if (strcmp((char *)vd, str)!=0) { + strncpy_s((char *)vd, di.Size, str, di.Size-1); + + ob->updateChanged(); + if (noUpdate == false) + ob->synchronize(true); + + if (di.SubType == oSSEnum) { + size_t ix = inputId-1; + if (ix < di.enumDescription.size()) { + output = lang.tl(di.enumDescription[ix].second); + // This might be incorrect if data was changed on server, + // but this issue is minor, I think: conflicts have no resolution + // Anyway, the row will typically be reloaded + } + else + output=(char *)vd; + } + else + output=(char *)vd; + return true; + } + else + output=input; + + return false; + } + else if (di.Type == oDTStringDynamic) { + string &vd = (*strptr)[0][di.Index]; + + if (vd != input) { + vd = input; + ob->updateChanged(); + if (noUpdate == false) + ob->synchronize(true); + + output = (*strptr)[0][di.Index]; + return true; + } + else + output=input; + + return false; + } + } + } + return true; +} + +void oDataContainer::fillInput(const void *data, int id, const char *name, + vector< pair > &out, size_t &selected) const { + + + const oDataInfo * info = findVariable(name); + + if (!info) { + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di=ordered[kk]; + if (di.tableIndex+1000==id && di.Type == oDTString && di.SubType == oSSEnum) { + info = &di; + break; + } + } + } + + if (info && info->Type == oDTString && info->SubType == oSSEnum) { + char *vd = (char *)(LPBYTE(data)+info->Index); + + selected = -1; + for (size_t k = 0; k < info->enumDescription.size(); ++k) { + out.push_back(make_pair(lang.tl(info->enumDescription[k].second), k+1)); + if (info->enumDescription[k].first == string(vd)) + selected = k+1; + } + } + else + throw meosException("Invalid enum"); +} + +bool oDataContainer::setEnum(oBase *ob, const char *name, int selectedIndex) { + const oDataInfo * info = findVariable(name); + + if (info && info->Type == oDTString && info->SubType == oSSEnum) { + if (size_t(selectedIndex - 1) < info->enumDescription.size()) { + return setString(ob, name, info->enumDescription[selectedIndex-1].first); + } + } + throw meosException("Invalid enum"); +} + +bool oVariableString::store(const char *in) { + if (data) { + char cb[1024]; + strncpy_s(cb, maxSize, in, maxSize-1); + if (strcmp(cb, data) != 0) { + strncpy_s(data, maxSize, cb, maxSize-1); + return true; + } + return false; + } + else { + vector &str = *strData; + if (strIndex>=0) { + if (str[strIndex] != in) { + str[strIndex] = in; + return true; + } + else + return false; + } + } + + return false; +} + +string oDataContainer::encodeArray(const vector &input) { + return "";//XXX +} + +void oDataContainer::decodeArray(const string &input, vector &output) { +} diff --git a/code/oDataContainer.h b/code/oDataContainer.h new file mode 100644 index 0000000..f2d1cb6 --- /dev/null +++ b/code/oDataContainer.h @@ -0,0 +1,378 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include + +#include "oBase.h" +#include "inthashmap.h" + +class Table; + +class oDataDefiner { +public: + virtual ~oDataDefiner() {} + virtual const string &formatData(oBase *obj) const = 0; + virtual string setData(oBase *obj, const string &input) const = 0; + /** Used to define/add the table column in the table*/ + virtual int addTableColumn(Table *table, const string &description, int minWidth) const = 0; +}; + +struct oDataInfo { + char Name[20]; + int Index; + int Size; + int Type; + int SubType; + int tableIndex; + char Description[48]; + int decimalSize; + int decimalScale; + vector< pair > enumDescription; + const oDataDefiner *dataDefiner; + int zeroSortPadding; + oDataInfo(); + ~oDataInfo(); +}; + +struct oVariableInt { + char name[20]; + int *data32; + __int64 *data64; + oVariableInt() : data32(0), data64(0) {name[0] = 0;} +}; + +class oVariableString { + public: + oVariableString(char *buff, int size) : data(buff), maxSize(size), strData(0), strIndex(-2) {} + oVariableString(vector &vec) : data(0), maxSize(0), strData(&vec), strIndex(-1) {} + oVariableString(vector &vec, int position) : data(0), maxSize(0), strData(&vec), strIndex(position) {} + char name[20]; + bool store(const char *str); + private: + char *data; + int maxSize; + vector *strData; + int strIndex; //-1 means array, otherwise string in fixed position +}; + +class oBase; + +class xmlparser; +class xmlobject; +class gdioutput; +class oDataInterface; +class oDataConstInterface; + +class oDataContainer { +protected: + enum oDataType{oDTInt=1, oDTString=2, oDTStringDynamic=3, oDTStringArray=4}; + int dataMaxSize; + int dataPointer; + size_t stringIndexPointer; + size_t stringArrayIndexPointer; + + //map index; + //vector ordered; + inthashmap index; + vector ordered; + + static int hash(const char *name); + + oDataInfo *findVariable(const char *name); + const oDataInfo *findVariable(const char *Name) const; + bool formatNumber(int nr, const oDataInfo &di, char bf[64]) const; + + static string encodeArray(const vector &input); + static void decodeArray(const string &input, vector &output); + + bool isModified(const oDataInfo &di, + const void *data, + const void *oldData, + vector< vector > *strptr) const; + + oDataInfo &addVariable(oDataInfo &odi); + static string C_INT(const string & name); + static string C_INT64(const string & name); + static string C_SMALLINT(const string & name); + static string C_TINYINT(const string & name); + static string C_SMALLINTU(const string & name); + static string C_TINYINTU(const string & name); + static string C_STRING(const string & name, int len); + static string SQL_quote(const char *in); +public: + enum oIntSize{oISDecimal = 28, oISTime = 29, oISCurrency = 30, oISDate = 31, oIS64=64, oIS32=32, oIS16=16, oIS8=8, oIS16U=17, oIS8U=9}; + enum oStringSubType {oSSString = 0, oSSEnum = 1}; + string generateSQLDefinition(const std::set &exclude) const; + string generateSQLDefinition() const { + return generateSQLDefinition(std::set()); + } + + string generateSQLSet(const oBase *ob, bool forceSetAll) const; + + void allDataStored(const oBase *ob); + void getVariableInt(const void *data, list &var) const; + void getVariableString(const oBase *data, list &var) const; + + oDataInterface getInterface(void *data, int datasize, oBase *ob); + oDataConstInterface getConstInterface(const void *data, int datasize, + const oBase *ob) const; + + oDataInfo &addVariableInt(const char *name, oIntSize isize, const char *descr, const oDataDefiner *dataDef = 0); + oDataInfo &addVariableDecimal(const char *name, const char *descr, int fixedDeci); + oDataInfo &addVariableDate(const char *name, const char *descr){return addVariableInt(name, oISDate, descr);} + oDataInfo &addVariableCurrency(const char *name, const char *descr){return addVariableInt(name, oISCurrency, descr);} + oDataInfo &addVariableString(const char *name, int maxChar, const char *descr, const oDataDefiner *dataDef = 0); + oDataInfo &addVariableString(const char *name, const char *descr, const oDataDefiner *dataDef = 0); + + oDataInfo &addVariableEnum(const char *name, int maxChar, const char *descr, + const vector< pair > enumValues); + + void initData(oBase *ob, int datasize); + + bool setInt(void *data, const char *Name, int V); + int getInt(const void *data, const char *Name) const; + + bool setInt64(void *data, const char *Name, __int64 V); + __int64 getInt64(const void *data, const char *Name) const; + + bool setString(oBase *ob, const char *name, const string &v); + const string &getString(const oBase *ob, const char *name) const; + + bool setDate(void *data, const char *Name, const string &V); + const string &getDate(const void *data, const char *Name) const; + + bool write(const oBase *ob, xmlparser &xml) const; + void set(oBase *ob, const xmlobject &xo); + + // Get a measure of how much data is stored in this record. + int getDataAmountMeasure(const void *data) const; + + void buildDataFields(gdioutput &gdi) const; + void buildDataFields(gdioutput &gdi, const vector &fields) const; + + void fillDataFields(const oBase *ob, gdioutput &gdi) const; + bool saveDataFields(oBase *ob, gdioutput &gdi); + + int fillTableCol(const oBase &owner, Table &table, bool canEdit) const; + void buildTableCol(Table *table); + bool inputData(oBase *ob, int id, const string &input, int inputId, string &output, bool noUpdate); + + // Use id (table internal) or name + void fillInput(const void *data, int id, const char *name, vector< pair > &out, size_t &selected) const; + + bool setEnum(oBase *ob, const char *name, int selectedIndex); + + oDataContainer(int maxsize); + virtual ~oDataContainer(void); + + friend class oDataInterface; +}; + + +class oDataInterface +{ +private: + void *Data; + oDataContainer *oDC; + oBase *oB; +public: + + inline bool setInt(const char *Name, int Value) + { + if (oDC->setInt(Data, Name, Value)){ + oB->updateChanged(); + return true; + } + else return false; + } + + inline bool setInt64(const char *Name, __int64 Value) + { + if (oDC->setInt64(Data, Name, Value)){ + oB->updateChanged(); + return true; + } + else return false; + } + + inline int getInt(const char *Name) const + {return oDC->getInt(Data, Name);} + + inline __int64 getInt64(const char *Name) const + {return oDC->getInt64(Data, Name);} + + inline bool setStringNoUpdate(const char *Name, const string &Value) + {return oDC->setString(oB, Name, Value);} + + inline bool setString(const char *Name, const string &Value) + { + if (oDC->setString(oB, Name, Value)){ + oB->updateChanged(); + return true; + } + else return false; + } + + inline string getString(const char *Name) const + {return oDC->getString(oB, Name);} + + inline bool setDate(const char *Name, const string &Value) + { + if (oDC->setDate(Data, Name, Value)){ + oB->updateChanged(); + return true; + } + else return false; + } + + inline const string &getDate(const char *Name) const + {return oDC->getDate(Data, Name);} + + inline void buildDataFields(gdioutput &gdi) const + {oDC->buildDataFields(gdi);} + + inline void buildDataFields(gdioutput &gdi, const vector &fields) const + {oDC->buildDataFields(gdi, fields);} + + inline void fillDataFields(gdioutput &gdi) const + {oDC->fillDataFields(oB, gdi);} + + inline bool saveDataFields(gdioutput &gdi) + {return oDC->saveDataFields(oB, gdi);} + + inline string generateSQLDefinition() const + {return oDC->generateSQLDefinition(std::set());} + + inline string generateSQLDefinition(const std::set &exclude) const + {return oDC->generateSQLDefinition(exclude);} + + inline string generateSQLSet(bool forceSetAll) const + {return oDC->generateSQLSet(oB, forceSetAll);} + + // Mark all data as stored in db + inline void allDataStored() + {return oDC->allDataStored(oB);} + + inline void getVariableInt(list &var) const + {oDC->getVariableInt(Data, var);} + + inline void getVariableString(list &var) const + {oDC->getVariableString(oB, var);} + + inline void initData() + {oDC->initData(oB, oDC->dataMaxSize);} + + inline bool write(xmlparser &xml) const + {return oDC->write(oB, xml);} + + inline void set(const xmlobject &xo) + {oDC->set(oB, xo);} + + void fillInput(const char *name, vector< pair > &out, size_t &selected) const { + oDC->fillInput(Data, -1, name, out, selected); + } + + bool setEnum(const char *name, int selectedIndex) { + if (oDC->setEnum(oB, name, selectedIndex) ) { + oB->updateChanged(); + return true; + } + else return false; + } + + int getDataAmountMeasure() const + {return oDC->getDataAmountMeasure(Data);} + + oDataInterface(oDataContainer *odc, void *data, oBase *ob); + ~oDataInterface(void); +}; + +class oDataConstInterface +{ +private: + const void *Data; + const oDataContainer *oDC; + const oBase *oB; +public: + + inline int getInt(const char *Name) const + {return oDC->getInt(Data, Name);} + + inline __int64 getInt64(const char *Name) const + {return oDC->getInt64(Data, Name);} + + inline const string &getString(const char *Name) const + {return oDC->getString(oB, Name);} + + inline const string &getDate(const char *Name) const + {return oDC->getDate(Data, Name);} + + inline int getInt(const string &name) const + {return oDC->getInt(Data, name.c_str());} + + inline __int64 getInt64(const string &name) const + {return oDC->getInt64(Data, name.c_str());} + + inline const string &getString(const string &name) const + {return oDC->getString(oB, name.c_str());} + + inline const string &getDate(const string &name) const + {return oDC->getDate(Data, name.c_str());} + + inline void buildDataFields(gdioutput &gdi) const + {oDC->buildDataFields(gdi);} + + inline void fillDataFields(gdioutput &gdi) const + {oDC->fillDataFields(oB, gdi);} + + inline string generateSQLDefinition() const + {return oDC->generateSQLDefinition(set());} + + inline string generateSQLDefinition(const set &exclude) const + {return oDC->generateSQLDefinition(exclude);} + + inline string generateSQLSet(bool forceSetAll) const + {return oDC->generateSQLSet(oB, forceSetAll);} + + inline void getVariableInt(list &var) const + {oDC->getVariableInt(Data, var);} + + inline void getVariableString(list &var) const + {oDC->getVariableString(oB, var);} + + inline bool write(xmlparser &xml) const + {return oDC->write(oB, xml);} + + int getDataAmountMeasure() const + {return oDC->getDataAmountMeasure(Data);} + + void fillInput(const char *name, vector< pair > &out, size_t &selected) const { + oDC->fillInput(Data, -1, name, out, selected); + } + + oDataConstInterface(const oDataContainer *odc, const void *data, const oBase *ob); + ~oDataConstInterface(void); +}; diff --git a/code/oEvent.cpp b/code/oEvent.cpp new file mode 100644 index 0000000..b51169a --- /dev/null +++ b/code/oEvent.cpp @@ -0,0 +1,6443 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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 fro more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "oDataContainer.h" +#include "MetaList.h" + +#include "random.h" +#include "SportIdent.h" + +#include "meosException.h" +#include "oFreeImport.h" +#include "TabBase.h" +#include "meos.h" +#include "meos_util.h" +#include "RunnerDB.h" +#include "localizer.h" +#include "progress.h" +#include "intkeymapimpl.hpp" +#include "meosdb/sqltypes.h" +#include "socket.h" +#include +#include "MeOSFeatures.h" +#include "generalresult.h" +#include "oEventDraw.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "Table.h" + +//Version of database +int oEvent::dbVersion = 79; + +class RelativeTimeFormatter : public oDataDefiner { + string name; + public: + RelativeTimeFormatter(const char *n) : name(n) {} + + const string &formatData(oBase *obj) const { + int t = obj->getDCI().getInt(name); + if (t <= 0) + return MakeDash("-"); + return obj->getEvent()->getAbsTime(t); + } + string setData(oBase *obj, const string &input) const { + int t = obj->getEvent()->getRelativeTime(input); + obj->getDI().setInt(name.c_str(), t); + return formatData(obj); + } + int addTableColumn(Table *table, const string &description, int minWidth) const { + return table->addColumn(description, max(minWidth, 90), false, true); + } +}; + +class AbsoluteTimeFormatter : public oDataDefiner { + string name; + public: + AbsoluteTimeFormatter(const char *n) : name(n) {} + + const string &formatData(oBase *obj) const { + int t = obj->getDCI().getInt(name); + return formatTime(t); + } + string setData(oBase *obj, const string &input) const { + int t = convertAbsoluteTimeMS(input); + if (t == NOTIME) + t = 0; + obj->getDI().setInt(name.c_str(), t); + return formatData(obj); + } + int addTableColumn(Table *table, const string &description, int minWidth) const { + return table->addColumn(description, max(minWidth, 90), false, true); + } +}; + +oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi) +{ + readOnly = false; + tLongTimesCached = -1; + directSocket = 0; + hMod=0; + ZeroTime=0; + vacantId = 0; + dataRevision = 0; + sqlCounterRunners=0; + sqlCounterClasses=0; + sqlCounterCourses=0; + sqlCounterControls=0; + sqlCounterClubs=0; + sqlCounterCards=0; + sqlCounterPunches=0; + sqlCounterTeams=0; + + disableRecalculate = false; + + initProperties(); + +#ifndef MEOSDB + listContainer = new MetaListContainer(this); +#else + throw std::exception(); +#endif + + + tCurrencyFactor = 1; + tCurrencySymbol = "kr"; + tCurrencySeparator = ","; + tCurrencyPreSymbol = false; + + tClubDataRevision = -1; + + nextFreeStartNo = 0; + + SYSTEMTIME st; + GetLocalTime(&st); + + char bf[64]; + sprintf_s(bf, 64, "%d-%02d-%02d", st.wYear, st.wMonth, st.wDay); + + Date=bf; + ZeroTime=st.wHour*3600; + oe=this; + + runnerDB = new RunnerDB(this); + meosFeatures = new MeOSFeatures(); + openFileLock = new MeOSFileLock(); + + char cp[64]; + DWORD size=64; + GetComputerName(cp, &size); + clientName=cp; + + HasDBConnection = false; + HasPendingDBConnection = false; + +#ifdef BUILD_DB_DLL + msSynchronizeList=0; + msSynchronizeRead=0; + msSynchronizeUpdate=0; + msOpenDatabase=0; + msRemove=0; + msMonitor=0; + msUploadRunnerDB = 0; + + msGetErrorState=0; + msResetConnection=0; + msReConnect=0; +#endif + + currentNameMode = FirstLast; + + nextTimeLineEvent = 0; + //These object must be initialized on creation of any oObject, + //but we need to create (dummy) objects to get the sizeof their + //oData[]-sets... + + // --- REMEMBER TO UPDATE dvVersion when these are changed. + + oEventData=new oDataContainer(dataSize); + oEventData->addVariableCurrency("CardFee", "Brickhyra"); + oEventData->addVariableCurrency("EliteFee", "Elitavgift"); + oEventData->addVariableCurrency("EntryFee", "Normalavgift"); + oEventData->addVariableCurrency("YouthFee", "Ungdomsavgift"); + oEventData->addVariableInt("YouthAge", oDataContainer::oIS8U, "Åldersgräns ungdom"); + oEventData->addVariableInt("SeniorAge", oDataContainer::oIS8U, "Åldersgräns äldre"); + + oEventData->addVariableString("Account", 30, "Konto"); + oEventData->addVariableDate("PaymentDue", "Sista betalningsdatum"); + oEventData->addVariableDate("OrdinaryEntry", "Ordinarie anmälningsdatum"); + oEventData->addVariableString("LateEntryFactor", 6, "Avgiftshöjning (procent)"); + + oEventData->addVariableString("Organizer", "Arrangör"); + oEventData->addVariableString("CareOf", 31, "c/o"); + + oEventData->addVariableString("Street", 32, "Adress"); + oEventData->addVariableString("Address", 32, "Postadress"); + oEventData->addVariableString("EMail", "E-post"); + oEventData->addVariableString("Homepage", "Hemsida"); + oEventData->addVariableString("Phone", 32, "Telefon"); + + oEventData->addVariableInt("UseEconomy", oDataContainer::oIS8U, "Ekonomi"); + oEventData->addVariableInt("UseSpeaker", oDataContainer::oIS8U, "Speaker"); + oEventData->addVariableInt("SkipRunnerDb", oDataContainer::oIS8U, "Databas"); + oEventData->addVariableInt("ExtId", oDataContainer::oIS64, "Externt Id"); + + oEventData->addVariableInt("MaxTime", oDataContainer::oISTime, "Gräns för maxtid"); + + oEventData->addVariableString("PreEvent", sizeof(CurrentNameId), ""); + oEventData->addVariableString("PostEvent", sizeof(CurrentNameId), ""); + + // Positive number -> stage number, negative number -> no stage number. Zero = unknown + oEventData->addVariableInt("EventNumber", oDataContainer::oIS8, ""); + + oEventData->addVariableInt("CurrencyFactor", oDataContainer::oIS16, "Valutafaktor"); + oEventData->addVariableString("CurrencySymbol", 5, "Valutasymbol"); + oEventData->addVariableString("CurrencySeparator", 2, "Decimalseparator"); + oEventData->addVariableInt("CurrencyPreSymbol", oDataContainer::oIS8, "Symbolläge"); + oEventData->addVariableString("CurrencyCode", 5, "Valutakod"); + oEventData->addVariableInt("UTC", oDataContainer::oIS8, "UTC"); + + oEventData->addVariableInt("Analysis", oDataContainer::oIS8, "Utan analys"); + // With split time analysis (0 = default, with analysis, with min/km) + // bit 1: without analysis + // bit 2: without min/km + // bit 4: without result + + oEventData->addVariableString("SPExtra", "Extra rader"); + oEventData->addVariableString("IVExtra", "Fakturainfo"); + oEventData->addVariableString("Features", "Funktioner"); + oEventData->addVariableString("EntryExtra", "Extra rader"); + oEventData->addVariableInt("NumStages", oDataContainer::oIS8, "Antal etapper"); + oEventData->addVariableInt("BibGap", oDataContainer::oIS8U, "Nummerlappshopp"); + oEventData->addVariableInt("LongTimes", oDataContainer::oIS8U, "Långa tider"); + oEventData->addVariableString("PayModes", "Betalsätt"); + + oEventData->initData(this, dataSize); + + oClubData=new oDataContainer(oClub::dataSize); + oClubData->addVariableInt("District", oDataContainer::oIS32, "Organisation"); + + oClubData->addVariableString("ShortName", 8, "Kortnamn"); + oClubData->addVariableString("CareOf", 31, "c/o"); + oClubData->addVariableString("Street", 41, "Gata"); + oClubData->addVariableString("City", 23, "Stad"); + oClubData->addVariableString("State", 23, "Region"); + oClubData->addVariableString("ZIP", 11, "Postkod"); + oClubData->addVariableString("EMail", 64, "E-post"); + oClubData->addVariableString("Phone", 32, "Telefon"); + oClubData->addVariableString("Nationality", 3, "Nationalitet"); + oClubData->addVariableString("Country", 23, "Land"); + oClubData->addVariableString("Type", 20, "Typ"); + oClubData->addVariableInt("ExtId", oDataContainer::oIS64, "Externt Id"); + + vector< pair > eInvoice; + eInvoice.push_back(make_pair("E", "Elektronisk")); + eInvoice.push_back(make_pair("A", "Elektronisk godkänd")); + eInvoice.push_back(make_pair("P", "Ej elektronisk")); + eInvoice.push_back(make_pair("", MakeDash("-"))); + oClubData->addVariableEnum("Invoice", 1, "Faktura", eInvoice); + oClubData->addVariableInt("InvoiceNo", oDataContainer::oIS16U, "Fakturanummer"); + + oRunnerData=new oDataContainer(oRunner::dataSize); + oRunnerData->addVariableCurrency("Fee", "Anm. avgift"); + oRunnerData->addVariableCurrency("CardFee", "Brickhyra"); + oRunnerData->addVariableCurrency("Paid", "Betalat"); + oRunnerData->addVariableInt("PayMode", oDataContainer::oIS8U, "Betalsätt"); + oRunnerData->addVariableCurrency("Taxable", "Skattad avgift"); + oRunnerData->addVariableInt("BirthYear", oDataContainer::oIS32, "Födelseår"); + oRunnerData->addVariableString("Bib", 8, "Nummerlapp").zeroSortPadding = 5; + oRunnerData->addVariableInt("Rank", oDataContainer::oIS16U, "Ranking"); + //oRunnerData->addVariableInt("VacRank", oDataContainer::oIS16U, "Vak. ranking"); + + oRunnerData->addVariableDate("EntryDate", "Anm. datum"); + + vector< pair > sex; + sex.push_back(make_pair("M", "Man")); + sex.push_back(make_pair("F", "Kvinna")); + sex.push_back(make_pair("", MakeDash("-"))); + + oRunnerData->addVariableEnum("Sex", 1, "Kön", sex); + oRunnerData->addVariableString("Nationality", 3, "Nationalitet"); + oRunnerData->addVariableString("Country", 23, "Land"); + oRunnerData->addVariableInt("ExtId", oDataContainer::oIS64, "Externt Id"); + oRunnerData->addVariableInt("Priority", oDataContainer::oIS8U, "Prioritering"); + oRunnerData->addVariableString("Phone", 20, "Telefon"); + + oRunnerData->addVariableInt("RaceId", oDataContainer::oIS32, "Lopp-id", &oRunner::raceIdFormatter); + + oRunnerData->addVariableInt("TimeAdjust", oDataContainer::oIS16, "Tidsjustering"); + oRunnerData->addVariableInt("PointAdjust", oDataContainer::oIS32, "Poängjustering"); + oRunnerData->addVariableInt("TransferFlags", oDataContainer::oIS32, "Överföring"); + oRunnerData->addVariableInt("Shorten", oDataContainer::oIS8U, "Avkortning"); + oRunnerData->addVariableInt("EntrySource", oDataContainer::oIS32, "Källa"); + oRunnerData->addVariableInt("Heat", oDataContainer::oIS8U, "Heat"); + + oControlData=new oDataContainer(oControl::dataSize); + oControlData->addVariableInt("TimeAdjust", oDataContainer::oIS32, "Tidsjustering"); + oControlData->addVariableInt("MinTime", oDataContainer::oIS32, "Minitid"); + oControlData->addVariableDecimal("xpos", "x", 1); + oControlData->addVariableDecimal("ypos", "y", 1); + oControlData->addVariableDecimal("latcrd", "Latitud", 6); + oControlData->addVariableDecimal("longcrd", "Longitud", 6); + + oControlData->addVariableInt("Rogaining", oDataContainer::oIS32, "Poäng"); + oControlData->addVariableInt("Radio", oDataContainer::oIS8U, "Radio"); + + oCourseData=new oDataContainer(oCourse::dataSize); + oCourseData->addVariableInt("NumberMaps", oDataContainer::oIS16, "Kartor"); + oCourseData->addVariableString("StartName", 16, "Start"); + oCourseData->addVariableInt("Climb", oDataContainer::oIS16, "Stigning"); + oCourseData->addVariableInt("StartIndex", oDataContainer::oIS32, "Startindex"); + oCourseData->addVariableInt("FinishIndex", oDataContainer::oIS32, "Målindex"); + oCourseData->addVariableInt("RPointLimit", oDataContainer::oIS32, "Poänggräns"); + oCourseData->addVariableInt("RTimeLimit", oDataContainer::oIS32, "Tidsgräns"); + oCourseData->addVariableInt("RReduction", oDataContainer::oIS32, "Poängreduktion"); + oCourseData->addVariableInt("RReductionMethod", oDataContainer::oIS8U, "Reduktionsmetod"); + + oCourseData->addVariableInt("FirstAsStart", oDataContainer::oIS8U, "Från första"); + oCourseData->addVariableInt("LastAsFinish", oDataContainer::oIS8U, "Till sista"); + + oCourseData->addVariableInt("CControl", oDataContainer::oIS16U, "Varvningskontroll"); //Common control index + oCourseData->addVariableInt("Shorten", oDataContainer::oIS32, "Avkortning"); + + oClassData=new oDataContainer(oClass::dataSize); + oClassData->addVariableInt("ExtId", oDataContainer::oIS64, "Externt Id"); + oClassData->addVariableString("LongName", 32, "Långt namn"); + oClassData->addVariableInt("LowAge", oDataContainer::oIS8U, "Undre ålder"); + oClassData->addVariableInt("HighAge", oDataContainer::oIS8U, "Övre ålder"); + oClassData->addVariableInt("HasPool", oDataContainer::oIS8U, "Banpool"); + oClassData->addVariableInt("AllowQuickEntry", oDataContainer::oIS8U, "Direktanmälan"); + + oClassData->addVariableString("ClassType", 40, "Klasstyp"); + + vector< pair > sexClass; + sexClass.push_back(make_pair("M", "Män")); + sexClass.push_back(make_pair("F", "Kvinnor")); + sexClass.push_back(make_pair("B", "Alla")); + sexClass.push_back(make_pair("", MakeDash("-"))); + + oClassData->addVariableEnum("Sex", 1, "Kön", sexClass); + oClassData->addVariableString("StartName", 16, "Start"); + oClassData->addVariableInt("StartBlock", oDataContainer::oIS8U, "Block"); + oClassData->addVariableInt("NoTiming", oDataContainer::oIS8U, "Ej tidtagning"); + oClassData->addVariableInt("FreeStart", oDataContainer::oIS8U, "Fri starttid"); + oClassData->addVariableInt("IgnoreStart", oDataContainer::oIS8U, "Ej startstämpling"); + + firstStartDefiner = new RelativeTimeFormatter("FirstStart"); + oClassData->addVariableInt("FirstStart", oDataContainer::oIS32, "Första start", firstStartDefiner); + intervalDefiner = new AbsoluteTimeFormatter("StartInterval"); + oClassData->addVariableInt("StartInterval", oDataContainer::oIS16, "Intervall", intervalDefiner); + oClassData->addVariableInt("Vacant", oDataContainer::oIS8U, "Vakanser"); + oClassData->addVariableInt("Reserved", oDataContainer::oIS16U, "Extraplatser"); + + oClassData->addVariableCurrency("ClassFee", "Anm. avgift"); + oClassData->addVariableCurrency("HighClassFee", "Efteranm. avg."); + oClassData->addVariableCurrency("ClassFeeRed", "Reducerad avg."); + oClassData->addVariableCurrency("HighClassFeeRed", "Red. avg. efteranm."); + + oClassData->addVariableInt("SortIndex", oDataContainer::oIS32, "Sortering"); + oClassData->addVariableInt("MaxTime", oDataContainer::oISTime, "Maxtid"); + + vector< pair > statusClass; + statusClass.push_back(make_pair("", "OK")); + statusClass.push_back(make_pair("IR", "Struken med återbetalning")); + statusClass.push_back(make_pair("I", "Struken utan återbetalning")); + + oClassData->addVariableEnum("Status", 2, "Status", statusClass); + oClassData->addVariableInt("DirectResult", oDataContainer::oIS8, "Resultat vid målstämpling"); + oClassData->addVariableString("Bib", 8, "Nummerlapp"); + + vector< pair > bibMode; + bibMode.push_back(make_pair("", "Från lag")); + bibMode.push_back(make_pair("A", "Lag + sträcka")); + bibMode.push_back(make_pair("F", "Fritt")); + + oClassData->addVariableEnum("BibMode", 1, "Nummerlappshantering", bibMode); + oClassData->addVariableInt("Unordered", oDataContainer::oIS8U, "Oordnade parallella"); + oClassData->addVariableInt("Heat", oDataContainer::oIS8U, "Heat"); + + oTeamData = new oDataContainer(oTeam::dataSize); + oTeamData->addVariableCurrency("Fee", "Anm. avgift"); + oTeamData->addVariableCurrency("Paid", "Betalat"); + oTeamData->addVariableInt("PayMode", oDataContainer::oIS8U, "Betalsätt"); + oTeamData->addVariableCurrency("Taxable", "Skattad avgift"); + oTeamData->addVariableDate("EntryDate", "Anm. datum"); + oTeamData->addVariableString("Nationality", 3, "Nationalitet"); + oTeamData->addVariableString("Country", 23, "Land"); + oTeamData->addVariableString("Bib", 8, "Nummerlapp").zeroSortPadding = 5; + oTeamData->addVariableInt("ExtId", oDataContainer::oIS64, "Externt Id"); + oTeamData->addVariableInt("Priority", oDataContainer::oIS8U, "Prioritering"); + oTeamData->addVariableInt("SortIndex", oDataContainer::oIS16, "Sortering"); + oTeamData->addVariableInt("TimeAdjust", oDataContainer::oIS16, "Tidsjustering"); + oTeamData->addVariableInt("PointAdjust", oDataContainer::oIS32, "Poängjustering"); + oTeamData->addVariableInt("TransferFlags", oDataContainer::oIS32, "Överföring"); + oTeamData->addVariableInt("EntrySource", oDataContainer::oIS32, "Källa"); + oTeamData->addVariableInt("Heat", oDataContainer::oIS8U, "Heat"); + + generalResults.push_back(GeneralResultCtr("atcontrol", "Result at a control", new ResultAtControl())); + generalResults.push_back(GeneralResultCtr("totatcontrol", "Total/team result at a control", new TotalResultAtControl())); + + currentClientCS = 0; + memset(CurrentFile, 0, sizeof(CurrentFile)); +} + +oEvent::~oEvent() +{ + //Clean up things in the right order. + clear(); + delete runnerDB; + delete meosFeatures; + runnerDB = 0; + meosFeatures = 0; + + if (hMod) { + HasDBConnection=false; + FreeLibrary(hMod); + hMod=0; + } + + delete oEventData; + delete oRunnerData; + delete oClubData; + delete oControlData; + delete oCourseData; + delete oClassData; + delete oTeamData; + + delete openFileLock; + delete listContainer; + + return; +} + +void oEvent::initProperties() { + setProperty("TextSize", getPropertyString("TextSize", "0")); + setProperty("Language", getPropertyString("Language", "103")); + + setProperty("Interactive", getPropertyString("Interactive", "1")); + setProperty("Database", getPropertyString("Database", "1")); + + // Setup some defaults + getPropertyInt("SplitLateFees", false); + getPropertyInt("DirectPort", 21338); + getPropertyInt("UseHourFormat", 1); + getPropertyInt("UseDirectSocket", true); + getPropertyInt("UseEventorUTC", 0); +} + +void oEvent::listProperties(bool userProps, vector< pair > &propNames) const { + + + set filter; + if (userProps) { + filter.insert("Language"); + filter.insert("apikey"); + filter.insert("Colors"); + filter.insert("xpos"); + filter.insert("ypos"); + filter.insert("xsize"); + filter.insert("ysize"); + filter.insert("ListType"); + filter.insert("LastCompetition"); + filter.insert("DrawTypeDefault"); + filter.insert("Email"); + filter.insert("TextSize"); + filter.insert("PayModes"); + } + + // Boolean and integer properties + set b, i; + + // Booleans + b.insert("AdvancedClassSettings"); + b.insert("AutoTie"); + b.insert("CurrencyPreSymbol"); + b.insert("Database"); + b.insert("Interactive"); + b.insert("intertime"); + b.insert("ManualInput"); + b.insert("PageBreak"); + b.insert("RentCard"); + b.insert("SpeakerShortNames"); + b.insert("splitanalysis"); + b.insert("UseDirectSocket"); + b.insert("UseEventor"); + b.insert("UseEventorUTC"); + b.insert("UseHourFormat"); + b.insert("SplitLateFees"); + b.insert("WideSplitFormat"); + b.insert("pagebreak"); + b.insert("FirstTime"); + b.insert("ExportCSVSplits"); + + // Integers + i.insert("YouthFee"); + i.insert("YouthAge"); + i.insert("TextSize"); + i.insert("SynchronizationTimeOut"); + i.insert("SeniorAge"); + i.insert("Port"); + i.insert("MaximumSpeakerDelay"); + i.insert("FirstInvoice"); + i.insert("EntryFee"); + i.insert("EliteFee"); + i.insert("DirectPort"); + i.insert("DatabaseUpdate"); + i.insert("ControlTo"); + i.insert("ControlFrom"); + i.insert("CardFee"); + i.insert("addressypos"); + i.insert("addressxpos"); + i.insert("AutoSaveTimeOut"); + + propNames.clear(); + for(map::const_iterator it = eventProperties.begin(); + it != eventProperties.end(); ++it) { + if (!filter.count(it->first)) { + if (b.count(it->first)) { + assert(!i.count(it->first)); + propNames.push_back(make_pair(it->first, Boolean)); + } + else if (i.count(it->first)) { + propNames.push_back(make_pair(it->first, Integer)); + } + else + propNames.push_back(make_pair(it->first, String)); + } + } +} + +pControl oEvent::addControl(int Id, int Number, const string &Name) +{ + if (Id<=0) + Id=getFreeControlId(); + else + qFreeControlId = max (qFreeControlId, Id); + + oControl c(this); + c.set(Id, Number, Name); + Controls.push_back(c); + + oe->updateTabs(); + return &Controls.back(); +} + +int oEvent::getNextControlNumber() const +{ + int c = 31; + for (oControlList::const_iterator it = Controls.begin(); it!=Controls.end(); ++it) + c = max(c, it->maxNumber()+1); + + return c; +} + +pControl oEvent::addControl(const oControl &oc) +{ + if (oc.Id<=0) + return 0; + + if (getControl(oc.Id, false)) + return 0; + + qFreeControlId = max (qFreeControlId, Id); + + Controls.push_back(oc); + return &Controls.back(); +} + +DirectSocket &oEvent::getDirectSocket() { + if (directSocket == 0) + directSocket = new DirectSocket(getId(), getPropertyInt("DirectPort", 21338)); + + return *directSocket; +} + +pControl oEvent::getControl(int Id) const { + return const_cast(this)->getControl(Id, false); +} + +pControl oEvent::getControl(int Id, bool create) { + oControlList::const_iterator it; + + for (it=Controls.begin(); it != Controls.end(); ++it) { + if (it->Id==Id) + return pControl(&*it); + } + + if (!create || Id<=0) + return 0; + + //Not found. Auto add... + return addControl(Id, Id, ""); +} + +bool oEvent::writeControls(xmlparser &xml) +{ + oControlList::iterator it; + + xml.startTag("ControlList"); + + for (it=Controls.begin(); it != Controls.end(); ++it) + it->write(xml); + + xml.endTag(); + + return true; +} + +bool oEvent::writeCourses(xmlparser &xml) +{ + oCourseList::iterator it; + + xml.startTag("CourseList"); + + for (it=Courses.begin(); it != Courses.end(); ++it) + it->Write(xml); + + xml.endTag(); + + return true; +} + +bool oEvent::writeClasses(xmlparser &xml) +{ + oClassList::iterator it; + + xml.startTag("ClassList"); + + for (it=Classes.begin(); it != Classes.end(); ++it) + it->Write(xml); + + xml.endTag(); + + return true; +} + +bool oEvent::writeClubs(xmlparser &xml) +{ + oClubList::iterator it; + + xml.startTag("ClubList"); + + for (it=Clubs.begin(); it != Clubs.end(); ++it) + it->write(xml); + + xml.endTag(); + + return true; +} + +bool oEvent::writeRunners(xmlparser &xml, ProgressWindow &pw) +{ + oRunnerList::iterator it; + + xml.startTag("RunnerList"); + int k=0; + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->tDuplicateLeg) //Duplicates is written by the ruling runner. + it->Write(xml); + if (++k%300 == 200) + pw.setSubProgress( (1000*k)/ Runners.size()); + } + xml.endTag(); + + return true; +} + + +bool oEvent::writePunches(xmlparser &xml, ProgressWindow &pw) +{ + oFreePunchList::iterator it; + + xml.startTag("PunchList"); + int k = 0; + for (it=punches.begin(); it != punches.end(); ++it) { + it->Write(xml); + if (++k%300 == 200) + pw.setSubProgress( (1000*k)/ Runners.size()); + } + xml.endTag(); + + return true; +} + +//Write free cards not owned by a runner. +bool oEvent::writeCards(xmlparser &xml) +{ + oCardList::iterator it; + + xml.startTag("CardList"); + + for (it=Cards.begin(); it != Cards.end(); ++it) { + if (it->getOwner() == 0) + it->Write(xml); + } + + xml.endTag(); + return true; +} + +void oEvent::duplicate() { + char file[260]; + char filename[64]; + char nameid[64]; + + SYSTEMTIME st; + GetLocalTime(&st); + + sprintf_s(filename, 64, "meos_%d%02d%02d_%02d%02d%02d_%X.meos", + st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + + getUserFile(file, filename); + + _splitpath_s(filename, NULL, 0, NULL,0, nameid, 64, NULL, 0); + int i=0; + while (nameid[i]) { + if (nameid[i]=='.') { + nameid[i]=0; + break; + } + i++; + } + + char oldFile[260]; + char oldId[64]; + strcpy_s(oldFile, CurrentFile); + strcpy_s(oldId, CurrentNameId); + string oldAnno = getAnnotation(); + + strcpy_s(CurrentFile, file); + strcpy_s(CurrentNameId, nameid); + + sprintf_s(filename, "%d/%d %d:%02d", + st.wDay, st.wMonth, st.wHour, st.wMinute); + + string anno = lang.tl("Kopia (X)#" + string(filename)); + anno = oldAnno.empty() ? anno : oldAnno + " " + anno; + setAnnotation(anno); + + try { + save(); + } + catch(...) { + // Restore in case of error + strcpy_s(CurrentFile, oldFile); + strcpy_s(CurrentNameId, oldId); + setAnnotation(oldAnno); + throw; + } + + // Restore + strcpy_s(CurrentFile, oldFile); + strcpy_s(CurrentNameId, oldId); + setAnnotation(oldAnno); +} + +bool oEvent::save() +{ + if (empty() || gdibase.isTest()) + return true; + + autoSynchronizeLists(true); + + if (!CurrentFile[0]) + throw std::exception("Felaktigt filnamn"); + + int f=0; + _sopen_s(&f, CurrentFile, _O_RDONLY, _SH_DENYNO, _S_IWRITE); + + char fn1[260]; + char fn2[260]; + string finalRenameTarget; + + if (f!=-1) { + _close(f); + time_t currentTime = time(0); + const int baseAge = 3; // Three minutes + time_t allowedAge = baseAge*60; + time_t oldAge = allowedAge + 60; + const int maxBackup = 8; + int toDelete = maxBackup; + + for(int k = 0; k <= maxBackup; k++) { + sprintf_s(fn1, MAX_PATH, "%s.bu%d", CurrentFile, k); + struct stat st; + int ret = stat(fn1, &st); + if (ret==0) { + time_t age = currentTime - st.st_mtime; + // If file is too young or to old at its + // position, it is possible to delete. + // The oldest old file (or youngest young file if none is old) + // possible to delete is deleted. + // If no file is possible to delete, the oldest + // file is deleted. + if ( (ageoldAge) + toDelete = k; + allowedAge *= 2; + oldAge*=2; + + if (k==maxBackup-3) + oldAge = 24*3600; // Allow a few old copies + } + else { + toDelete = k; // File does not exist. No file need be deleted + break; + } + } + + sprintf_s(fn1, MAX_PATH, "%s.bu%d", CurrentFile, toDelete); + ::remove(fn1); + + for(int k=toDelete;k>0;k--) { + sprintf_s(fn1, MAX_PATH, "%s.bu%d", CurrentFile, k-1); + sprintf_s(fn2, MAX_PATH, "%s.bu%d", CurrentFile, k); + rename(fn1, fn2); + } + + finalRenameTarget = fn1; + //rename(CurrentFile, fn1); + } + bool res; + if (finalRenameTarget.empty()) { + res = save(CurrentFile); + if (!(HasDBConnection || HasPendingDBConnection)) + openFileLock->lockFile(CurrentFile); + } + else { + string tmpName = string(CurrentFile) + ".~tmp"; + res = save(tmpName); + if (res) { + openFileLock->unlockFile(); + rename(CurrentFile, finalRenameTarget.c_str()); + rename(tmpName.c_str(), CurrentFile); + + if (!(HasDBConnection || HasPendingDBConnection)) + openFileLock->lockFile(CurrentFile); + } + } + + return res; +} + +bool oEvent::save(const string &fileIn) { + if (gdibase.isTest()) + return true; + + const char *file = fileIn.c_str(); + xmlparser xml(0); + ProgressWindow pw(gdibase.getHWND()); + + if (Runners.size()>200) + pw.init(); + + xml.openOutput(file, true); + xml.startTag("meosdata", "version", getMajorVersion()); + xml.write("Name", Name); + xml.write("Date", Date); + xml.write("ZeroTime", ZeroTime); + xml.write("NameId", CurrentNameId); + xml.write("Annotation", Annotation); + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + + oEventData->write(this, xml); + + int i = 0; + vector p; + p.resize(10); + p[0] = 2; //= {2, 20, 50, 80, 180, 400,500,700,800,1000}; + p[1] = Controls.size(); + p[2] = Courses.size(); + p[3] = Classes.size(); + p[4] = Clubs.size(); + p[5] = Runners.size() + Cards.size(); + p[6] = Teams.size(); + p[7] = punches.size(); + p[8] = Cards.size(); + p[9] = Runners.size()/2; + + int sum = 0; + for (int k = 0; k<10; k++) + sum += p[k]; + + for (int k = 1; k<10; k++) + p[k] = p[k-1] + (1000 * p[k]) / sum; + + p[9] = 1000; + + pw.setProgress(p[i++]); + writeControls(xml); + pw.setProgress(p[i++]); + writeCourses(xml); + pw.setProgress(p[i++]); + writeClasses(xml); + pw.setProgress(p[i++]); + writeClubs(xml); + pw.initSubProgress(p[i], p[i+1]); + pw.setProgress(p[i++]); + writeRunners(xml, pw); + pw.setProgress(p[i++]); + writeTeams(xml); + pw.initSubProgress(p[i], p[i+1]); + pw.setProgress(p[i++]); + writePunches(xml, pw); + pw.setProgress(p[i++]); + writeCards(xml); + + xml.startTag("Lists"); + listContainer->save(MetaListContainer::ExternalList, xml, this); + xml.endTag(); + + xml.closeOut(); + pw.setProgress(p[i++]); + updateRunnerDatabase(); + pw.setProgress(p[i++]); + + return true; +} + +string oEvent::getNameId(int id) const { + if (id == 0) + return CurrentNameId; + + list::const_iterator it; + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Server.empty()) { + if (id == it->Id) + return it->NameId; + } + else if (!it->Server.empty()) { + if (id == (10000000+it->Id)) { + return it->NameId; + } + } + } + return _EmptyString; +} + +const string &oEvent::getFileNameFromId(int id) const { + + list::const_iterator it; + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Server.empty()) { + if (id == it->Id) + return it->FullPath; + } + else if (!it->Server.empty()) { + if (id == (10000000+it->Id)) { + return _EmptyString; + } + } + } + return _EmptyString; +} + + +bool oEvent::open(int id) +{ + list::iterator it; + + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Server.empty()) { + if (id == it->Id) { + CompetitionInfo ci=*it; //Take copy + return open(ci.FullPath.c_str()); + } + } + else if (!it->Server.empty()) { + if (id == (10000000+it->Id)) { + CompetitionInfo ci=*it; //Take copy + return readSynchronize(ci); + } + } + } + + return false; +} + +static DWORD timer; +static string mlog; + +static void tic() { + timer = GetTickCount(); + mlog.clear(); +} + +static void toc(const string &str) { + DWORD t = GetTickCount(); + if (!mlog.empty()) + mlog += ",\n"; + else + mlog = "Tid (hundradels sekunder):\n"; + + mlog += str + "=" + itos( (t-timer)/10 ); + timer = t; +} + + +bool oEvent::open(const string &file, bool Import) +{ + if (!Import) + openFileLock->lockFile(file); + + xmlparser xml(0); + xml.setProgress(gdibase.getHWND()); + tic(); + string log; + xml.read(file); + + xmlattrib ver = xml.getObject(0).getAttrib("version"); + if (ver) { + string vs = ver.get(); + if (vs > getMajorVersion()) { + // Tävlingen är skapad i MeOS X. Data kan gå förlorad om du öppnar tävlingen.\n\nVill du fortsätta? + bool cont = gdibase.ask("warn:opennewversion#" + vs); + if (!cont) + return false; + } + } + toc("parse"); + //This generates a new file name + newCompetition("-"); + + if (!Import) { + strcpy_s(CurrentFile, MAX_PATH, file.c_str()); //Keep new file name, if imported + + _splitpath_s(CurrentFile, NULL, 0, NULL,0, CurrentNameId, 64, NULL, 0); + int i=0; + while (CurrentNameId[i]) { + if (CurrentNameId[i]=='.') { + CurrentNameId[i]=0; + break; + } + i++; + } + } + bool res = open(xml); + if (res && !Import) + openFileLock->lockFile(file); + return res; +} + +void oEvent::restoreBackup() +{ + string cfile = string(CurrentFile) + ".meos"; + strcpy_s(CurrentFile, cfile.c_str()); +} + +bool oEvent::open(const xmlparser &xml) { + xmlobject xo; + + xo = xml.getObject("Date"); + if (xo) Date=xo.get(); + + xo = xml.getObject("Name"); + if (xo) Name=xo.get(); + + xo = xml.getObject("Annotation"); + if (xo) Annotation = xo.get(); + + xo=xml.getObject("ZeroTime"); + if (xo) ZeroTime=xo.getInt(); + + xo=xml.getObject("Id"); + if (xo) Id=xo.getInt(); + + xo=xml.getObject("oData"); + + if (xo) + oEventData->set(this, xo); + + setCurrency(-1, "", ",", false); + + xo = xml.getObject("NameId"); + if (xo) + strncpy_s(CurrentNameId, xo.get(), sizeof(CurrentNameId)); + + toc("event"); + //Get controls + xo = xml.getObject("ControlList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + set knownControls; + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Control")){ + oControl c(this); + c.set(&*it); + + if (c.Id>0 && knownControls.count(c.Id) == 0) { + Controls.push_back(c); + knownControls.insert(c.Id); + } + } + } + } + + toc("controls"); + + //Get courses + xo=xml.getObject("CourseList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + set knownCourse; + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Course")){ + oCourse c(this); + c.Set(&*it); + if (c.Id>0 && knownCourse.count(c.Id) == 0) { + addCourse(c); + knownCourse.insert(c.Id); + } + } + } + } + + toc("course"); + + //Get classes + xo=xml.getObject("ClassList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + set knownClass; + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Class")){ + oClass c(this); + c.Set(&*it); + if (c.Id>0 && knownClass.count(c.Id) == 0) { + Classes.push_back(c); + knownClass.insert(c.Id); + } + } + } + } + + toc("class"); + + //Get clubs + xo=xml.getObject("ClubList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Club")){ + oClub c(this); + c.set(*it); + if (c.Id>0) + addClub(c);//Clubs.push_back(c); + } + } + } + + toc("club"); + + //Get runners + xo=xml.getObject("RunnerList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Runner")){ + oRunner r(this, 0); + r.Set(*it); + if (r.Id>0) + addRunner(r, false); + else if (r.Card) + r.Card->tOwner=0; + } + } + } + + toc("runner"); + + //Get teams + xo=xml.getObject("TeamList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Team")){ + oTeam t(this, 0); + t.set(*it); + if (t.Id>0){ + Teams.push_back(t); + teamById[t.Id] = &Teams.back(); + Teams.back().apply(false, 0, true); + } + } + } + } + + toc("team"); + + xo=xml.getObject("PunchList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + if (xl.size() > 10) + setupCardHash(false); // This improves performance when there are many cards. + oFreePunch::disableHashing = true; + try { + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Punch")){ + oFreePunch p(this, 0, 0, 0); + p.Set(&*it); + addFreePunch(p); + } + } + } + catch(...) { + oFreePunch::disableHashing = false; + throw; + } + oFreePunch::disableHashing = false; + oFreePunch::rehashPunches(*this, 0, 0); + setupCardHash(true); // Clear + } + + toc("punch"); + + xo=xml.getObject("CardList"); + if (xo){ + xmlList xl; + xo.getObjects(xl); + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Card")){ + oCard c(this); + c.Set(*it); + assert(c.Id>=0); + Cards.push_back(c); + } + } + } + + toc("card"); + + xo=xml.getObject("Updated"); + if (xo) Modified.setStamp(xo.get()); + + adjustTeamMultiRunners(0); + updateFreeId(); + reEvaluateAll(set(), true); //True needed to update data for sure + + toc("update"); + string err; + + try { + xmlobject xList = xml.getObject("Lists"); + if (xList) { + if (!listContainer->load(MetaListContainer::ExternalList, xList, true)) { + err = "Visa listor är gjorda i en senare version av MeOS och kunde inte laddas."; + } + } + } + catch (const std::exception &ex) { + if (err.empty()) + err = ex.what(); + } + getMeOSFeatures().deserialize(getDCI().getString("Features"), *this); + + if (!err.empty()) + throw meosException(err); + + return true; +} + +bool oEvent::openRunnerDatabase(char* filename) +{ + char file[260]; + getUserFile(file, filename); + + char fclub[260]; + char frunner[260]; + + strcpy_s(fclub, file); + strcat_s(fclub, ".clubs"); + + strcpy_s(frunner, file); + strcat_s(frunner, ".persons"); + + try { + if (fileExist(fclub) && fileExist(frunner)) { + runnerDB->loadClubs(fclub); + runnerDB->loadRunners(frunner); + } + } + catch(std::exception &ex) { + MessageBox(0, ex.what(), "Error", MB_OK); + } + return true; +} + +pRunner oEvent::dbLookUpById(__int64 extId) const +{ + if (!useRunnerDb()) + return 0; + oEvent *toe = const_cast(this); + static oRunner sRunner = oRunner(toe, 0); + sRunner = oRunner(toe, 0); + RunnerDBEntry *dbr = runnerDB->getRunnerById(int(extId)); + if (dbr != 0) { + sRunner.init(*dbr); + /*dbr->getName(sRunner.Name); + sRunner.CardNo = dbr->cardNo; + sRunner.Club = runnerDB->getClub(dbr->clubNo); + sRunner.getDI().setString("Nationality", dbr->getNationality()); + sRunner.getDI().setInt("BirthYear", dbr->getBirthYear()); + sRunner.getDI().setString("Sex", dbr->getSex()); + sRunner.setExtIdentifier(dbr->getExtId());*/ + return &sRunner; + } + else + return 0; +} + +pRunner oEvent::dbLookUpByCard(int cardNo) const +{ + if (!useRunnerDb()) + return 0; + + oEvent *toe = const_cast(this); + static oRunner sRunner = oRunner(toe, 0); + sRunner = oRunner(toe, 0); + RunnerDBEntry *dbr = runnerDB->getRunnerByCard(cardNo); + if (dbr != 0) { + dbr->getName(sRunner.sName); + oRunner::getRealName(sRunner.sName, sRunner.tRealName); + sRunner.init(*dbr); + sRunner.CardNo = cardNo; + return &sRunner; + } + else + return 0; +} + +pRunner oEvent::dbLookUpByName(const string &name, int clubId, int classId, int birthYear) const +{ + if (!useRunnerDb()) + return 0; + + oEvent *toe = const_cast(this); + + static oRunner sRunner = oRunner(toe, 0); + sRunner = oRunner(toe, 0); + + if (birthYear == 0) { + pClass pc = getClass(classId); + + int expectedAge = pc ? pc->getExpectedAge() : 0; + + if (expectedAge>0) + birthYear = getThisYear() - expectedAge; + } + + pClub pc = getClub(clubId); + + if (pc && pc->getExtIdentifier()>0) + clubId = (int)pc->getExtIdentifier(); + + RunnerDBEntry *dbr = runnerDB->getRunnerByName(name, clubId, birthYear); + + if (dbr) { + sRunner.init(*dbr); + /* + dbr->getName(sRunner.Name); + sRunner.CardNo = dbr->cardNo; + sRunner.Club = runnerDB->getClub(dbr->clubNo); + sRunner.getDI().setString("Nationality", dbr->getNationality()); + sRunner.getDI().setInt("BirthYear", dbr->getBirthYear()); + sRunner.getDI().setString("Sex", dbr->getSex());*/ + sRunner.setExtIdentifier(int(dbr->getExtId())); + return &sRunner; + } + + return 0; +} + +bool oEvent::saveRunnerDatabase(char *filename, bool onlyLocal) +{ + char file[260]; + getUserFile(file, filename); + + char fclub[260]; + char frunner[260]; + strcpy_s(fclub, file); + strcat_s(fclub, ".clubs"); + + strcpy_s(frunner, file); + strcat_s(frunner, ".persons"); + + if (!onlyLocal || !runnerDB->isFromServer()) { + runnerDB->saveClubs(fclub); + runnerDB->saveRunners(frunner); + } + return true; +} + +void oEvent::updateRunnerDatabase() +{ + if (Name=="!TESTTÄVLING") + return; + + if (useRunnerDb()) { + oRunnerList::iterator it; + map clubIdMap; + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (it->Card && it->Card->cardNo == it->CardNo && + it->getDI().getInt("CardFee")==0 && it->Card->getNumPunches()>7) + updateRunnerDatabase(&*it, clubIdMap); + } + runnerDB->refreshTables(); + } + if (listContainer) { + for (int k = 0; k < listContainer->getNumLists(); k++) { + if (listContainer->isExternal(k)) { + MetaList &ml = listContainer->getList(k); + string uid = ml.getUniqueId() + ".meoslist"; + char file[260]; + getUserFile(file, uid.c_str()); + if (!fileExist(file)) { + ml.save(file, this); + } + } + } + } +} + +void oEvent::updateRunnerDatabase(pRunner r, map &clubIdMap) +{ + if (!r->CardNo) + return; + runnerDB->updateAdd(*r, clubIdMap); +} + +pCourse oEvent::addCourse(const string &pname, int plengh, int id) +{ + oCourse c(this, id); + c.Length = plengh; + c.Name = pname; + return addCourse(c); +} + +pCourse oEvent::addCourse(const oCourse &oc) +{ + if (oc.Id==0) + return 0; + else { + pCourse pOld=getCourse(oc.getId()); + if (pOld) + return 0; + } + Courses.push_back(oc); + qFreeCourseId=max(qFreeCourseId, oc.getId()); + + pCourse pc = &Courses.back(); + + if (!pc->existInDB()) { + pc->updateChanged(); + pc->synchronize(); + } + courseIdIndex[oc.Id] = pc; + return pc; +} + +void oEvent::autoAddTeam(pRunner pr) +{ + //Warning: make sure there is no team already in DB that has not yet been applied yet... + if (pr && pr->Class) { + pClass pc = pr->Class; + if (pc->isSingleRunnerMultiStage()) { + //Auto create corresponding team + pTeam t = addTeam(pr->getName(), pr->getClubId(), pc->getId()); + if (pr->StartNo == 0) + pr->StartNo = Teams.size(); + t->setStartNo(pr->StartNo, false); + t->setRunner(0, pr, true); + } + } +} + +void oEvent::autoRemoveTeam(pRunner pr) +{ + if (pr && pr->Class) { + pClass pc = pr->Class; + if (pc->isSingleRunnerMultiStage()) { + if (pr->tInTeam) { + // A team may have more than this runner -> do not remove + bool canRemove = true; + const vector &runners = pr->tInTeam->Runners; + for (size_t k = 0; ksName != pr->sName) + canRemove = false; + } + if (canRemove) + removeTeam(pr->tInTeam->getId()); + } + } + } +} + +pRunner oEvent::addRunner(const string &name, int clubId, int classId, + int cardNo, int birthYear, bool autoAdd) +{ + if (birthYear != 0) + birthYear = extendYear(birthYear); + + pRunner db_r = oe->dbLookUpByCard(cardNo); + + if (db_r && !db_r->matchName(name)) + db_r = 0; // "Existing" card, but different runner + + + if (db_r == 0 && getNumberSuffix(name) == 0) + db_r = oe->dbLookUpByName(name, clubId, classId, birthYear); + + if (db_r) { + // We got name from DB. Other parameters might have changed from DB. + if (clubId>0) + db_r->Club = getClub(clubId); + db_r->Class = getClass(classId); + if (cardNo>0) + db_r->CardNo = cardNo; + if (birthYear>0) + db_r->setBirthYear(birthYear); + return addRunnerFromDB(db_r, classId, autoAdd); + } + oRunner r(this); + r.sName = name; + oRunner::getRealName(r.sName, r.tRealName); + r.Club = getClub(clubId); + r.Class = getClass(classId); + if (cardNo>0) + r.CardNo = cardNo; + if (birthYear>0) + r.setBirthYear(birthYear); + pRunner pr = addRunner(r, true); + + if (pr->getDI().getInt("EntryDate") == 0) + pr->getDI().setDate("EntryDate", getLocalDate()); + if (pr->Class) { + int heat = pr->Class->getDCI().getInt("Heat"); + if (heat != 0) + pr->getDI().setInt("Heat", heat); + } + + pr->updateChanged(); + + if (autoAdd) + autoAddTeam(pr); + return pr; +} + +pRunner oEvent::addRunner(const string &pname, const string &pclub, int classId, + int cardNo, int birthYear, bool autoAdd) +{ + if (!pclub.empty() || getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + pClub club = getClubCreate(0, pclub); + return addRunner(pname, club->getId(), classId, cardNo, birthYear, autoAdd); + } + else + return addRunner(pname, 0, classId, cardNo, birthYear, autoAdd); +} + +pRunner oEvent::addRunnerFromDB(const pRunner db_r, + int classId, bool autoAdd) +{ + oRunner r(this); + r.sName = db_r->sName; + oRunner::getRealName(r.sName, r.tRealName); + r.CardNo = db_r->CardNo; + + if (db_r->Club) { + r.Club = getClub(db_r->getClubId()); + if (!r.Club) + r.Club = addClub(*db_r->Club); + } + + r.Class=classId ? getClass(classId) : 0; + memcpy(r.oData, db_r->oData, sizeof(r.oData)); + + pRunner pr = addRunner(r, true); + if (pr->getDI().getInt("EntryDate") == 0) + pr->getDI().setDate("EntryDate", getLocalDate()); + + if (r.Class) { + int heat = r.Class->getDCI().getInt("Heat"); + if (heat != 0) + pr->getDI().setInt("Heat", heat); + } + + pr->updateChanged(); + + if (autoAdd) + autoAddTeam(pr); + return pr; +} + +pRunner oEvent::addRunner(const oRunner &r, bool updateStartNo) { + bool needUpdate = Runners.empty(); + + Runners.push_back(r); + pRunner pr=&Runners.back(); + if (pr->StartNo == 0 && updateStartNo) { + pr->StartNo = ++nextFreeStartNo; // Need not be unique + } + else { + nextFreeStartNo = max(nextFreeStartNo, pr->StartNo); + } + + if (pr->Card) + pr->Card->tOwner = pr; + + if (HasDBConnection) { + if (!pr->existInDB()) + pr->synchronize(); + } + if (needUpdate) + oe->updateTabs(); + + if (pr->Class) + pr->Class->tResultInfo.clear(); + + bibStartNoToRunnerTeam.clear(); + runnerById[pr->Id] = pr; + + // Notify runner database that runner has entered + getRunnerDatabase().hasEnteredCompetition(r.getExtIdentifier()); + return pr; +} + +pRunner oEvent::addRunnerVacant(int classId) { + pRunner r=addRunner(lang.tl("Vakant"), getVacantClub(), classId, 0,0, true); + if (r) { + r->apply(false, 0, false); + r->synchronize(true); + } + return r; +} + +int oEvent::getFreeCourseId() +{ + qFreeCourseId++; + return qFreeCourseId; +} + +int oEvent::getFreeControlId() +{ + qFreeControlId++; + return qFreeControlId; +} + +string oEvent::getAutoCourseName() const +{ + char bf[32]; + sprintf_s(bf, lang.tl("Bana %d").c_str(), Courses.size()+1); + return bf; +} + +int oEvent::getFreeClassId() +{ + qFreeClassId++; + return qFreeClassId; +} + +int oEvent::getFirstClassId(bool teamClass) const { + for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + int ns = it->getNumStages(); + if (teamClass && ns > 0) + return it->Id; + else if (!teamClass && ns == 0) + return it->Id; + } + return 0; +} + +int oEvent::getFreeCardId() +{ + qFreeCardId++; + return qFreeCardId; +} + +int oEvent::getFreePunchId() +{ + qFreePunchId++; + return qFreePunchId; +} + +string oEvent::getAutoClassName() const +{ + char bf[32]; + sprintf_s(bf, 32, lang.tl("Klass %d").c_str(), Classes.size()+1); + return bf; +} + +string oEvent::getAutoTeamName() const +{ + char bf[32]; + sprintf_s(bf, 32, lang.tl("Lag %d").c_str(), Teams.size()+1); + return bf; +} + +string oEvent::getAutoRunnerName() const +{ + char bf[32]; + sprintf_s(bf, 32, lang.tl("Deltagare %d").c_str(), Runners.size()+1); + return bf; +} + +int oEvent::getFreeClubId() +{ + qFreeClubId++; + return qFreeClubId; +} + +int oEvent::getFreeRunnerId() +{ + qFreeRunnerId++; + return qFreeRunnerId; +} + +void oEvent::updateFreeId(oBase *obj) +{ + if (typeid(*obj)==typeid(oRunner)){ + qFreeRunnerId=max(obj->Id, qFreeRunnerId); + } + else if (typeid(*obj)==typeid(oClass)){ + qFreeClassId=max(obj->Id, qFreeClassId); + } + else if (typeid(*obj)==typeid(oCourse)){ + qFreeCourseId=max(obj->Id, qFreeCourseId); + } + else if (typeid(*obj)==typeid(oControl)){ + qFreeControlId=max(obj->Id, qFreeControlId); + } + else if (typeid(*obj)==typeid(oClub)){ + if (obj->Id != cVacantId) + qFreeClubId=max(obj->Id, qFreeClubId); + } + else if (typeid(*obj)==typeid(oCard)){ + qFreeCardId=max(obj->Id, qFreeCardId); + } + else if (typeid(*obj)==typeid(oFreePunch)){ + qFreePunchId=max(obj->Id, qFreePunchId); + } + else if (typeid(*obj)==typeid(oTeam)){ + qFreeTeamId=max(obj->Id, qFreeTeamId); + } + /*else if (typeid(*obj)==typeid(oEvent)){ + qFree + }*/ +} + +void oEvent::updateFreeId() +{ + { + oRunnerList::iterator it; + qFreeRunnerId=0; + nextFreeStartNo = 0; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + qFreeRunnerId = max(qFreeRunnerId, it->Id); + nextFreeStartNo = max(nextFreeStartNo, it->StartNo); + } + } + { + oClassList::iterator it; + qFreeClassId=0; + for (it=Classes.begin(); it != Classes.end(); ++it) + qFreeClassId=max(qFreeClassId, it->Id); + } + { + oCourseList::iterator it; + qFreeCourseId=0; + for (it=Courses.begin(); it != Courses.end(); ++it) + qFreeCourseId=max(qFreeCourseId, it->Id); + } + { + oControlList::iterator it; + qFreeControlId=0; + for (it=Controls.begin(); it != Controls.end(); ++it) + qFreeControlId=max(qFreeControlId, it->Id); + } + { + oClubList::iterator it; + qFreeClubId=0; + for (it=Clubs.begin(); it != Clubs.end(); ++it) { + if (it->Id != cVacantId) + qFreeClubId=max(qFreeClubId, it->Id); + } + } + { + oCardList::iterator it; + qFreeCardId=0; + for (it=Cards.begin(); it != Cards.end(); ++it) + qFreeCardId=max(qFreeCardId, it->Id); + } + { + oFreePunchList::iterator it; + qFreePunchId=0; + for (it=punches.begin(); it != punches.end(); ++it) + qFreePunchId=max(qFreePunchId, it->Id); + } + + { + oTeamList::iterator it; + qFreeTeamId=0; + for (it=Teams.begin(); it != Teams.end(); ++it) + qFreeTeamId=max(qFreeTeamId, it->Id); + } +} + +int oEvent::getVacantClub() +{ + if (vacantId > 0) + return vacantId; + + pClub pc = getClub("Vakant"); + if (pc == 0) + pc = getClub("Vacant"); //eng + if (pc == 0) + pc = getClub(lang.tl("Vakant")); //other lang? + + if (pc == 0) + pc=getClubCreate(cVacantId, lang.tl("Vakant")); + + vacantId = pc->getId(); + return vacantId; +} + +int oEvent::getVacantClubIfExist() const +{ + if (vacantId > 0) + return vacantId; + if (vacantId == -1) + return 0; + pClub pc=getClub("Vakant"); + if (pc == 0) + pc = getClub("Vacant"); + if (pc == 0) + pc = getClub(lang.tl("Vakant")); //other lang? + + if (!pc) { + vacantId = -1; + return 0; + } + vacantId = pc->getId(); + return vacantId; +} + +pCard oEvent::allocateCard(pRunner owner) +{ + oCard c(this); + c.tOwner = owner; + Cards.push_back(c); + pCard newCard = &Cards.back(); + return newCard; +} + +bool oEvent::sortRunners(SortOrder so) { + reinitializeClasses(); + if (so == Custom) + return false; + CurrentSortOrder=so; + Runners.sort(); + return true; +} + +bool oEvent::sortTeams(SortOrder so, int leg, bool linearLeg) { + reinitializeClasses(); + oTeamList::iterator it; + map classId2Linear; + if (so==ClassResult || so==ClassTotalResult || so == ClassTeamLegResult) { + bool totalResult = so == ClassTotalResult; + bool legResult = so == ClassTeamLegResult; + bool hasRunner = (leg == -1); + for (it=Teams.begin(); it != Teams.end(); ++it) { + int lg = leg; + int clsId = it->Class->getId(); + + if (leg>=0 && !linearLeg && it->Class) { + map::iterator res = classId2Linear.find(it->Class->getId()); + if (res == classId2Linear.end()) { + unsigned linLegBase = it->Class->getLegNumberLinear(leg, 0); + while (linLegBase + 1 < it->Class->getNumStages()) { + if (it->Class->isParallel(linLegBase+1) || it->Class->isOptional(linLegBase+1)) + linLegBase++; + else + break; + } + lg = linLegBase; + //lg = linLegBase + it->Class->getNumParallel(linLegBase) - 1; + classId2Linear[clsId] = lg; + } + else { + lg = res->second; + } + } + + const int lastIndex = it->Class ? it->Class->getLastStageIndex() : 0; + lg = min(lg, lastIndex); + + + if (lg >= leg) + hasRunner = true; + if (legResult) { + pRunner r = it->getRunner(lg); + if (r) { + it->_sortTime = r->getRunningTime(); + it->_cachedStatus = r->getStatus(); + } + else { + it->_sortTime = 0; + it->_cachedStatus = StatusUnknown; + } + } + else { + it->_sortTime=it->getLegRunningTime(lg, totalResult) + it->getNumShortening(lg)*3600*24*10; + it->_cachedStatus = it->getLegStatus(lg, totalResult); + + // Ensure number of restarts has effect on final result + if (lg == lastIndex) + it->_sortTime += it->tNumRestarts*24*3600; + } + unsigned rawStatus = it->_cachedStatus; + it->_sortStatus = RunnerStatusOrderMap[rawStatus < 100u ? rawStatus : 0]; + + } + + if (!hasRunner) + return false; + + Teams.sort(oTeam::compareResult); + } + else if (so==ClassStartTime) { + for (it=Teams.begin(); it != Teams.end(); ++it) { + it->_cachedStatus = StatusUnknown; + it->_sortStatus=0; + it->_sortTime=it->getLegStartTime(leg); + if (it->_sortTime<=0) + it->_sortStatus=1; + } + Teams.sort(oTeam::compareResult); + } + return true; +} +string oEvent::getZeroTime() const +{ + return getAbsTime(0); +} + +void oEvent::setZeroTime(string m) +{ + unsigned nZeroTime = convertAbsoluteTime(m); + if (nZeroTime!=ZeroTime && nZeroTime != -1) { + updateChanged(); + ZeroTime=nZeroTime; + } +} + +void oEvent::setName(const string &m) +{ + if (trim(m).empty()) + throw meosException("Tomt namn är inte tillåtet."); + + if (m != getName()) { + Name = m; + updateChanged(); + } +} + +void oEvent::setAnnotation(const string &m) +{ + if (m!=Annotation) { + Annotation=m; + updateChanged(); + } +} + +string oEvent::getTitleName() const { + if (empty()) + return ""; + if (HasPendingDBConnection) + return getName() + lang.tl(" (på server)") + lang.tl(" DATABASE ERROR"); + else if (isClient()) + return getName() + lang.tl(" (på server)"); + else + return getName() + lang.tl(" (lokalt)"); +} + +void oEvent::setDate(const string &m) +{ + if (m!=Date) { + int d = convertDateYMS(m, true); + if (d <= 0) + throw meosException("Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD).#" + m); + Date = formatDate(d, true); + updateChanged(); + } +} + +const string &oEvent::getAbsTime(DWORD time) const { + DWORD t = ZeroTime + time; + if (int(t)<0) + t = 0; + int days = time/(3600*24); + if (days <= 0) + return formatTimeHMS(t % (24*3600)); + else { + string &res = StringCache::getInstance().get(); + res = itos(days) + "D " + formatTimeHMS(t % (24*3600)); + return res; + } +} + +const string &oEvent::getTimeZoneString() const { + if (!date2LocalTZ.count(Date)) + date2LocalTZ[Date] = ::getTimeZoneString(Date); + return date2LocalTZ[Date]; +} + +string oEvent::getAbsDateTimeISO(DWORD time, bool includeDate, bool useGMT) const +{ + DWORD t = ZeroTime + time; + string dateS, timeS; + if (int(t)<0) { + dateS = "2000-01-01"; + if (useGMT) + timeS = "00:00:00Z"; + else + timeS = "00:00:00" + getTimeZoneString(); + } + else { + int extraDay; + + if (useGMT) { + int offset = ::getTimeZoneInfo(Date); + t += offset; + if (t < 0) { + extraDay = -1; + t += 3600 * 24; + } + else { + extraDay = t / (3600*24); + } + char bf[64]; + sprintf_s(bf, "%02d:%02d:%02dZ", (t/3600)%24, (t/60)%60, t%60); + timeS = bf; + } + else { + char bf[64]; + extraDay = t / (3600*24); + sprintf_s(bf, "%02d:%02d:%02d", (t/3600)%24, (t/60)%60, t%60); + timeS = bf + getTimeZoneString(); + } + + if (extraDay == 0 ) { + dateS = Date; + } + else { + SYSTEMTIME st; + convertDateYMS(Date, st, false); + __int64 sec = SystemTimeToInt64Second(st); + sec = sec + (extraDay * 3600 * 24); + st = Int64SecondToSystemTime(sec); + dateS = convertSystemDate(st); + } + } + + if (includeDate) + return dateS + "T" + timeS; + else + return timeS; +} + +const string &oEvent::getAbsTimeHM(DWORD time) const +{ + DWORD t=ZeroTime+time; + + if (int(t)<0) + return MakeDash("-"); + + char bf[32]; + sprintf_s(bf, "%02d:%02d", (t/3600)%24, (t/60)%60); + + string &res = StringCache::getInstance().get(); + res = bf; + return res; +} + +//Absolute time string to absolute time int (used by cvs-parser) +int oEvent::convertAbsoluteTime(const string &m) +{ + if (m.empty() || m[0]=='-') + return -1; + + int len=m.length(); + bool firstComma = false; + for (int k=0;k='0' && b<='9')) ) { + if (b==':' && firstComma == false) + continue; + else if ((b==',' || b=='.') && firstComma == false) { + firstComma = true; + continue; + } + return -1; + } + } + + int hour=atoi(m.c_str()); + + if (hour<0 || hour>23) + return -1; + + int minute=0; + int second=0; + + int kp=m.find_first_of(':'); + + if (kp>0) + { + string mtext=m.substr(kp+1); + minute=atoi(mtext.c_str()); + + if (minute<0 || minute>60) + minute=0; + + kp=mtext.find_last_of(':'); + + if (kp>0) { + second=atoi(mtext.substr(kp+1).c_str()); + + if (second<0 || second>60) + second=0; + } + } + int t=hour*3600+minute*60+second; + + if (t<0) return 0; + + return t; +} + +int oEvent::getRelativeTime(const string &date, const string &absoluteTime, const string &timeZone) const { + + int atime=convertAbsoluteTime(absoluteTime); + + if (timeZone == "Z" || timeZone == "z") { + SYSTEMTIME st; + convertDateYMS(date, st, false); + + st.wHour = atime / 3600; + st.wMinute = (atime / 60) % 60; + st.wSecond = atime % 60; + + SYSTEMTIME localTime; + memset(&localTime, 0, sizeof(SYSTEMTIME)); + SystemTimeToTzSpecificLocalTime(0, &st, &localTime); + + atime = localTime.wHour*3600 + localTime.wMinute * 60 + localTime.wSecond; + } + + if (atime>=0 && atime<3600*24){ + int rtime=atime-ZeroTime; + + if (rtime<=0) + rtime+=3600*24; + + //Don't allow times just before zero time. + if (rtime>3600*23) + return -1; + + return rtime; + } + else return -1; +} + + +int oEvent::getRelativeTime(const string &m) const +{ + int dayIndex = 0; + for (size_t k = 0; k + 1 < m.length(); k++) { + int c = m[k]; + if (c == 'D' || c == 'd' || c == 'T' || c == 't') { + dayIndex = k + 1; + break; + } + } + + int atime; + int days = 0; + if (dayIndex == 0) + atime = convertAbsoluteTime(m); + else { + atime = convertAbsoluteTime(m.substr(dayIndex)); + days = atoi(m.c_str()); + } + if (atime>=0 && atime <= 3600*24){ + int rtime = atime-ZeroTime; + + if (rtime < 0) + rtime += 3600*24; + + rtime += days * 3600 * 24; + //Don't allow times just before zero time. + //if (rtime>3600*22) + // return -1; + + return rtime; + } + else return -1; +} + +int oEvent::getRelativeTimeFrom12Hour(const string &m) const +{ + int atime=convertAbsoluteTime(m); + + if (atime>=0 && atime<3600*24) { + int lowBound = ZeroTime; + int highBound = ZeroTime + 3600 * 12; + + bool ok = ( atime >= lowBound && atime <= highBound) || + ( (atime+3600*24) >= lowBound && (atime+3600*24) <= highBound); + + int rtime = atime - ZeroTime; + if (!ok) + rtime += 12 * 3600; + + rtime = (rtime+24*3600)%(24*3600); + + //int rtime=atime-(ZeroTime % (3600*12)); + +/* if (rtime<=0) + rtime+=3600*12; + */ + //Don't allow times just before zero time. + if (rtime>3600*22) + return -1; + + return rtime; + } + else return -1; +} + +void oEvent::removeRunner(const vector &ids) +{ + oRunnerList::iterator it; + + set toRemove; + for (size_t k = 0; k < ids.size(); k++) { + int Id = ids[k]; + pRunner r=getRunner(Id, 0); + + if (r==0) + continue; + + r = r->tParentRunner ? r->tParentRunner : r; + + if (toRemove.count(r->getId())) + continue; //Already found. + + //Remove a singe runner team + autoRemoveTeam(r); + + for (size_t k=0;kmultiRunner.size();k++) + if (r->multiRunner[k]) + toRemove.insert(r->multiRunner[k]->getId()); + + toRemove.insert(Id); + } + + if (toRemove.empty()) + return; + + dataRevision++; + set affectedCls; + for (it=Runners.begin(); it != Runners.end();){ + oRunner &cr = *it; + if (toRemove.count(cr.getId())> 0) { + if (cr.Class) + affectedCls.insert(cr.Class); + if (HasDBConnection) + msRemove(&cr); + toRemove.erase(cr.getId()); + runnerById.erase(cr.getId()); + if (cr.Card) { + assert( cr.Card->tOwner == &cr ); + cr.Card->tOwner = 0; + } + // Reset team runner (this should not happen) + if (it->tInTeam) { + if (it->tInTeam->Runners[it->tLeg]==&*it) + it->tInTeam->Runners[it->tLeg] = 0; + } + + oRunnerList::iterator next = it; + ++next; + + Runners.erase(it); + if (toRemove.empty()) { + break; + } + else + it = next; + } + else + ++it; + } + + for (set::iterator it = affectedCls.begin(); it != affectedCls.end(); ++it) { + (*it)->clearCache(true); + (*it)->markSQLChanged(-1,-1); + } + + oe->updateTabs(); +} + +void oEvent::removeCourse(int Id) +{ + oCourseList::iterator it; + + for (it=Courses.begin(); it != Courses.end(); ++it){ + if (it->Id==Id){ + if (HasDBConnection) + msRemove(&*it); + dataRevision++; + Courses.erase(it); + courseIdIndex.erase(Id); + return; + } + } +} + +void oEvent::removeClass(int Id) +{ + oClassList::iterator it; + + for (it=Classes.begin(); it != Classes.end(); ++it){ + if (it->Id==Id){ + if (HasDBConnection) + msRemove(&*it); + Classes.erase(it); + dataRevision++; + updateTabs(); + return; + } + } +} + +void oEvent::removeControl(int Id) +{ + oControlList::iterator it; + + for (it=Controls.begin(); it != Controls.end(); ++it){ + if (it->Id==Id){ + if (HasDBConnection) + msRemove(&*it); + Controls.erase(it); + dataRevision++; + return; + } + } +} + +void oEvent::removeClub(int Id) +{ + oClubList::iterator it; + + for (it=Clubs.begin(); it != Clubs.end(); ++it){ + if (it->Id==Id) { + if (HasDBConnection) + msRemove(&*it); + Clubs.erase(it); + clubIdIndex.erase(Id); + dataRevision++; + return; + } + } + if (vacantId == Id) + vacantId = 0; // Clear vacant id +} + +void oEvent::removeCard(int Id) +{ + oCardList::iterator it; + + for (it=Cards.begin(); it != Cards.end(); ++it) { + if (it->getOwner() == 0 && it->Id == Id) { + if (it->tOwner) { + if (it->tOwner->Card == &*it) + it->tOwner->Card = 0; + } + if (HasDBConnection) + msRemove(&*it); + Cards.erase(it); + dataRevision++; + return; + } + } +} + +bool oEvent::isCourseUsed(int Id) const +{ + oClassList::const_iterator it; + + for (it=Classes.begin(); it != Classes.end(); ++it){ + if (it->isCourseUsed(Id)) + return true; + } + + oRunnerList::const_iterator rit; + + for (rit=Runners.begin(); rit != Runners.end(); ++rit){ + pCourse pc=rit->getCourse(false); + if (pc && pc->Id==Id) + return true; + } + return false; +} + +bool oEvent::isClassUsed(int Id) const +{ + //Search runners + oRunnerList::const_iterator it; + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (it->getClassId()==Id) + return true; + } + + //Search teams + oTeamList::const_iterator tit; + for (tit=Teams.begin(); tit != Teams.end(); ++tit){ + if (tit->getClassId()==Id) + return true; + } + return false; +} + +bool oEvent::isClubUsed(int Id) const +{ + //Search runners + oRunnerList::const_iterator it; + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (it->getClubId()==Id) + return true; + } + + //Search teams + oTeamList::const_iterator tit; + for (tit=Teams.begin(); tit != Teams.end(); ++tit){ + if (tit->getClubId()==Id) + return true; + } + + return false; +} + +bool oEvent::isRunnerUsed(int Id) const +{ + //Search teams + oTeamList::const_iterator tit; + for (tit=Teams.begin(); tit != Teams.end(); ++tit){ + if (tit->isRunnerUsed(Id)) { + if (tit->Class && tit->Class->isSingleRunnerMultiStage()) + //Don't report single-runner-teams as blocking + continue; + return true; + } + } + + return false; +} + +bool oEvent::isControlUsed(int Id) const +{ + oCourseList::const_iterator it; + + for (it=Courses.begin(); it != Courses.end(); ++it){ + + for(int i=0;inControls;i++) + if (it->Controls[i] && it->Controls[i]->Id==Id) + return true; + } + return false; +} + +bool oEvent::classHasResults(int Id) const +{ + oRunnerList::const_iterator it; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + if ( (Id == 0 || it->getClassId() == Id) && (it->getCard() || it->FinishTime)) + return true; + } + + return false; +} + +bool oEvent::classHasTeams(int Id) const +{ + oTeamList::const_iterator it; + + for (it=Teams.begin(); it != Teams.end(); ++it) + if (it->getClassId()==Id) + return true; + + return false; +} + +void oEvent::generateVacancyList(gdioutput &gdi, GUICALLBACK cb) +{ + sortRunners(ClassStartTime); + oRunnerList::iterator it; + + // BIB, START, NAME, CLUB, SI + int dx[5]={0, 0, 70, 150}; + + bool withbib=hasBib(true, false); + int i; + + if (withbib) for (i=1;i<4;i++) dx[i]+=40; + + int y=gdi.getCY(); + int x=gdi.getCX(); + int lh=gdi.getLineHeight(); + + const int yStart = y; + int nVac = 0; + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->skip() || !it->isVacant()) + continue; + nVac++; + } + + int nCol = 1 + min(3, nVac/10); + int RunnersPerCol = nVac / nCol; + + char bf[256]; + int nRunner = 0; + y+=lh; + + int Id=0; + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (it->skip() || !it->isVacant()) + continue; + + if (it->getClassId() != Id) { + Id=it->getClassId(); + y+=lh/2; + + if (nRunner>=RunnersPerCol) { + y = yStart; + x += dx[3]+5; + nRunner = 0; + } + + + gdi.addStringUT(y, x+dx[0], 1, it->getClass()); + y+=lh+lh/3; + } + + oDataInterface DI=it->getDI(); + + if (withbib) { + string bib=it->getBib(); + + if (!bib.empty()) { + gdi.addStringUT(y, x+dx[0], 0, bib); + } + } + gdi.addStringUT(y, x+dx[1], 0, it->getStartTimeS(), 0, cb).setExtra(it->getId()); + + _itoa_s(it->Id, bf, 256, 10); + gdi.addStringUT(y, x+dx[2], 0, it->getName(), dx[3]-dx[2]-4, cb).setExtra(it->getId()); + //gdi.addStringUT(y, x+dx[3], 0, it->getClub()); + + y+=lh; + nRunner++; + } + if (nVac==0) + gdi.addString("", y, x, 0, "Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning."); + gdi.updateScrollbars(); +} + +void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb_nostart) +{ + //Lazy setup: tie runners and persons + oFreePunch::rehashPunches(*oe, 0, 0); + + // Map cardNo -> punch + multimap punchHash; + map cardCount; + + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && it->getCardNo() > 0) + ++cardCount[it->getCardNo()]; + } + + typedef multimap::const_iterator TPunchIter; + + for (oFreePunchList::iterator it = punches.begin(); it != punches.end(); ++it) { + punchHash.insert(make_pair(it->getCardNo(), &*it)); + } + + sortTeams(ClassStartTime, 0, true); + int y=gdi.getCY(); + int x=gdi.getCX(); + int lh=gdi.getLineHeight(); + + oTeamList::iterator it; + gdi.addStringUT(2, lang.tl("Kvar-i-skogen") + MakeDash(" - ") + getName()); + y+=lh/2; + + gdi.addStringUT(1, getDate()); + + gdi.dropLine(); + + y+=3*lh; + int id=0; + int nr=0; + + for(it=Teams.begin(); it!=Teams.end(); ++it) { + if (it->isRemoved()) + continue; + + if (it->tStatus==StatusUnknown) { + + if (id != it->getClassId()) { + if (nr>0) { + gdi.addString("", y, x, 0, "Antal: X#"+itos(nr)); + y+=lh; + nr=0; + } + y += lh; + id = it->getClassId(); + gdi.addStringUT(y, x, 1, it->getClass()); + y += lh; + } + gdi.addStringUT(y, x, 0, it->getClass()); + nr++; + gdi.addStringUT(y, x+100, 0, it->getName(), 0, cb).setExtra(it->getId()).id = "T"; + y+=lh; + } + } + + if (nr>0) { + gdi.addString("", y, x, 0, "Antal: X#"+itos(nr)); + y+=lh; + } + + { + int tnr = 0; + id=0; + nr=0; + sortRunners(ClassStartTime); + + oRunnerList::iterator it; + + int dx[4]={0, 70, 350, 470}; + int y=gdi.getCY(); + int x=gdi.getCX(); + int lh=gdi.getLineHeight(); + + y+=lh; + char bf[256]; + + y=gdi.getCY(); + vector rr; + setupCardHash(false); + + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (it->skip() || it->needNoCard()) + continue; + + if (it->tStatus == StatusUnknown) { + + if (id != it->getClassId()) { + if (nr>0) { + gdi.addString("", y, x, 0, "Antal: X#"+itos(nr)); + y+=lh; + nr=0; + } + y += lh; + id = it->getClassId(); + gdi.addStringUT(y, x, 1, it->getClass()); + y += lh; + } + + bool hasPunch = false; + string punches; + string otherRunners; + pair range = punchHash.equal_range(it->getCardNo()); + for (TPunchIter pit = range.first; pit != range.second; ++pit) { + if (pit->second->tRunnerId == it->getId()) { + if (hasPunch) + punches.append(", "); + else + hasPunch = true; + + punches.append(pit->second->getSimpleString()); + } + } + + getRunnersByCardNo(it->getCardNo(), true, true, rr); + for (size_t k = 0; k < rr.size(); k++) { + if (rr[k]->getId() != it->getId()) { + if (otherRunners.empty()) { + otherRunners = lang.tl("Bricka X används också av: #" + itos(it->getCardNo())); + } + else { + otherRunners += ", "; + } + otherRunners += rr[k]->getName(); + } + } + gdi.addStringUT(y, x+dx[0], 0, it->getStartTimeS()); + string club = it->getClub(); + if (!club.empty()) + club = " (" + club + ")"; + + gdi.addStringUT(y, x+dx[1], 0, it->getName()+club, dx[2]-dx[1]-4, cb).setExtra(it->getId()).id = "R"; + _itoa_s(it->Id, bf, 256, 10); + nr++; + tnr++; + + if (hasPunch) { + if (otherRunners.empty()) { + RECT rc = gdi.addString("", y, x+dx[2], 0, "(har stämplat)", dx[3]-dx[2]-4).textRect; + capitalize(punches); + gdi.addToolTip("", "#" + punches, 0, &rc); + } + else { + // Återanvänd bricka + RECT rc = gdi.addString("", y, x+dx[2], 0, "#(" + lang.tl("reused card") + ")", dx[3]-dx[2]-4).textRect; + capitalize(punches); + gdi.addToolTip("", "#" + punches + ". " + otherRunners, 0, &rc); + } + } + gdi.addStringUT(y, x+dx[3], 0, it->getClass()); + y+=lh; + } + } + if (nr>0) { + gdi.addString("", y, x, 0, "Antal: X#"+itos(nr)); + y+=lh; + } + + if (tnr == 0 && Runners.size()>0) { + gdi.addString("", 10, "inforestwarning"); + } + } + setupCardHash(true); + + gdi.updateScrollbars(); +} + +void oEvent::generateMinuteStartlist(gdioutput &gdi) { + sortRunners(SortByStartTime); + + int dx[4]={0, gdi.scaleLength(70), gdi.scaleLength(340), gdi.scaleLength(510)}; + int y=gdi.getCY(); + int x=gdi.getCX(); + int lh=gdi.getLineHeight(); + + vector blocks; + vector starts; + getStartBlocks(blocks, starts); + + char bf[256]; + for (size_t k=0;k0) + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + + gdi.addStringUT(boldLarge, lang.tl("Minutstartlista") + MakeDash(" - ") + getName()); + if (!starts[k].empty()) { + sprintf_s(bf, lang.tl("%s, block: %d").c_str(), starts[k].c_str(), blocks[k]); + gdi.addStringUT(fontMedium, bf); + } + else if (blocks[k]!=0) { + sprintf_s(bf, lang.tl("Startblock: %d").c_str(), blocks[k]); + gdi.addStringUT(fontMedium, bf); + } + + vector< vector< vector > > sb; + sb.reserve(Runners.size()); + int LastStartTime=-1; + for (oRunnerList::iterator it=Runners.begin(); it != Runners.end(); ++it) { + if (it->Class && it->Class->getBlock()!=blocks[k]) + continue; + if (it->Class && it->Class->getStart() != starts[k] ) + continue; + if (!it->Class && blocks[k]!=0) + continue; + if (it->getStatus() == StatusNotCompetiting) + continue; + + if (LastStartTime!=it->tStartTime) { + sb.resize(sb.size() + 1); + LastStartTime = it->tStartTime; + } + + if (sb.empty()) + sb.resize(1); + + if (it->tInTeam == 0) + sb.back().push_back(vector(1, &*it)); + else { + if (it->legToRun() > 0 && it->getStartTime() == 0) + continue; + int minIx = 10000; + for (int j = 0; j < it->tInTeam->getNumRunners(); j++) { + if (j != it->tLeg && + it->tInTeam->Runners[j] && + it->tInTeam->Runners[j]->tStartTime == it->tStartTime) + minIx = min(minIx, j); + } + if (minIx == 10000) + sb.back().push_back(vector(1, &*it)); // Single runner on this start time + else if (minIx > it->tLeg) { + sb.back().push_back(vector()); + for (int j = 0; j < it->tInTeam->getNumRunners(); j++) { + if (it->tInTeam->Runners[j] && + it->tInTeam->Runners[j]->tStartTime == it->tStartTime) + sb.back().back().push_back(it->tInTeam->Runners[j]); + } + } + } + } + + y = gdi.getCY(); + for (size_t k = 0; k < sb.size(); k++) { + if (sb[k].empty()) + continue; + y+=lh/2; + gdi.addStringUT(y, x+dx[0], boldText, sb[k][0][0]->getStartTimeS()); + y+=lh; + + for (size_t j = 0; j < sb[k].size(); j++) { + const int src_y = y; + int indent = 0; + const vector &r = sb[k][j]; + if (r.size() == 1) { + if (r[0]->getCardNo()>0) + gdi.addStringUT(y, x+dx[0], fontMedium, itos(r[0]->getCardNo())); + + string name; + if (r[0]->getBib().empty()) + name = r[0]->getName(); + else + name = r[0]->getName() + " (" + r[0]->getBib() + ")"; + gdi.addStringUT(y, x+dx[1], fontMedium, name, dx[2]-dx[1]-4); + } + else { + string name; + if (!r[0]->tInTeam->getBib().empty()) + name = r[0]->tInTeam->getBib() + ": "; + + int nnames = 0; + for (size_t i = 0; i < r.size(); i++) { + if (nnames>0) + name += ", "; + nnames++; + + if (nnames > 2) { + gdi.addStringUT(y, x+dx[0]+indent, fontMedium, name, dx[2]-dx[0]-4-indent); + name.clear(); + nnames = 1; + y+=lh; + indent = gdi.scaleLength(20); + } + + name += r[i]->getName(); + if (r[i]->getCardNo()>0) { + name += " (" + itos(r[i]->getCardNo()) + ")"; + } + + } + gdi.addStringUT(y, x+dx[0]+indent, fontMedium, name, dx[2]-dx[0]-4-indent); + } + + gdi.addStringUT(src_y, x+dx[2], fontMedium, r[0]->getClub(), dx[3]-dx[2]-4); + gdi.addStringUT(src_y, x+dx[3], fontMedium, r[0]->getClass()); + y+=lh; + } + } + } + gdi.refresh(); +} + +const string &oEvent::getName() const { + if (Name.size() > 1 && Name.at(0) == '%') { + return lang.tl(Name.substr(1)); + } + else + return Name; +} + +bool oEvent::empty() const +{ + return Name.empty(); +} + +void oEvent::clearListedCmp() +{ + cinfo.clear(); +} + +bool oEvent::enumerateCompetitions(const char *file, const char *filetype) +{ + WIN32_FIND_DATA fd; + + char dir[MAX_PATH]; + char FullPath[MAX_PATH]; + + strcpy_s(dir, MAX_PATH, file); + + if (dir[strlen(file)-1]!='\\') + strcat_s(dir, MAX_PATH, "\\"); + + strcpy_s(FullPath, MAX_PATH, dir); + + strcat_s(dir, MAX_PATH, filetype); + + HANDLE h=FindFirstFile(dir, &fd); + + if (h==INVALID_HANDLE_VALUE) + return false; + + bool more=true; + int id=1; + cinfo.clear(); + + while (more) { + if (fd.cFileName[0]!='.') //Avoid .. and . + { + char FullPathFile[MAX_PATH]; + strcpy_s(FullPathFile, MAX_PATH, FullPath); + strcat_s(FullPathFile, MAX_PATH, fd.cFileName); + + CompetitionInfo ci; + + ci.FullPath=FullPathFile; + ci.Name=""; + ci.Date="2007-01-01"; + ci.Id=id++; + + SYSTEMTIME st; + FileTimeToSystemTime(&fd.ftLastWriteTime, &st); + ci.Modified=convertSystemTime(st); + xmlparser xp(0); + + try { + xp.read(FullPathFile, 8); + + const xmlobject date=xp.getObject("Date"); + + if (date) ci.Date=date.get(); + + const xmlobject name=xp.getObject("Name"); + + if (name) { + ci.Name=name.get(); + if (ci.Name.size() > 1 && ci.Name.at(0) == '%') { + ci.Name = lang.tl(ci.Name.substr(1)); + } + } + const xmlobject annotation=xp.getObject("Annotation"); + + if (annotation) + ci.Annotation=annotation.get(); + + const xmlobject nameid = xp.getObject("NameId"); + if (nameid) + ci.NameId = nameid.get(); + + cinfo.push_front(ci); + } + catch (std::exception &) { + // XXX Do what?? + } + } + more=FindNextFile(h, &fd)!=0; + } + + FindClose(h); + + if (!getServerName().empty()) + msListCompetitions(this); + + for (list::iterator it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Name.size() > 1 && it->Name[0] == '%') + it->Name = lang.tl(it->Name.substr(1)); + } + + return true; +} + +bool oEvent::enumerateBackups(const char *file) +{ + backupInfo.clear(); + + enumerateBackups(file, "*.meos.bu?", 1); + enumerateBackups(file, "*.removed", 1); + enumerateBackups(file, "*.dbmeos*", 2); + backupInfo.sort(); + + int id = 1; + for (list::iterator it = backupInfo.begin(); it != backupInfo.end(); ++it) { + it->backupId = id++; + } + return true; +} + +const BackupInfo &oEvent::getBackup(int bid) const { + for (list::const_iterator it = backupInfo.begin(); it != backupInfo.end(); ++it) { + if (it->backupId == bid) { + return *it; + } + } + throw meosException("Internal error"); +} + +void oEvent::deleteBackups(const BackupInfo &bu) { + string file = bu.fileName + bu.Name; + list toRemove; + + for (list::iterator it = backupInfo.begin(); it != backupInfo.end(); ++it) { + if (file == it->fileName + it->Name) + toRemove.push_back(it->FullPath); + } + if (!toRemove.empty()) { + char path[260]; + char drive[48]; + char filename[260]; + char ext[64]; + //_splitpath_s(toRemove.back().c_str(), drive, ds, path, dirs, filename, fns, ext, exts); + _splitpath_s(toRemove.back().c_str(), drive, path, filename, ext); + + string dest = string(drive) + path; + toRemove.push_back(dest + bu.fileName + ".persons"); + toRemove.push_back(dest + bu.fileName + ".clubs"); + + for (list::iterator it = toRemove.begin(); it != toRemove.end(); ++it) { + DeleteFile(it->c_str()); + } + } +} + + +bool oEvent::listBackups(gdioutput &gdi, GUICALLBACK cb) +{ + int y = gdi.getCY(); + int x = gdi.getCX(); + + list::iterator it = backupInfo.begin(); + while (it != backupInfo.end()) { + list::iterator sum_size = it; + size_t s = 0; + //string date = it->Modified; + string file = it->fileName + it->Name; + + while(sum_size != backupInfo.end() && file == sum_size->fileName + sum_size->Name) { + s += sum_size->fileSize; + ++sum_size; + } + string type = lang.tl(it->type==1 ? "backup" : "serverbackup"); + string size; + if (s < 1024) { + size = itos(s) + " bytes"; + } + else if (s < 1024*512) { + size = itos(s/1024) + " kB"; + } + else { + size = itos(s/(1024*1024)) + "." + itos( ((10*(s/1024))/1024)%10) + " MB"; + } + gdi.dropLine(); + gdi.addStringUT(gdi.getCY(), gdi.getCX(), boldText, it->Name + " (" + it->Date + ") " + type, 400); + + gdi.pushX(); + gdi.fillRight(); + gdi.addString("", 0, "Utrymme: X#" + size); + gdi.addString("EraseBackup", 0, "[Radera]", cb).setExtra(it->backupId); + gdi.fillDown(); + gdi.popX(); + gdi.dropLine(1.5); + y = gdi.getCY(); + while(it != backupInfo.end() && file == it->fileName + it->Name) { + gdi.addStringUT(y, x+30, 0, it->Modified, 400, cb).setExtra(it->backupId); + ++it; + y += gdi.getLineHeight(); + } + } + + return true; +} + +bool BackupInfo::operator<(const BackupInfo &ci) +{ + if (Date!=ci.Date) + return Date>ci.Date; + + if (fileName!=ci.fileName) + return fileNameci.Modified; +} + + +bool oEvent::enumerateBackups(const char *file, const char *filetype, int type) +{ + WIN32_FIND_DATA fd; + char dir[MAX_PATH]; + char FullPath[MAX_PATH]; + + strcpy_s(dir, MAX_PATH, file); + + if (dir[strlen(file)-1]!='\\') + strcat_s(dir, MAX_PATH, "\\"); + + strcpy_s(FullPath, MAX_PATH, dir); + strcat_s(dir, MAX_PATH, filetype); + HANDLE h=FindFirstFile(dir, &fd); + + if (h==INVALID_HANDLE_VALUE) + return false; + + bool more=true; + while (more) { + if (fd.cFileName[0]!='.') {//Avoid .. and . + char FullPathFile[MAX_PATH]; + strcpy_s(FullPathFile, MAX_PATH, FullPath); + strcat_s(FullPathFile, MAX_PATH, fd.cFileName); + + BackupInfo ci; + + ci.type = type; + ci.FullPath=FullPathFile; + ci.Name=""; + ci.Date="2007-01-01"; + ci.fileName = fd.cFileName; + ci.fileSize = fd.nFileSizeLow; + size_t pIndex = ci.fileName.find_first_of("."); + if (pIndex>0 && pIndex 1 && ci.Name.at(0) == '%') { + ci.Name = lang.tl(ci.Name.substr(1)); + } + } + + backupInfo.push_front(ci); + } + catch (std::exception &) { + //XXX Do what? + } + } + more=FindNextFile(h, &fd)!=0; + } + + FindClose(h); + + return true; +} + +bool oEvent::fillCompetitions(gdioutput &gdi, + const string &name, int type, + const string &select) { + cinfo.sort(); + cinfo.reverse(); + list::iterator it; + + gdi.clearList(name); + string b; + int idSel = -1; + //char bf[128]; + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + string annotation; + if (!it->Annotation.empty()) + annotation = " (" + it->Annotation + ")"; + if (it->Server.length()==0) { + if (type==0 || type==1) { + if (it->NameId == select && !select.empty()) + idSel = it->Id; + string bf = "[" + it->Date + "] " + it->Name; + gdi.addItem(name, bf + annotation, it->Id); + } + } + else if (type==0 || type==2) { + if (it->NameId == select && !select.empty()) + idSel = it->Id; + string bf; + if (type==0) + bf = lang.tl("Server: [X] Y#" + it->Date + "#" + it->Name); + else + bf = "[" + it->Date + "] " + it->Name; + + gdi.addItem(name, bf + annotation, 10000000+it->Id); + } + } + + if (idSel != -1) + gdi.selectItemByData(name.c_str(), idSel); + return true; +} + +void tabAutoKillMachines(); + +void oEvent::checkDB() +{ + if (HasDBConnection) { + vector err; + int k=checkChanged(err); + +#ifdef _DEBUG + if (k>0) { + char bf[256]; + sprintf_s(bf, "Databasen innehåller %d osynkroniserade ändringar.", k); + string msg(bf); + for(int i=0;i < min(err.size(), 10);i++) + msg+=string("\n")+err[i]; + + MessageBox(0, msg.c_str(), "Varning/Fel", MB_OK); + } +#endif + } + updateTabs(); + gdibase.setWindowTitle(getTitleName()); +} + +void destroyExtraWindows(); + +void oEvent::clear() +{ + checkDB(); + + if (HasDBConnection) + msMonitor(0); + + HasDBConnection=false; + HasPendingDBConnection = false; + + destroyExtraWindows(); + + while (!tables.empty()) { + tables.begin()->second->releaseOwnership(); + tables.erase(tables.begin()); + } + Table::resetTableIds(); + + getRunnerDatabase().releaseTables(); + getMeOSFeatures().clear(*this); + Id=0; + dataRevision = 0; + tClubDataRevision = -1; + + ZeroTime=0; + Name.clear(); + Annotation.clear(); + + //Make sure no daemon is hunting us. + tabAutoKillMachines(); + + delete directSocket; + directSocket = 0; + + tLongTimesCached = -1; + + //Order of destruction is extreamly important... + runnerById.clear(); + bibStartNoToRunnerTeam.clear(); + Runners.clear(); + Teams.clear(); + teamById.clear(); + + Classes.clear(); + Courses.clear(); + courseIdIndex.clear(); + + Controls.clear(); + + Cards.clear(); + Clubs.clear(); + clubIdIndex.clear(); + + punchIndex.clear(); + punches.clear(); + + updateFreeId(); + + strcpy_s(CurrentNameId, ""); + strcpy_s(CurrentFile, ""); + + sqlCounterRunners=0; + sqlCounterClasses=0; + sqlCounterCourses=0; + sqlCounterControls=0; + sqlCounterClubs=0; + sqlCounterCards=0; + sqlCounterPunches=0; + sqlCounterTeams=0; + + sqlUpdateControls.clear(); + sqlUpdateCards.clear(); + sqlUpdateClubs.clear(); + sqlUpdateClasses.clear(); + sqlUpdateCourses.clear(); + sqlUpdateRunners.clear(); + sqlUpdatePunches.clear(); + sqlUpdateTeams.clear(); + + vacantId = 0; + oEventData->initData(this, sizeof(oData)); + timelineClasses.clear(); + timeLineEvents.clear(); + nextTimeLineEvent = 0; + + tCurrencyFactor = 1; + tCurrencySymbol = "kr"; + tCurrencySeparator = ","; + tCurrencyPreSymbol = false; + + readPunchHash.clear(); + + //Reset speaker data structures. + listContainer->clearExternal(); + while(!generalResults.empty() && generalResults.back().isDynamic()) + generalResults.pop_back(); + + // Cleanup user interface + gdibase.getTabs().clearCompetitionData(); + + MeOSUtil::useHourFormat = getPropertyInt("UseHourFormat", 1) != 0; + + currentNameMode = (NameMode) getPropertyInt("NameMode", FirstLast); +} + +bool oEvent::deleteCompetition() +{ + if (!empty() && !HasDBConnection) { + string removed = string(CurrentFile)+".removed"; + ::remove(removed.c_str()); //Delete old removed file + openFileLock->unlockFile(); + ::rename(CurrentFile, removed.c_str()); + return true; + } + else return false; +} + +void oEvent::newCompetition(const string &name) +{ + openFileLock->unlockFile(); + clear(); + + SYSTEMTIME st; + GetLocalTime(&st); + + Date = convertSystemDate(st); + ZeroTime = st.wHour*3600; + + Name = name; + oEventData->initData(this, sizeof(oData)); + + getDI().setString("Organizer", getPropertyString("Organizer", "")); + getDI().setString("Street", getPropertyString("Street", "")); + getDI().setString("Address", getPropertyString("Address", "")); + getDI().setString("EMail", getPropertyString("EMail", "")); + getDI().setString("Homepage", getPropertyString("Homepage", "")); + + getDI().setInt("CardFee", getPropertyInt("CardFee", 25)); + getDI().setInt("EliteFee", getPropertyInt("EliteFee", 130)); + getDI().setInt("EntryFee", getPropertyInt("EntryFee", 90)); + getDI().setInt("YouthFee", getPropertyInt("YouthFee", 50)); + + getDI().setInt("SeniorAge", getPropertyInt("SeniorAge", 0)); + getDI().setInt("YouthAge", getPropertyInt("YouthAge", 16)); + + getDI().setString("Account", getPropertyString("Account", "")); + getDI().setString("LateEntryFactor", getPropertyString("LateEntryFactor", "50 %")); + + getDI().setString("CurrencySymbol", getPropertyString("CurrencySymbol", "kr")); + getDI().setString("CurrencySeparator", getPropertyString("CurrencySeparator", ".")); + getDI().setInt("CurrencyFactor", getPropertyInt("CurrencyFactor", 1)); + getDI().setInt("CurrencyPreSymbol", getPropertyInt("CurrencyPreSymbol", 0)); + getDI().setString("PayModes", getPropertyString("PayModes", "")); + + setCurrency(-1, "", "", 0); + + char file[260]; + char filename[64]; + sprintf_s(filename, 64, "meos_%d%02d%02d_%02d%02d%02d_%X.meos", + st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + + //strcpy_s(CurrentNameId, filename); + getUserFile(file, filename); + + strcpy_s(CurrentFile, MAX_PATH, file); + _splitpath_s(CurrentFile, NULL, 0, NULL,0, CurrentNameId, 64, NULL, 0); + int i=0; + while (CurrentNameId[i]) { + if (CurrentNameId[i]=='.') { + CurrentNameId[i]=0; + break; + } + i++; + } + + oe->updateTabs(); +} + +void oEvent::reEvaluateCourse(int CourseId, bool DoSync) +{ + oRunnerList::iterator it; + + if (DoSync) + autoSynchronizeLists(false); + + vector mp; + set classes; + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (it->getCourse(false) && it->getCourse(false)->getId()==CourseId){ + classes.insert(it->getClassId()); + } + } + + reEvaluateAll(classes, DoSync); +} + +void oEvent::reEvaluateAll(const set &cls, bool doSync) +{ + if (doSync) + autoSynchronizeLists(false); + + for(oClassList::iterator it=Classes.begin();it!=Classes.end();++it) { + if (cls.empty() || cls.count(it->Id)) { + it->clearSplitAnalysis(); + it->resetLeaderTime(); + it->reinitialize(); + } + } + + for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) { + if (!cls.empty() && cls.count(tit->getClassId()) == 0) + continue; + + tit->resetTmpStore(); + int nr = tit->getNumRunners(); + for (int k = 0; k < nr; k++) { + if (tit->Runners[k]) + tit->Runners[k]->resetTmpStore(); + } + + if (!tit->isRemoved()) { + tit->apply(false, 0, true); + } + } + oRunnerList::iterator it; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!cls.empty() && cls.count(it->getClassId()) == 0) + continue; + + if (!it->tInTeam) { + it->resetTmpStore(); + it->apply(false, 0, true); + } + } + + vector mp; + bool needupdate = true; + int leg = 0; + while (needupdate) { + needupdate = false; + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!cls.empty() && cls.count(it->getClassId()) == 0) + continue; + + if (!it->isRemoved()) { + if (it->tLeg == leg) { + it->evaluateCard(false, mp); // Must not sync! + it->storeTimes(); + } + else if (it->tLeg>leg) + needupdate = true; + } + } + leg++; + } + + // Update team start times etc. + for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) { + if (!tit->isRemoved()) { + if (!cls.empty() && cls.count(tit->getClassId()) == 0) + continue; + + tit->apply(false, 0, true); + tit->setTmpStore(); + if (doSync) + tit->synchronize(true); + } + } + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved()) { + if (!cls.empty() && cls.count(it->getClassId()) == 0) + continue; + + if (!it->tInTeam) + it->apply(false, 0, true); + it->setTmpStore(); + it->storeTimes(); + it->clearOnChangedRunningTime(); + } + } + //reCalculateLeaderTimes(0); +} + +void oEvent::reEvaluateChanged() +{ + if (sqlChangedClasses || sqlChangedCourses || sqlChangedControls) { + reEvaluateAll(set(), false); + globalModification = true; + return; + } + + if (sqlChangedClubs) + globalModification = true; + + + if (!sqlChangedCards && !sqlChangedRunners && !sqlChangedTeams) + return; // Nothing to do + + map resetClasses; + for(oClassList::iterator it=Classes.begin();it!=Classes.end();++it) { + if (it->wasSQLChanged(-1, oPunch::PunchFinish)) { + it->clearSplitAnalysis(); + it->resetLeaderTime(); + it->reinitialize(); + resetClasses[it->getId()] = it->hasClassGlobalDependance(); + } + } + + stdext::hash_set addedTeams; + + for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) { + if (tit->isRemoved() || !tit->wasSQLChanged()) + continue; + + addedTeams.insert(tit->getId()); + tit->resetTmpStore(); + + int nr = tit->getNumRunners(); + for (int k = 0; k < nr; k++) { + if (tit->Runners[k]) + tit->Runners[k]->resetTmpStore(); + } + tit->apply(false, 0, true); + } + + oRunnerList::iterator it; + vector< vector > legRunners(maxRunnersTeam); + + if (Teams.size() > 0) { + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + + if (resetClasses.count(it->getClassId())) + it->storeTimes(); + + if (!it->wasSQLChanged() && !resetClasses[it->getClassId()]) + continue; + + pTeam t = it->tInTeam; + if (t && !addedTeams.count(t->getId())) { + addedTeams.insert(t->getId()); + t->resetTmpStore(); + int nr = t->getNumRunners(); + for (int k = 0; k < nr; k++) { + if (t->Runners[k]) + t->Runners[k]->resetTmpStore(); + } + t->apply(false, 0, true); + } + } + } + + for (it=Runners.begin(); it != Runners.end(); ++it) { + pRunner r = &*it; + if (r->isRemoved()) + continue; + + if (r->wasSQLChanged() || (r->tInTeam && addedTeams.count(r->tInTeam->getId()))) { + unsigned leg = r->tLeg; + if (leg <0 || leg >= maxRunnersTeam) + leg = 0; + + if (legRunners[leg].empty()) + legRunners[leg].reserve(Runners.size() / (leg+1)); + + legRunners[leg].push_back(r); + if (!r->tInTeam) { + r->resetTmpStore(); + r->apply(false, 0, true); + } + } + else { + if (r->Class && r->Class->wasSQLChanged(-1, oPunch::PunchFinish)) { + it->storeTimes(); + } + } + } + + vector mp; + + // Reevaluate + for (size_t leg = 0; leg < legRunners.size(); leg++) { + const vector &lr = legRunners[leg]; + for (size_t k = 0; k < lr.size(); k++) { + lr[k]->evaluateCard(false, mp); // Must not sync! + } + } + + for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) { + if (addedTeams.count(tit->getId())) { + tit->apply(false, 0, true); + tit->setTmpStore(); + } + } + + for (size_t leg = 0; leg < legRunners.size(); leg++) { + const vector &lr = legRunners[leg]; + for (size_t k = 0; k < lr.size(); k++) { + if (!lr[k]->tInTeam) + lr[k]->apply(false, 0, true); + lr[k]->setTmpStore(); + lr[k]->clearOnChangedRunningTime(); + } + } +} + +void oEvent::reCalculateLeaderTimes(int classId) +{ + if (disableRecalculate) + return; +#ifdef _DEBUG + char bf[128]; + sprintf_s(bf, "Calculate leader times %d\n", classId); + OutputDebugString(bf); +#endif + for (oClassList::iterator it=Classes.begin(); it != Classes.end(); ++it) { + if (!it->isRemoved() && (classId==it->getId() || classId==0)) + it->resetLeaderTime(); + } + bool needupdate = true; + int leg = 0; + while (needupdate) { + needupdate = false; + for (oRunnerList::iterator it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && (classId==0 || classId==it->getClassId())) { + if (it->tLeg == leg) + it->storeTimes(); + else if (it->tLeg>leg) + needupdate = true; + } + } + leg++; + } +} + + +string oEvent::getCurrentTimeS() const +{ + SYSTEMTIME st; + GetLocalTime(&st); + + char bf[64]; + sprintf_s(bf, 64, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); + return bf; +} + +int oEvent::findBestClass(const SICard &card, vector &classes) const +{ + classes.clear(); + int Distance=-1000; + oClassList::const_iterator it; + + for (it=Classes.begin(); it != Classes.end(); ++it) { + vector courses; + it->getCourses(0, courses); + bool insertClass = false; // Make sure a class is only included once + + for (size_t k = 0; kdistance(card); + + if (d>=0) { + if (Distance<0) Distance=1000; + + if (dDistance) { + Distance = d; + classes.clear(); + insertClass = true; + classes.push_back(pClass(&*it)); + } + else if (Distance == d) { + if (!insertClass) { + insertClass = true; + classes.push_back(pClass(&*it)); + } + } + } + } + } + } + return Distance; +} + +void oEvent::convertTimes(SICard &sic) const +{ + if (sic.convertedTime) + return; + + sic.convertedTime = true; + + if (sic.CheckPunch.Code!=-1){ + if (sic.CheckPunch.Time 0) { + + const int START = 1000; + const int FINISH = 1001; + vector > times; + + if (sic.StartPunch.Code!=-1) { + if (sic.StartPunch.Time != -1) + times.push_back(make_pair(sic.StartPunch.Time, START)); + } + + for (unsigned k=0; k getClassId()==ClassId) + if (it->tStartTimetStatus==StatusOK && it->tStartTime!=0) + MinTime=it->tStartTime; + + ++it; + } + + if (MinTime==3600*24) + MinTime=0; + + return MinTime; +} + +bool oEvent::exportONattResults(gdioutput &gdi, const string &file) +{ + ofstream fout(file.c_str()); + + calculateResults(RTClassResult); + + sortRunners(ClassFinishTime); + + oRunnerList::iterator it; + + int Id=0; + + int ClassNr=1; + bool warn=false; + char bf[256]; + + int FirstStart=0; + + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (it->tStatus!=0 && it->tStatus!=StatusDNS){ + if (it->getClassId()!=Id){ + //Next class + Id=it->getClassId(); + FirstStart=getFirstStart(Id); + + if (it->getClass()=="Lång") + ClassNr=1; + else if (it->getClass()=="Mellan") + ClassNr=2; + else if (it->getClass()=="Kort") + ClassNr=3; + else{ + if (!warn) + gdi.alert("Varning: Funktionen anpassad för klassnamn Lång, Mellan och Kort"); + warn=true; + ClassNr=Id; + } + } + + fout << ClassNr << ";"; + + int st=it->tStartTime-FirstStart; + sprintf_s(bf, 64, "%d.%02d;", st/60, st%60); + fout << bf; + + if (it->getStatus()==StatusOK){ + int ft=it->FinishTime-FirstStart; + sprintf_s(bf, 64, "%d.%02d;", ft/60, ft%60); + fout << bf; + } + else fout << ";"; + + fout << it->getName() << ";"; + fout << it->getClub() << endl; + + } + } + + return true; +} + +bool oEvent::hasRank() const +{ + oRunnerList::const_iterator it; + + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (it->getDCI().getInt("Rank")>0) + return true; + } + return false; +} + +void oEvent::setMaximalTime(const string &t) +{ + getDI().setInt("MaxTime", convertAbsoluteTime(t)); +} + +int oEvent::getMaximalTime() const +{ + return getDCI().getInt("MaxTime"); +} + +string oEvent::getMaximalTimeS() const +{ + return formatTime(getMaximalTime()); +} + + +bool oEvent::hasBib(bool runnerBib, bool teamBib) const +{ + if (runnerBib) { + oRunnerList::const_iterator it; + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (!it->getBib().empty()) + return true; + } + } + if (teamBib) { + oTeamList::const_iterator it; + for (it=Teams.begin(); it != Teams.end(); ++it){ + if (!it->getBib().empty()) + return true; + } + } + return false; +} + +bool oEvent::hasTeam() const +{ + return Teams.size() > 0; +} + +void oEvent::addBib(int ClassId, int leg, const string &firstNumber) { + if ( !classHasTeams(ClassId) ) { + sortRunners(ClassStartTimeClub); + oRunnerList::iterator it; + + if (!firstNumber.empty()) { + char pattern[32]; + int num = oClass::extractBibPattern(firstNumber, pattern); + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + if ( (ClassId==0 || it->getClassId()==ClassId) && it->legToRun()==leg) { + char bib[32]; + sprintf_s(bib, pattern, num); + it->setBib(bib, num, true, false); + num++; + it->synchronize(); + } + } + } + else { + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (it->isRemoved()) + continue; + if (ClassId==0 || it->getClassId()==ClassId) { + it->getDI().setString("Bib", "");//Update only bib + it->synchronize(); + } + } + } + } + else { + oTeamList::iterator it; + for (it=Teams.begin(); it != Teams.end(); ++it) + it->apply(false, 0, false); + + if (!firstNumber.empty()) { + // Clear out start number temporarily, to not use it for sorting + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (ClassId==0 || it->getClassId()==ClassId) { + if (it->getClassRef() && it->getClassRef()->getBibMode() != BibFree) { + for (size_t i = 0; i < it->Runners.size(); i++) { + if (it->Runners[i]) { + it->Runners[i]->setStartNo(0, false); + it->Runners[i]->setBib("", 0, false, false); + } + } + } + it->setStartNo(0, false); + } + } + } + + sortTeams(ClassStartTime, 0, true); // Sort on first leg starttime and sortindex + + if (!firstNumber.empty()) { + char pattern[32]; + int num = oClass::extractBibPattern(firstNumber, pattern); + + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (ClassId==0 || it->getClassId()==ClassId) { + char bib[32]; + sprintf_s(bib, pattern, num); + it->setBib(bib, num, true, false); + num++; + it->apply(true, 0, false); + } + } + } + else { + for(it=Teams.begin(); it != Teams.end(); ++it){ + if (ClassId==0 || it->getClassId()==ClassId) { + it->getDI().setString("Bib", ""); //Update only bib + it->apply(true, 0, false); + } + } + } + } +} + +void oEvent::addAutoBib() { + sortRunners(ClassStartTimeClub); + oRunnerList::iterator it; + int clsId = -1; + int bibGap = oe->getBibClassGap(); + int interval = 1; + + char pattern[32] = {0}; + char storedPattern[32]; + strcpy_s(storedPattern, "%d"); + + int number = 0; + + + for (oTeamList::iterator tit=Teams.begin(); tit != Teams.end(); ++tit) { + if (!tit->skip()) + tit->apply(false, 0, false); + } + + // Clear out start number temporarily, to not use it for sorting + for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) { + if (tit->skip()) + continue; + pClass cls = tit->getClassRef(); + if (cls == 0) + continue; + string bibInfo = cls->getDCI().getString("Bib"); + + bool teamAssign = !bibInfo.empty(); + bool freeMode = cls->getBibMode()==BibFree; + if (!teamAssign && freeMode) + continue; // Manul or none + + bool addBib = bibInfo != "-"; + + if (addBib && teamAssign) + tit->setStartNo(0, false); + + if (tit->getClassRef() && tit->getClassRef()->getBibMode() != BibFree) { + for (size_t i = 0; i < tit->Runners.size(); i++) { + if (tit->Runners[i]) { + if (addBib && teamAssign) + tit->Runners[i]->setStartNo(0, false); + if (!freeMode) + tit->Runners[i]->setBib("", 0, false, false); + } + } + } + } + + sortTeams(ClassStartTime, 0, true); // Sort on first leg starttime and sortindex + map > cls2TeamList; + + for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) { + if (tit->skip()) + continue; + int clsId = tit->getClassId(); + cls2TeamList[clsId].push_back(&*tit); + } + + map > cls2RunnerList; + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->skip() || !it->getClassId()) + continue; + int clsId = it->getClassId(); + cls2RunnerList[clsId].push_back(&*it); + } + + Classes.sort(); + for (oClassList::iterator clsIt = Classes.begin(); clsIt != Classes.end(); ++clsIt) { + + const pClass cls = &*clsIt; + clsId = cls->getId(); + + string bibInfo = cls->getDCI().getString("Bib"); + if (bibInfo.empty()) { + // Skip class + continue; + } + else if (bibInfo == "*") { + if (number == 0) + number = 1; + else + number += bibGap; + + if (pattern[0] == 0) { + strcpy_s(pattern, storedPattern); + } + } + else if (bibInfo == "-") { + if (pattern[0]) { + strcpy_s(storedPattern, pattern); + } + pattern[0] = 0; // Clear bibs in class + + } + else { + number = oClass::extractBibPattern(bibInfo, pattern); + } + + if (cls->getNumStages() > 1) { + vector &tl = cls2TeamList[clsId]; + + if (cls->getBibMode() == BibAdd) { + int ns = cls->getNumStages(); + if (ns <= 10) + interval = 10; + else + interval = 100; + + if (bibInfo == "*") { + int add = interval - number % interval; + number += add; + } + } + else { + interval = 1; + } + + if (pattern[0] == 0) { + // Remove bib + for (size_t k = 0; k < tl.size(); k++) { + tl[k]->getDI().setString("Bib", ""); //Update only bib + tl[k]->apply(true, 0, false); + } + } + else { + for (size_t k = 0; k < tl.size(); k++) { + char buff[32]; + sprintf_s(buff, pattern, number); + tl[k]->setBib(buff, number, true, false); + number += interval; + tl[k]->apply(true, 0, false); + } + } + + continue; + } + else { + interval = 1; + + vector &rl = cls2RunnerList[clsId]; + for (size_t k = 0; k < rl.size(); k++) { + if (pattern[0]) { + char buff[32]; + sprintf_s(buff, pattern, number); + rl[k]->setBib(buff, number, true, false); + number += interval; + } + else { + rl[k]->getDI().setString("Bib", ""); //Update only bib + } + rl[k]->synchronize(); + } + } + } +} + +void oEvent::checkOrderIdMultipleCourses(int ClassId) +{ + sortRunners(ClassStartTime); + int order=1; + oRunnerList::iterator it; + + //Find first free order + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (ClassId==0 || it->getClassId()==ClassId){ + it->synchronize();//Ensure we are up-to-date + order=max(order, it->StartNo); + } + } + + //Assign orders + for(it=Runners.begin(); it != Runners.end(); ++it){ + if (ClassId==0 || it->getClassId()==ClassId) + if (it->StartNo==0){ + it->StartNo=++order; + it->updateChanged(); //Mark as changed. + it->synchronize(); //Sync! + } + } +} + +void oEvent::fillStatus(gdioutput &gdi, const string& id) +{ + vector< pair > d; + oe->fillStatus(d); + gdi.addItem(id, d); +} + +const vector< pair > &oEvent::fillStatus(vector< pair > &out) +{ + out.clear(); + out.push_back(make_pair(lang.tl("-"), StatusUnknown)); + out.push_back(make_pair(lang.tl("Godkänd"), StatusOK)); + out.push_back(make_pair(lang.tl("Ej start"), StatusDNS)); + out.push_back(make_pair(lang.tl("Felst."), StatusMP)); + out.push_back(make_pair(lang.tl("Utg."), StatusDNF)); + out.push_back(make_pair(lang.tl("Disk."), StatusDQ)); + out.push_back(make_pair(lang.tl("Maxtid"), StatusMAX)); + out.push_back(make_pair(lang.tl("Deltar ej"), StatusNotCompetiting)); + return out; +} + +int oEvent::getPropertyInt(const char *name, int def) +{ + if (eventProperties.count(name)==1) + return atoi(eventProperties[name].c_str()); + else { + setProperty(name, def); + return def; + } +} + +const string &oEvent::getPropertyString(const char *name, const string &def) +{ + if (eventProperties.count(name)==1) + return eventProperties[name]; + else { + eventProperties[name] = def; + return eventProperties[name]; + } +} + +string oEvent::getPropertyStringDecrypt(const char *name, const string &def) +{ + char bf[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD len = MAX_COMPUTERNAME_LENGTH + 1; + GetComputerName(bf, &len); + string prop = getPropertyString(name, def); + string prop2; + int code = 0; + const int s = 337; + + for (size_t j = 0; j>4) + 33; + prop2.push_back((unsigned char)b1); + prop2.push_back((unsigned char)b2); + } + + setProperty(name, prop2); +} + +void oEvent::setProperty(const char *name, int prop) +{ + eventProperties[name]=itos(prop); +} + +void oEvent::setProperty(const char *name, const string &prop) +{ + eventProperties[name]=prop; +} + +void oEvent::saveProperties(const char *file) { + map::const_iterator it; + xmlparser xml(0); + xml.openOutputT(file, false, "MeOSPreference"); + + for (it = eventProperties.begin(); it != eventProperties.end(); ++it) { + xml.write(it->first.c_str(), it->second); + } + + xml.closeOut(); +} + +void oEvent::loadProperties(const char *file) { + eventProperties.clear(); + initProperties(); + try { + xmlparser xml(0); + xml.read(file); + xmlobject xo = xml.getObject("MeOSPreference"); + if (xo) { + xmlList list; + xo.getObjects(list); + for (size_t k = 0; kgetStartNo() < b.tInTeam->getStartNo(); + else return false; + } + return b.tInTeam!=0; + } + else + return a.getClass()skip() || it->getCardNo() || it->isVacant() || it->needNoCard()) + continue; + + if (it->getStatus() == StatusDNS || it->getStatus() == StatusNotCompetiting) + continue; + + if (it->Club!=lastClub) { + lastClub=it->Club; + gdi.dropLine(0.5); + gdi.addString("", 1, it->getClub()); + } + + string r; + if (it->Class) + r+=it->getClass()+", "; + + if (it->tInTeam) { + char bf[1024]; + sprintf_s(bf, "%d %s, ", it->tInTeam->getStartNo(), + it->tInTeam->getName().c_str()); + r+=bf; + } + + r+=it->getName()+":"; + gdi.fillRight(); + gdi.pushX(); + gdi.addStringUT(0, r); + char id[24]; + sprintf_s(id, "*%d", k++); + + gdi.addInput(max(gdi.getCX(), 450), gdi.getCY()-4, + id, "", 10, cb).setExtra(it->getId()); + + gdi.popX(); + gdi.dropLine(1.6); + gdi.fillDown(); + } + + if (k==0) + gdi.addString("", 0, "Ingen löpare saknar bricka"); +} + +void oEvent::calcUseStartSeconds() +{ + tUseStartSeconds=false; + oRunnerList::iterator it; + for (it=Runners.begin(); it != Runners.end(); ++it) + if ( it->getStartTime()>0 && + (it->getStartTime()+ZeroTime)%60!=0 ) { + tUseStartSeconds=true; + return; + } +} + +const string &oEvent::formatStatus(RunnerStatus status) +{ + const static string stats[8]={"?", "Godkänd", "Ej start", "Felst.", "Utg.", "Disk.", "Maxtid", "Deltar ej"}; + switch(status) { + case StatusOK: + return lang.tl(stats[1]); + case StatusDNS: + return lang.tl(stats[2]); + case StatusMP: + return lang.tl(stats[3]); + case StatusDNF: + return lang.tl(stats[4]); + case StatusDQ: + return lang.tl(stats[5]); + case StatusMAX: + return lang.tl(stats[6]); + case StatusNotCompetiting: + return lang.tl(stats[7]); + default: + return stats[0]; + } +} + +#ifndef MEOSDB + +void oEvent::analyzeClassResultStatus() const +{ + map res; + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved() || !it->Class) + continue; + + int id = it->Class->Id * 31 + it->tLeg; + ClassResultInfo &cri = res[id]; + + if (it->getStatus() == StatusUnknown) { + cri.nUnknown++; + if (it->tStartTime > 0) { + if (!it->isVacant()) { + if (cri.lastStartTime>=0) + cri.lastStartTime = max(cri.lastStartTime, it->tStartTime); + } + } + else + cri.lastStartTime = -1; // Cannot determine + } + else + cri.nFinished++; + + } + + for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + if (!it->legInfo.empty()) { + it->tResultInfo.resize(it->legInfo.size()); + for (size_t k = 0; klegInfo.size(); k++) { + int id = it->Id * 31 + k; + it->tResultInfo[k] = res[id]; + } + } + else { + it->tResultInfo.resize(1); + it->tResultInfo[0] = res[it->Id * 31]; + } + } +} + +void oEvent::generateTestCard(SICard &sic) const +{ + sic.clear(0); + + if (Runners.empty()) + return; + + analyzeClassResultStatus(); + + oRunnerList::const_iterator it; + + int rNo = rand()%Runners.size(); + + it=Runners.begin(); + + while(rNo-->0) + ++it; + + oRunner *r = 0; + int cardNo = 0; + while(r==0 && it!=Runners.end()) { + cardNo = it->CardNo; + if (cardNo == 0 && it->tParentRunner) + cardNo = it->tParentRunner->CardNo; + + if (it->Class && it->tLeg>0) { + StartTypes st = it->Class->getStartType(it->tLeg); + if (st == STHunting) { + if (it->Class->tResultInfo[it->tLeg-1].nUnknown > 0) + cardNo = 0; // Wait with this leg + } + } + + // Make sure teams start in right order + if (it->tInTeam && it->tLeg>0) { + if (it->Class) { + StartTypes st = it->Class->getStartType(it->tLeg); + if (st != STDrawn && st != STTime) { + pRunner prev = it->tInTeam->Runners[it->tLeg - 1]; + if (prev && prev->getStatus() == StatusUnknown) + cardNo = 0; // Wait with this runner + } + } + } + + if (cardNo && !it->Card) { + // For team runners, we require start time to get right order + if (!it->tInTeam || it->tStartTime>0) + r=pRunner(&*it); + } + ++it; + } + --it; + while(r==0 && it!=Runners.begin()) { + cardNo = it->CardNo; + if (cardNo == 0 && it->tParentRunner) + cardNo = it->tParentRunner->CardNo; + + if (it->Class && it->tLeg>0) { + StartTypes st = it->Class->getStartType(it->tLeg); + if (st == STHunting) { + if (it->Class->tResultInfo[it->tLeg-1].nUnknown > 0) + cardNo = 0; // Wait with this leg + } + } + + // Make sure teams start in right order + if (it->tInTeam && it->tLeg>0) { + if (it->Class) { + StartTypes st = it->Class->getStartType(it->tLeg); + if (st != STDrawn && st != STTime) { + pRunner prev = it->tInTeam->Runners[it->tLeg - 1]; + if (prev && prev->getStatus() == StatusUnknown) + cardNo = 0; // Wait with this runner + } + } + } + + if (cardNo && !it->Card) { + // For team runners, we require start time to get right order + if (!it->tInTeam || it->tStartTime>0) { + r=pRunner(&*it); + } + } + --it; + } + + if (r) { + r->synchronize(); + pCourse pc=r->getCourse(false); + + if (!pc) { + pClass cls = r->Class; + if (cls) { + pc = const_cast(this)->generateTestCourse(rand()%15+7); + pc->synchronize(); + cls->setCourse(pc); + cls->synchronize(); + } + } + + if (pc) { + sic.CardNumber = cardNo; + + if (rand()%5 == 3) + sic.CardNumber = 100000; + + int s = sic.StartPunch.Time = r->tStartTime>0 ? r->tStartTime+ZeroTime : ZeroTime+3600+rand()%(3600*3); + int tomiss = rand()%(60*10); + if (tomiss>60*9) + tomiss = rand()%30; + else if (rand()%20 == 3) + tomiss *= rand()%3; + + int f = sic.FinishPunch.Time = s+(30+pc->getLength()/200)*60+ rand()%(60*10) + tomiss; + + if (rand()%40==0 || r->tStartTime>0) + sic.StartPunch.Code=-1; + + if (rand()%50==31) + sic.FinishPunch.Code=-1; + + if (rand()%70==31) + sic.CardNumber++; + + sic.nPunch=0; + double dt=1./double(pc->nControls+1); + + int missed = 0; + + for(int k=0;knControls;k++) { + if (rand()%130!=50) { + sic.Punch[sic.nPunch].Code=pc->getControl(k)->Numbers[0]; + double cc=(k+1)*dt; + + + if (missed < tomiss) { + int left = pc->nControls - k; + if (rand() % left == 1) + missed += ( (tomiss - missed) * (rand()%4 + 1))/6; + else if (left == 1) + missed = tomiss; + } + + sic.Punch[sic.nPunch].Time=int((f-tomiss)*cc+s*(1.-cc)) + missed; + sic.nPunch++; + } + } + } + } +} + +pCourse oEvent::generateTestCourse(int nCtrl) +{ + char bf[64]; + static int sk=0; + sprintf_s(bf, lang.tl("Bana %d").c_str(), ++sk); + pCourse pc=addCourse(bf, 4000+(rand()%1000)*10); + + int i=0; + for (;iaddControl(rand()%(99-32)+32); + + i++; + pc->addControl(50)->setName("Radio 1"); + + for (;i<(2*nCtrl)/3;i++) + pc->addControl(rand()%(99-32)+32); + + i++; + pc->addControl(150)->setName("Radio 2"); + + for (;iaddControl(rand()%(99-32)+32); + pc->addControl(100)->setName("Förvarning"); + + return pc; +} + + +pClass oEvent::generateTestClass(int nlegs, int nrunners, + char *name, const string &start) +{ + pClass cls=addClass(name); + + if (nlegs==1 && nrunners==1) { + int nCtrl=rand()%15+5; + if (rand()%10==1) + nCtrl+=rand()%40; + cls->setCourse(generateTestCourse(nCtrl)); + } + else if (nlegs==1 && nrunners==2) { + setupRelay(*cls, PPatrol, 2, start); + int nCtrl=rand()%15+10; + pCourse pc=generateTestCourse(nCtrl); + cls->addStageCourse(0, pc->getId()); + cls->addStageCourse(1, pc->getId()); + } + else if (nlegs>1 && nrunners==2) { + setupRelay(*cls, PTwinRelay, nlegs, start); + int nCtrl=rand()%8+10; + int cid[64]; + for (int k=0;kgetId(); + + for (int k=0;kaddStageCourse(k, cid[(k+j)%nlegs]); + } + else if (nlegs>1 && nrunners==nlegs) { + setupRelay(*cls, PRelay, nlegs, start); + int nCtrl=rand()%8+10; + int cid[64]; + for (int k=0;kgetId(); + + for (int k=0;kaddStageCourse(k, cid[(k+j)%nlegs]); + } + else if (nlegs>1 && nrunners==1) { + setupRelay(*cls, PHunting, 2, start); + cls->addStageCourse(0, generateTestCourse(rand()%8+10)->getId()); + cls->addStageCourse(1, generateTestCourse(rand()%8+10)->getId()); + } + return cls; +} + + +void oEvent::generateTestCompetition(int nClasses, int nRunners, + bool generateTeams) { + if (nClasses > 0) { + oe->newCompetition("!TESTTÄVLING"); + oe->setZeroTime("05:00:00"); + oe->getMeOSFeatures().useAll(*oe); + } + bool useSOFTMethod = true; + vector gname; + //gname.reserve(RunnerDatabase.size()); + vector fname; + //fname.reserve(RunnerDatabase.size()); + + runnerDB->getAllNames(gname, fname); + + if (fname.empty()) + fname.push_back("Foo"); + + if (gname.empty()) + gname.push_back("Bar"); + +/* oRunnerList::iterator it; + for(it=RunnerDatabase.begin(); it!=RunnerDatabase.end(); ++it){ + if (!it->getGivenName().empty()) + gname.push_back(it->getGivenName()); + + if (!it->getFamilyName().empty()) + fname.push_back(it->getFamilyName()); + } +*/ + int nClubs=30; + char bf[128]; + int startno=1; + const vector &oc = runnerDB->getClubDB(); + for(int k=0;k2 && nRInClass>3) + nRInClass+=int(nRInClass*0.7)-rand()%int(nRInClass*1.5); + + if (cls->getNumDistinctRunners()==1) { + for (int i=0;igetId(), 0, 0, true); + + r->setStartNo(startno++, false); + r->setCardNo(500001+Runners.size()*97+rand()%97, false); + r->apply(false, 0, false); + } + nRunners-=nRInClass; + if (k%5!=5) { + vector spec; + spec.push_back(ClassDrawSpecification(cls->getId(), 0, getRelativeTime(start), 10, 3)); + drawList(spec, useSOFTMethod, 1, drawAll); + } + else + cls->Name += " Öppen"; + } + else { + int dr=cls->getNumDistinctRunners(); + for (int i=0;igetId()); + t->setStartNo(startno++, false); + + for (int j=0;jsetCardNo(500001+Runners.size()*97+rand()%97, false); + t->setRunner(j, r, false); + } + } + nRunners-=nRInClass; + + if ( cls->getStartType(0)==STDrawn ) { + vector spec; + spec.push_back(ClassDrawSpecification(cls->getId(), 0, getRelativeTime(start), 20, 3)); + drawList(spec, useSOFTMethod, 1, drawAll); + } + } + } +} + +#endif + +void oEvent::getFreeImporter(oFreeImport &fi) +{ + if (!fi.isLoaded()) + fi.load(); + + fi.init(Runners, Clubs, Classes); +} + + +void oEvent::fillFees(gdioutput &gdi, const string &name, bool withAuto) const { + gdi.clearList(name); + + set fees; + + int f; + for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + f = it->getDCI().getInt("ClassFee"); + if (f > 0) + fees.insert(f); + + f = it->getDCI().getInt("ClassFeeRed"); + if (f > 0) + fees.insert(f); + + if (withAuto) { + f = it->getDCI().getInt("HighClassFee"); + if (f > 0) + fees.insert(f); + + f = it->getDCI().getInt("HighClassFeeRed"); + if (f > 0) + fees.insert(f); + } + } + + f = getDCI().getInt("EliteFee"); + if (f > 0) + fees.insert(f); + + f = getDCI().getInt("EntryFee"); + if (f > 0) + fees.insert(f); + + f = getDCI().getInt("YouthFee"); + if (f > 0) + fees.insert(f); + + vector< pair > ff; + if (withAuto) + ff.push_back(make_pair(lang.tl("Från klassen"), -1)); + for (set::iterator it = fees.begin(); it != fees.end(); ++it) + ff.push_back(make_pair(formatCurrency(*it), *it)); + + gdi.addItem(name, ff); +} + +void oEvent::fillLegNumbers(const set &cls, + bool isTeamList, + bool includeSubLegs, + vector< pair > &out) { + oClassList::iterator it; + synchronizeList(oLClassId); + + out.clear(); + set< pair > legs; + + for (it=Classes.begin(); it != Classes.end(); ++it) { + if (!it->Removed && (cls.empty() || cls.count(it->getId()))) { + if (it->getNumStages() == 0) + continue; + + for (size_t j = 0; j < it->getNumStages(); j++) { + int number, order; + if (it->splitLegNumberParallel(j, number, order)) { + if (order == 0) + legs.insert( make_pair(number, 0) ); + else { + if (it->isOptional(j)) + continue; + + if (order == 1) + legs.insert( make_pair(number, 1000)); + legs.insert(make_pair(number, 1000+order)); + } + } + else { + legs.insert( make_pair(number, 0) ); + } + } + } + } + + out.reserve(legs.size() + 1); + for (set< pair >::const_iterator it = legs.begin(); it != legs.end(); ++it) { + if (it->second == 0) { + out.push_back( make_pair(lang.tl("Sträcka X#" + itos(it->first + 1)), it->first)); + } + } + if (includeSubLegs) { + for (set< pair >::const_iterator it = legs.begin(); it != legs.end(); ++it) { + if (it->second >= 1000) { + int leg = it->first; + int sub = it->second - 1000; + char bf[64]; + char symb = 'a' + sub; + sprintf_s(bf, "Sträcka X#%d%c", leg+1, symb); + out.push_back( make_pair(lang.tl(bf), (leg + 1) * 10000 + sub)); + } + } + } + + if (isTeamList) + out.push_back(make_pair(lang.tl("Sista sträckan"), 1000)); + else + out.push_back(make_pair(lang.tl("Alla sträckor"), 1000)); +} + +void oEvent::generateTableData(const string &tname, Table &table, TableUpdateInfo &tui) +{ + if (tname == "runners") { + if (tui.doRefresh && !tui.doAdd) + return; + pRunner r = tui.doAdd ? addRunner(getAutoRunnerName(),0,0,0,0,false) : pRunner(tui.object); + generateRunnerTableData(table, r); + return; + } + else if (tname == "classes") { + if (tui.doRefresh && !tui.doAdd) + return; + pClass c = tui.doAdd ? addClass(getAutoClassName()) : pClass(tui.object); + generateClassTableData(table, c); + return; + } + else if (tname == "clubs") { + if (tui.doRefresh && !tui.doAdd) + return; + pClub c = tui.doAdd ? addClub("Club", 0) : pClub(tui.object); + generateClubTableData(table, c); + return; + } + else if (tname == "teams") { + if (tui.doRefresh && !tui.doAdd) + return; + pTeam t = tui.doAdd ? addTeam(getAutoTeamName()) : pTeam(tui.object); + generateTeamTableData(table, t); + return; + } + else if (tname == "cards") { + if (tui.doRefresh && !tui.doAdd) + return; + generateCardTableData(table, pCard(tui.object)); + return; + } + else if (tname == "controls") { + if (tui.doRefresh && !tui.doAdd) + return; + generateControlTableData(table, pControl(tui.object)); + return; + } + else if (tname == "punches") { + if (tui.doRefresh && !tui.doAdd) + return; + + pFreePunch c = tui.doAdd ? addFreePunch(0,0,0, false) : pFreePunch(tui.object); + generatePunchTableData(table, c); + return; + } + else if (tname == "runnerdb") { + if (tui.doAdd || !tui.doRefresh) { + oDBRunnerEntry *entry = tui.doAdd ? getRunnerDatabase().addRunner() : (oDBRunnerEntry *)(tui.object); + getRunnerDatabase().generateRunnerTableData(table, entry); + } + + if (tui.doRefresh) + getRunnerDatabase().refreshRunnerTableData(table); + + return; + } + else if (tname == "clubdb") { + if (tui.doAdd || !tui.doRefresh) { + pClub c = tui.doAdd ? getRunnerDatabase().addClub() : pClub(tui.object); + getRunnerDatabase().generateClubTableData(table, c); + } + + if (tui.doRefresh) { + getRunnerDatabase().refreshClubTableData(table); + } + return; + } + throw std::exception("Wrong table name"); +} + +void oEvent::applyEventFees(bool updateClassFromEvent, + bool updateFees, bool updateCardFees, + const set &classFilter) { + synchronizeList(oLClassId, true, false); + synchronizeList(oLRunnerId, false, true); + bool allClass = classFilter.empty(); + + if (updateClassFromEvent) { + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + if (allClass || classFilter.count(it->getId())) { + it->addClassDefaultFee(true); + it->synchronize(true); + } + } + } + + if (updateFees) { + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + + if (allClass || classFilter.count(it->getClassId())) { + it->addClassDefaultFee(true); + it->synchronize(true); + } + } + } + + if (updateCardFees) { + int cf = getDCI().getInt("CardFee"); + + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + + if (it->getDI().getInt("CardFee") != 0) { + it->getDI().setInt("CardFee", cf); + it->synchronize(true); + } + } + } +} + +#ifndef MEOSDB +void hideTabs(); +void createTabs(bool force, bool onlyMain, bool skipTeam, bool skipSpeaker, + bool skipEconomy, bool skipLists, bool skipRunners, bool skipControls); + +void oEvent::updateTabs(bool force, bool hide) const +{ + bool hasTeam = !Teams.empty(); + + for (oClassList::const_iterator it = Classes.begin(); + !hasTeam && it!=Classes.end(); ++it) { + if (it->getNumStages()>1) + hasTeam = true; + } + + bool hasRunner = !Runners.empty() || !Classes.empty(); + bool hasLists = !empty(); + + if (hide || isReadOnly()) + hideTabs(); + else + createTabs(force, empty(), !hasTeam, !getMeOSFeatures().hasFeature(MeOSFeatures::Speaker), + !(getMeOSFeatures().hasFeature(MeOSFeatures::Economy) + || getMeOSFeatures().hasFeature(MeOSFeatures::EditClub)), + !hasLists, !hasRunner, Controls.empty()); +} + +#else +void oEvent::updateTabs(bool force) const +{ +} +#endif + +bool oEvent::useRunnerDb() const +{ + return getMeOSFeatures().hasFeature(MeOSFeatures::RunnerDb); + //return getDCI().getInt("SkipRunnerDb")==0; +} +/* +void oEvent::useRunnerDb(bool use) { + getDI().setInt("SkipRunnerDb", use ? 0 : 1); +}*/ + +bool oEvent::hasMultiRunner() const { + for (oClassList::const_iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (it->hasMultiCourse() && it->getNumDistinctRunners() != it->getNumStages()) + return true; + } + + return false; +} + +/** Return false if card is not used */ +bool oEvent::checkCardUsed(gdioutput &gdi, oRunner &runnerToAssignCard, int cardNo) { + synchronizeList(oLRunnerId); + //pRunner pold=oe->getRunnerByCardNo(cardNo, 0, true, true); + char bf[1024]; + pRunner pold = 0; + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + if (!runnerToAssignCard.canShareCard(&*it, cardNo)) { + pold = &*it; + break; + } + } + + if (pold) { + sprintf_s(bf, ("#" + lang.tl("Bricka %d används redan av %s och kan inte tilldelas.")).c_str(), + cardNo, pold->getCompleteIdentification().c_str()); + gdi.alert(bf); + return true; + } + return false; +} + +void oEvent::removeVacanies(int classId) { + oRunnerList::iterator it; + vector toRemove; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->skip() || !it->isVacant()) + continue; + + if (classId!=0 && it->getClassId()!=classId) + continue; + + if (!isRunnerUsed(it->Id)) + toRemove.push_back(it->Id); + } + + removeRunner(toRemove); +} + +void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) { + bool hasResult = false; + bool warnNoName = false; + bool warnNoClass = false; + bool warnNoTeam = false; + bool warnNoPatrol = false; + bool warnIndividualTeam = false; + + for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { + if (it->isRemoved()) + continue; + if (onlyThisClass > 0 && it->getClassId() != onlyThisClass) + continue; + if (it->sName.empty()) { + if (!warnNoName) { + warnNoName = true; + gdi.alert("Varning: deltagare med blankt namn påträffad. MeOS " + "kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.'"); + } + it->setName("N.N.", false); + it->synchronize(); + } + + if (!it->Class) { + if (!warnNoClass) { + gdi.alert("Deltagaren 'X' saknar klass.#" + it->getName()); + warnNoClass = true; + } + continue; + } + + if (!it->tInTeam) { + ClassType type = it->Class->getClassType(); + if (type == oClassIndividRelay) { + it->setClassId(it->Class->getId(), true); + it->synchronize(); + } + else if (type == oClassRelay) { + if (!warnNoTeam) { + gdi.alert("Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- " + "och resultatlistor kan därmed bli felaktiga.#" + it->getName() + + "#" + it->getClass()); + warnNoTeam = true; + } + } + else if (type == oClassPatrol) { + if (!warnNoPatrol) { + gdi.alert("Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- " + "och resultatlistor kan därmed bli felaktiga.#" + it->getName() + + + "#" + it->getClass()); + warnNoPatrol = true; + } + } + } + + if (it->getFinishTime()>0) + hasResult = true; + } + + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved()) + continue; + + if (onlyThisClass > 0 && it->getClassId() != onlyThisClass) + continue; + + if (it->sName.empty()) { + if (!warnNoName) { + warnNoName = true; + gdi.alert("Varning: lag utan namn påträffat. " + "MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.'"); + } + it->setName("N.N.", false); + it->synchronize(); + } + + if (!it->Class) { + if (!warnNoClass) { + gdi.alert("Laget 'X' saknar klass.#" + it->getName()); + warnNoClass = true; + } + continue; + } + + ClassType type = it->Class->getClassType(); + if (type == oClassIndividual) { + if (!warnIndividualTeam) { + gdi.alert("Laget 'X' deltar i individuella klassen 'Y'. Klassens start- och resultatlistor " + "kan därmed bli felaktiga.#" + it->getName() + "#" + it->getClass()); + warnIndividualTeam = true; + } + } + } + + + if (expectResult && !hasResult) + gdi.alert("Tävlingen innehåller inga resultat."); + + + bool warnBadStart = false; + + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + if (it->getClassStatus() != oClass::Normal) + continue; + + if (onlyThisClass > 0 && it->getId() != onlyThisClass) + continue; + + if (it->hasMultiCourse()) { + for (unsigned k=0;kgetNumStages(); k++) { + StartTypes st = it->getStartType(k); + LegTypes lt = it->getLegType(k); + if (k==0 && (st == STChange || st == STHunting) && !warnBadStart) { + warnBadStart = true; + gdi.alert("Klassen 'X' har jaktstart/växling på första sträckan.#" + it->getName()); + } + if (st == STTime && it->getStartData(k)<=0 && !warnBadStart && + (lt == LTNormal || lt == LTSum)) { + warnBadStart = true; + gdi.alert("Ogiltig starttid i 'X' på sträcka Y.#" + it->getName() + "#" + itos(k+1)); + } + } + } + } +} + +HWND oEvent::hWnd() const +{ + return gdibase.getHWND(); +} + +oTimeLine::~oTimeLine() { + +} + +void oEvent::remove() { + if (isClient()) + dropDatabase(); + else + deleteCompetition(); + + clearListedCmp(); + newCompetition(""); +} + +bool oEvent::canRemove() const { + return true; +} + +string oEvent::formatCurrency(int c, bool includeSymbol) const { + if (tCurrencyFactor == 1) + if (!includeSymbol) + return itos(c); + else if (tCurrencyPreSymbol) + return tCurrencySymbol + itos(c); + else + return itos(c) + tCurrencySymbol; + else { + char bf[32]; + if (includeSymbol) { + sprintf_s(bf, 32, "%d%s%02d", c/tCurrencyFactor, + tCurrencySeparator.c_str(), c%tCurrencyFactor); + + if (tCurrencyPreSymbol) + return tCurrencySymbol + bf; + else + return bf + tCurrencySymbol; + } + else { + sprintf_s(bf, 32, "%d.%02d", c/tCurrencyFactor, c%tCurrencyFactor); + return bf; + } + } +} + +int oEvent::interpretCurrency(const string &c) const { + if (tCurrencyFactor == 1 && tCurrencyPreSymbol == false) + return atoi(c.c_str()); + + size_t s = 0; + while (s < c.length() && (c[s]<'0' || c[s]>'9')) + s++; + + string cc = c.substr(s); + + for (size_t k = 0; k 0) { + if (tCurrencyPreSymbol) { + char end = *tCurrencySymbol.rbegin(); + if ((end>='a' && end <='z') || end>='A' && end <='Z') + tCurrencySymbol += " "; + } + else { + char end = *tCurrencySymbol.begin(); + if ((end>='a' && end <='z') || end>='A' && end <='Z') + tCurrencySymbol = " " + tCurrencySymbol; + } + } + } + else { + tCurrencyFactor = factor; + tCurrencySymbol = symbol; + tCurrencySeparator = separator; + tCurrencyPreSymbol = preSymbol; + getDI().setString("CurrencySymbol", symbol); + getDI().setInt("CurrencyFactor", factor); + getDI().setString("CurrencySeparator", separator); + getDI().setInt("CurrencyPreSymbol", preSymbol ? 1 : 0); + } +} +string oEvent::cloneCompetition(bool cloneRunners, bool cloneTimes, + bool cloneCourses, bool cloneResult, bool addToDate) { + + if (cloneResult) { + cloneTimes = true; + cloneCourses = true; + } + if (cloneTimes) + cloneRunners = true; + + oEvent ce(gdibase); + ce.newCompetition(Name); + ce.ZeroTime = ZeroTime; + ce.Date = Date; + + if (addToDate) { + SYSTEMTIME st; + convertDateYMS(Date, st, false); + __int64 absD = SystemTimeToInt64Second(st); + absD += 3600*24; + ce.Date = convertSystemDate(Int64SecondToSystemTime(absD)); + } + int len = Name.length(); + if (len > 2 && isdigit(Name[len-1]) && !isdigit(Name[len-2])) { + ++ce.Name[len-1]; // E1 -> E2 + } + else + ce.Name += " E2"; + + memcpy(ce.oData, oData, sizeof(oData)); + + for (oClubList::iterator it = Clubs.begin(); it != Clubs.end(); ++it) { + if (it->isRemoved()) + continue; + pClub pc = ce.addClub(it->name, it->Id); + memcpy(pc->oData, it->oData, sizeof(pc->oData)); + } + + if (cloneCourses) { + for (oControlList::iterator it = Controls.begin(); it != Controls.end(); ++it) { + if (it->isRemoved()) + continue; + pControl pc = ce.addControl(it->Id, 100, it->Name); + pc->setNumbers(it->codeNumbers()); + pc->Status = it->Status; + memcpy(pc->oData, it->oData, sizeof(pc->oData)); + } + + for (oCourseList::iterator it = Courses.begin(); it != Courses.end(); ++it) { + if (it->isRemoved()) + continue; + pCourse pc = ce.addCourse(it->Name, it->Length, it->Id); + pc->importControls(it->getControls(), false); + pc->legLengths = it->legLengths; + memcpy(pc->oData, it->oData, sizeof(pc->oData)); + } + } + + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (it->isRemoved()) + continue; + pClass pc = ce.addClass(it->Name, 0, it->Id); + memcpy(pc->oData, it->oData, sizeof(pc->oData)); + pc->setNumStages(it->getNumStages()); + pc->legInfo = it->legInfo; + + if (cloneCourses) { + pc->Course = ce.getCourse(it->getCourseId()); + pc->MultiCourse = it->MultiCourse; // Points to wrong competition, but valid for now... + } + } + + if (cloneRunners) { + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + + oRunner r(&ce, it->Id); + r.sName = it->sName; + oRunner::getRealName(r.sName, r.tRealName); + r.StartNo = it->StartNo; + r.CardNo = it->CardNo; + r.Club = ce.getClub(it->getClubId()); + r.Class = ce.getClass(it->getClassId()); + + if (cloneCourses) + r.Course = ce.getCourse(it->getCourseId()); + + pRunner pr = ce.addRunner(r, false); + + pr->decodeMultiR(it->codeMultiR()); + memcpy(pr->oData, it->oData, sizeof(pr->oData)); + + if (cloneTimes) { + pr->startTime = it->startTime; + } + + if (cloneResult) { + if (it->Card) { + pr->Card = ce.addCard(*it->Card); + pr->Card->tOwner = pr; + } + pr->FinishTime = it->FinishTime; + pr->status = it->status; + } + } + + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (it->skip()) + continue; + + oTeam t(&ce, it->Id); + + t.sName = it->sName; + t.StartNo = it->StartNo; + t.Club = ce.getClub(it->getClubId()); + t.Class = ce.getClass(it->getClassId()); + + if (cloneTimes) + t.startTime = it->startTime; + + pTeam pt = ce.addTeam(t, false); + memcpy(pt->oData, it->oData, sizeof(pt->oData)); + + pt->Runners.resize(it->Runners.size()); + for (size_t k = 0; kRunners.size(); k++) { + int id = it->Runners[k] ? it->Runners[k]->Id : 0; + if (id) + pt->Runners[k] = ce.getRunner(id, 0); + } + + t.apply(false, 0, false); + } + + for (oRunnerList::iterator it = ce.Runners.begin(); it != ce.Runners.end(); ++it) { + it->createMultiRunner(false, false); + } + } + + vector changedClass, changedClassNoResult, assignedVacant, newEntries, notTransfered, noAssign; + set dummy; + transferResult(ce, dummy, TransferAnyway, false, changedClass, changedClassNoResult, assignedVacant, newEntries, notTransfered, noAssign); + + vector newEntriesT, notTransferedT, noAssignT; + transferResult(ce, TransferAnyway, newEntriesT, notTransferedT, noAssignT); + + int eventNumberCurrent = getStageNumber(); + if (eventNumberCurrent <= 0) { + eventNumberCurrent = 1; + setStageNumber(eventNumberCurrent); + } + + ce.getDI().setString("PreEvent", CurrentNameId); + ce.setStageNumber(eventNumberCurrent + 1); + getDI().setString("PostEvent", ce.CurrentNameId); + + int nf = getMeOSFeatures().getNumFeatures(); + for (int k = 0; k < nf; k++) { + MeOSFeatures::Feature f = getMeOSFeatures().getFeature(k); + if (getMeOSFeatures().hasFeature(f)) + ce.getMeOSFeatures().useFeature(f, true, ce); + } + + ce.save(); + + return ce.CurrentFile; +} + +bool checkTargetClass(pRunner target, pRunner source, + const oClassList &Classes, + const vector &targetVacant, + vector &changedClass, + oEvent::ChangedClassMethod changeClassMethod) { + if (changeClassMethod == oEvent::TransferAnyway) + return true; + + if (!compareClassName(target->getClass(), source->getClass())) { + // Store all vacant positions in the right class + int targetClass = -1; + + if (target->getStatus() == StatusOK) { + // There is already a result. Do not change class! + return false; + } + + if (changeClassMethod == oEvent::TransferNoResult) + return false; // Do not allow change class, do not transfer result + + for (oClassList::const_iterator cit = Classes.begin(); cit != Classes.end(); ++cit) { + if (cit->isRemoved()) + continue; + if (compareClassName(cit->getName(), source->getClass())) { + targetClass = cit->getId(); + + if (targetClass == source->getClassId() || cit->getName() == source->getClass()) + break; // Assume exact match + } + } + + if (targetClass != -1) { + set vacantIx; + for (size_t j = 0; j < targetVacant.size(); j++) { + if (!targetVacant[j]) + continue; + if (targetVacant[j]->getClassId() == targetClass) + vacantIx.insert(j); + } + int posToUse = -1; + if (vacantIx.size() == 1) + posToUse = *vacantIx.begin(); + else if (vacantIx.size() > 1) { + string srcBib = source->getBib(); + if (srcBib.length() > 0) { + for (set::iterator tit = vacantIx.begin(); tit != vacantIx.end(); ++tit) { + if (targetVacant[*tit]->getBib() == srcBib) { + posToUse = *tit; + break; + } + } + } + + if (posToUse == -1) + posToUse = *vacantIx.begin(); + } + + if (posToUse != -1) { + // Change class or change class vacant + changedClass.push_back(target); + + int oldStart = target->getStartTime(); + string oldBib = target->getBib(); + int oldSN = target->getStartNo(); + int oldClass = target->getClassId(); + pRunner tgt = targetVacant[posToUse]; + target->cloneStartTime(tgt); + target->setBib(tgt->getBib(), 0, false, false); + target->setStartNo(tgt->getStartNo(), false); + target->setClassId(tgt->getClassId(), false); + + tgt->setStartTime(oldStart, true, false); + tgt->setBib(oldBib, 0, false, false); + tgt->setStartNo(oldSN, false); + tgt->setClassId(oldClass, false); + return true; // Changed to correct class + } + else if (changeClassMethod == oEvent::ChangeClass) { + // Simpliy change class + target->setClassId(targetClass, false); + return true; + } + } + return false; // Wrong class, ChangeClass (but failed) + } + + return true; // Same class, OK +} + +void oEvent::transferResult(oEvent &ce, + const set &allowNewEntries, + ChangedClassMethod changeClassMethod, + bool transferAllNoCompete, + vector &changedClass, + vector &changedClassNoResult, + vector &assignedVacant, + vector &newEntries, + vector ¬Transfered, + vector &noAssignmentTarget) { + + inthashmap processed(ce.Runners.size()); + inthashmap used(Runners.size()); + + changedClass.clear(); + changedClassNoResult.clear(); + assignedVacant.clear(); + newEntries.clear(); + notTransfered.clear(); + noAssignmentTarget.clear(); + + vector targetRunners; + vector targetVacant; + + targetRunners.reserve(ce.Runners.size()); + for (oRunnerList::iterator it = ce.Runners.begin(); it != ce.Runners.end(); ++it) { + if (!it->skip()) { + if (!it->isVacant()) + targetRunners.push_back(&*it); + else + targetVacant.push_back(&*it); + } + } + + calculateResults(RTTotalResult); + // Lookup by id + for (size_t k = 0; k < targetRunners.size(); k++) { + pRunner it = targetRunners[k]; + pRunner r = getRunner(it->Id, 0); + if (!r) + continue; + + __int64 id1 = r->getExtIdentifier(); + __int64 id2 = it->getExtIdentifier(); + + if (id1>0 && id2>0 && id1 != id2) + continue; + + string cnA = canonizeName(it->sName.c_str()); + string cnB = canonizeName(r->sName.c_str()); + string ccnA = canonizeName(it->getClub().c_str()); + string ccnB = canonizeName(r->getClub().c_str()); + + if ((id1>0 && id1==id2) || + (r->CardNo>0 && r->CardNo == it->CardNo) || + (it->sName == r->sName) || (cnA == cnB && ccnA == ccnB)) { + processed.insert(it->Id, 1); + used.insert(r->Id, 1); + if (checkTargetClass(it, r, ce.Classes, targetVacant, changedClass, changeClassMethod)) + it->setInputData(*r); + else { + it->resetInputData(); + changedClassNoResult.push_back(it); + } + } + } + + if (processed.size() < int(targetRunners.size())) { + // Lookup by card + int v; + setupCardHash(false); + for (size_t k = 0; k < targetRunners.size(); k++) { + pRunner it = targetRunners[k]; + if (processed.lookup(it->Id, v)) + continue; + if (it->CardNo > 0) { + pRunner r = getRunnerByCardNo(it->CardNo, 0); + + if (!r || used.lookup(r->Id, v)) + continue; + + __int64 id1 = r->getExtIdentifier(); + __int64 id2 = it->getExtIdentifier(); + + if (id1>0 && id2>0 && id1 != id2) + continue; + + if ((id1>0 && id1==id2) || (it->sName == r->sName && it->getClub() == r->getClub())) { + processed.insert(it->Id, 1); + used.insert(r->Id, 1); + if (checkTargetClass(it, r, ce.Classes, targetVacant, changedClass, changeClassMethod)) + it->setInputData(*r); + else { + it->resetInputData(); + changedClassNoResult.push_back(it); + } + } + } + } + setupCardHash(true); // Clear cache + } + + int v = -1; + + // Store remaining runners + vector remainingRunners; + for (oRunnerList::iterator it2 = Runners.begin(); it2 != Runners.end(); ++it2) { + if (it2->skip() || used.lookup(it2->Id, v)) + continue; + if (it2->isVacant()) + continue; // Ignore vacancies on source side + + remainingRunners.push_back(&*it2); + } + + if (processed.size() < int(targetRunners.size()) && !remainingRunners.empty()) { + // Lookup by name / ext id + vector cnd; + for (size_t k = 0; k < targetRunners.size(); k++) { + pRunner it = targetRunners[k]; + if (processed.lookup(it->Id, v)) + continue; + + __int64 id1 = it->getExtIdentifier(); + + cnd.clear(); + for (size_t j = 0; j < remainingRunners.size(); j++) { + pRunner src = remainingRunners[j]; + if (!src) + continue; + + if (id1 > 0) { + __int64 id2 = src->getExtIdentifier(); + if (id2 == id1) { + cnd.clear(); + cnd.push_back(j); + break; //This is the one, if they have the same Id there will be a unique match below + } + } + if (it->sName == src->sName && it->getClub() == src->getClub()) + cnd.push_back(j); + } + + if (cnd.size() == 1) { + pRunner &src = remainingRunners[cnd[0]]; + processed.insert(it->Id, 1); + used.insert(src->Id, 1); + if (checkTargetClass(it, src, ce.Classes, targetVacant, changedClass, changeClassMethod)) { + it->setInputData(*src); + } + else { + it->resetInputData(); + changedClassNoResult.push_back(it); + } + src = 0; + } + else if (cnd.size() > 0) { // More than one candidate + int winnerIx = -1; + int point = -1; + for (size_t j = 0; j < cnd.size(); j++) { + pRunner src = remainingRunners[cnd[j]]; + int p = 0; + if (src->getClass() == it->getClass()) + p += 1; + if (src->getBirthYear() == it->getBirthYear()) + p += 2; + if (p > point) { + winnerIx = cnd[j]; + point = p; + } + } + + if (winnerIx != -1) { + processed.insert(it->Id, 1); + pRunner winner = remainingRunners[winnerIx]; + remainingRunners[winnerIx] = 0; + + used.insert(winner->Id, 1); + if (checkTargetClass(it, winner, ce.Classes, targetVacant, changedClass, changeClassMethod)) { + it->setInputData(*winner); + } + else { + it->resetInputData(); + changedClassNoResult.push_back(it); + } + } + } + } + } + + // Transfer vacancies + for (size_t k = 0; k < remainingRunners.size(); k++) { + pRunner src = remainingRunners[k]; + if (!src || used.lookup(src->Id, v)) + continue; + + bool forceSkip = src->hasFlag(oAbstractRunner::FlagTransferSpecified) && + !src->hasFlag(oAbstractRunner::FlagTransferNew); + + if (forceSkip) { + notTransfered.push_back(src); + continue; + } + + pRunner targetVacant = ce.getRunner(src->getId(), 0); + if (targetVacant && targetVacant->isVacant() && compareClassName(targetVacant->getClass(), src->getClass()) ) { + targetVacant->setName(src->getName(), false); + targetVacant->setClub(src->getClub()); + targetVacant->setCardNo(src->getCardNo(), false); + targetVacant->cloneData(src); + assignedVacant.push_back(targetVacant); + } + else { + pClass dstClass = ce.getClass(src->getClassId()); + if (dstClass && compareClassName(dstClass->getName(), src->getClass())) { + if ( (!src->hasFlag(oAbstractRunner::FlagTransferSpecified) && allowNewEntries.count(src->getClassId())) + || src->hasFlag(oAbstractRunner::FlagTransferNew)) { + if (src->getClubId() > 0) + ce.getClubCreate(src->getClubId(), src->getClub()); + pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(), + src->getCardNo(), src->getBirthYear(), true); + dst->cloneData(src); + dst->setInputData(*src); + newEntries.push_back(dst); + } + else if (transferAllNoCompete) { + if (src->getClubId() > 0) + ce.getClubCreate(src->getClubId(), src->getClub()); + pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(), + 0, src->getBirthYear(), true); + dst->cloneData(src); + dst->setInputData(*src); + dst->setStatus(StatusNotCompetiting, true, false); + notTransfered.push_back(dst); + } + else + notTransfered.push_back(src); + } + } + } + + // Runners on target side not assigned a result + for (size_t k = 0; k < targetRunners.size(); k++) { + if (targetRunners[k] && !processed.count(targetRunners[k]->Id)) { + noAssignmentTarget.push_back(targetRunners[k]); + if (targetRunners[k]->inputStatus == StatusUnknown || + (targetRunners[k]->inputStatus == StatusOK && targetRunners[k]->inputTime == 0)) { + targetRunners[k]->inputStatus = StatusNotCompetiting; + } + } + } +} + +void oEvent::transferResult(oEvent &ce, + ChangedClassMethod changeClassMethod, + vector &newEntries, + vector ¬Transfered, + vector &noAssignmentTarget) { + + inthashmap processed(ce.Teams.size()); + inthashmap used(Teams.size()); + + newEntries.clear(); + notTransfered.clear(); + noAssignmentTarget.clear(); + + vector targetTeams; + + targetTeams.reserve(ce.Teams.size()); + for (oTeamList::iterator it = ce.Teams.begin(); it != ce.Teams.end(); ++it) { + if (!it->skip()) { + targetTeams.push_back(&*it); + } + } + + calculateTeamResults(true); + // Lookup by id + for (size_t k = 0; k < targetTeams.size(); k++) { + pTeam it = targetTeams[k]; + pTeam t = getTeam(it->Id); + if (!t) + continue; + + __int64 id1 = t->getExtIdentifier(); + __int64 id2 = it->getExtIdentifier(); + + if (id1>0 && id2>0 && id1 != id2) + continue; + + if ((id1>0 && id1==id2) || (it->sName == t->sName && it->getClub() == t->getClub())) { + processed.insert(it->Id, 1); + used.insert(t->Id, 1); + it->setInputData(*t); + //checkTargetClass(it, r, ce.Classes, targetVacant, changedClass); + } + } + + int v = -1; + + // Store remaining runners + vector remainingTeams; + for (oTeamList::iterator it2 = Teams.begin(); it2 != Teams.end(); ++it2) { + if (it2->skip() || used.lookup(it2->Id, v)) + continue; + if (it2->isVacant()) + continue; // Ignore vacancies on source side + + remainingTeams.push_back(&*it2); + } + + if (processed.size() < int(targetTeams.size()) && !remainingTeams.empty()) { + // Lookup by name / ext id + vector cnd; + for (size_t k = 0; k < targetTeams.size(); k++) { + pTeam it = targetTeams[k]; + if (processed.lookup(it->Id, v)) + continue; + + __int64 id1 = it->getExtIdentifier(); + + cnd.clear(); + for (size_t j = 0; j < remainingTeams.size(); j++) { + pTeam src = remainingTeams[j]; + if (!src) + continue; + + if (id1 > 0) { + __int64 id2 = src->getExtIdentifier(); + if (id2 == id1) { + cnd.clear(); + cnd.push_back(j); + break; //This is the one, if they have the same Id there will be a unique match below + } + } + + if (it->sName == src->sName && it->getClub() == src->getClub()) + cnd.push_back(j); + } + + if (cnd.size() == 1) { + pTeam &src = remainingTeams[cnd[0]]; + processed.insert(it->Id, 1); + used.insert(src->Id, 1); + it->setInputData(*src); + //checkTargetClass(it, src, ce.Classes, targetVacant, changedClass); + src = 0; + } + else if (cnd.size() > 0) { // More than one candidate + int winnerIx = -1; + int point = -1; + for (size_t j = 0; j < cnd.size(); j++) { + pTeam src = remainingTeams[cnd[j]]; + int p = 0; + if (src->getClass() == it->getClass()) + p += 1; + if (p > point) { + winnerIx = cnd[j]; + point = p; + } + } + + if (winnerIx != -1) { + processed.insert(it->Id, 1); + pTeam winner = remainingTeams[winnerIx]; + remainingTeams[winnerIx] = 0; + + used.insert(winner->Id, 1); + it->setInputData(*winner); + //checkTargetClass(it, winner, ce.Classes, targetVacant, changedClass); + } + } + } + } +/* + // Transfer vacancies + for (size_t k = 0; k < remainingRunners.size(); k++) { + pRunner src = remainingRunners[k]; + if (!src || used.lookup(src->Id, v)) + continue; + + pRunner targetVacant = ce.getRunner(src->getId(), 0); + if (targetVacant && targetVacant->isVacant() && compareClassName(targetVacant->getClass(), src->getClass()) ) { + targetVacant->setName(src->getName()); + targetVacant->setClub(src->getClub()); + targetVacant->setCardNo(src->getCardNo(), false); + targetVacant->cloneData(src); + assignedVacant.push_back(targetVacant); + } + else { + pClass dstClass = ce.getClass(src->getClassId()); + if (dstClass && compareClassName(dstClass->getName(), src->getClass())) { + if (allowNewEntries.count(src->getClassId())) { + if (src->getClubId() > 0) + ce.getClubCreate(src->getClubId(), src->getClub()); + pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(), + src->getCardNo(), src->getBirthYear(), true); + dst->cloneData(src); + dst->setInputData(*src); + newEntries.push_back(dst); + } + else if (transferAllNoCompete) { + if (src->getClubId() > 0) + ce.getClubCreate(src->getClubId(), src->getClub()); + pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(), + 0, src->getBirthYear(), true); + dst->cloneData(src); + dst->setInputData(*src); + dst->setStatus(StatusNotCompetiting); + notTransfered.push_back(dst); + } + else + notTransfered.push_back(src); + } + } + } + + // Runners on target side not assigned a result + for (size_t k = 0; k < targetRunners.size(); k++) { + if (targetRunners[k] && !processed.count(targetRunners[k]->Id)) { + noAssignmentTarget.push_back(targetRunners[k]); + if (targetRunners[k]->inputStatus == StatusUnknown || + (targetRunners[k]->inputStatus == StatusOK && targetRunners[k]->inputTime == 0)) { + targetRunners[k]->inputStatus = StatusNotCompetiting; + } + } + + }*/ +} + +MetaListContainer &oEvent::getListContainer() const { + if (!listContainer) + throw std::exception("Nullpointer exception"); + return *listContainer; +} + +void oEvent::setExtraLines(const char *attrib, const vector< pair > &lines) { + string str; + + for(size_t k = 0; k < lines.size(); k++) { + if (k>0) + str.push_back('|'); + + string msg = lines[k].first; + for (size_t i = 0; i < msg.size(); i++) { + if (msg[i] == '|') + str.push_back(':'); // Encoding does not support | + else + str.push_back(msg[i]); + } + str.push_back('|'); + str.append(itos(lines[k].second)); + } + getDI().setString(attrib, str); +} + +void oEvent::getExtraLines(const char *attrib, vector< pair > &lines) const { + vector splt; + const string &splitPrintExtra = getDCI().getString(attrib); + split(splitPrintExtra, "|", splt); + lines.clear(); + lines.reserve(splt.size() / 2); + for (size_t k = 0; k + 1 < splt.size(); k+=2) { + lines.push_back(make_pair(splt[k], atoi(splt[k+1].c_str()))); + } + + while(!lines.empty()) { + if (lines.back().first.length() == 0) + lines.pop_back(); + else break; + } +} + +oEvent::MultiStageType oEvent::getMultiStageType() const { + if (getDCI().getString("PreEvent").empty()) + return MultiStageNone; + else + return MultiStageSameEntry; +} + +bool oEvent::hasNextStage() const { + return !getDCI().getString("PostEvent").empty(); +} + +bool oEvent::hasPrevStage() const { + return !getDCI().getString("PreEvent").empty(); +} + +int oEvent::getNumStages() const { + int ns = getDCI().getInt("NumStages"); + if (ns>0) + return ns; + else + return 1; +} + +void oEvent::setNumStages(int numStages) { + getDI().setInt("NumStages", numStages); +} + +int oEvent::getStageNumber() const { + return getDCI().getInt("EventNumber"); +} + +void oEvent::setStageNumber(int num) { + getDI().setInt("EventNumber", num); +} + +oDataContainer &oEvent::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = (pvectorstr)&dynamicData; + return *oEventData; +} + +void oEvent::changedObject() { + globalModification = true; +} + +void oEvent::pushDirectChange() { + PostMessage(gdibase.getMain(), WM_USER + 4, 0, 0); +} + +int oEvent::getBibClassGap() const { + int ns = getDCI().getInt("BibGap"); + return ns; +} + +void oEvent::setBibClassGap(int numStages) { + getDI().setInt("BibGap", numStages); +} + +void oEvent::checkNecessaryFeatures() { + bool hasMultiRace = false; + bool hasRelay = false; + bool hasPatrol = false; + bool hasForkedIndividual = false; + + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { + const oClass &c = *it; + bool multiRace = false; + bool relay = false; + bool patrol = false; + + for (size_t j = 0; j < c.legInfo.size(); j++) { + + if (c.legInfo[j].duplicateRunner != -1) + multiRace = true; + + if (j > 0 && !c.legInfo[j].isParallel() && !c.legInfo[j].isOptional()) { + relay = true; + patrol = false; + } + + if (j > 0 && (c.legInfo[j].isParallel() || c.legInfo[j].isOptional()) && !relay) { + patrol = true; + } + } + + hasForkedIndividual |= c.legInfo.size() == 1; + hasMultiRace |= multiRace; + hasRelay |= relay; + hasPatrol |= patrol; + } + + if (hasForkedIndividual) + oe->getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *this); + + if (hasRelay) + oe->getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this); + + if (hasPatrol) + oe->getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this); + + if (hasMultiRace) + oe->getMeOSFeatures().useFeature(MeOSFeatures::MultipleRaces, true, *this); + + oe->synchronize(true); +} + +bool oEvent::useLongTimes() const { + if (tLongTimesCached != -1) + return tLongTimesCached != 0; + + tLongTimesCached = getDCI().getInt("LongTimes"); + return tLongTimesCached != 0; +} + +void oEvent::useLongTimes(bool use) { + tLongTimesCached = use; + getDI().setInt("LongTimes", use ? 1 : 0); +} + +int oEvent::convertToFullTime(int inTime) { + if (inTime < 0 || !useLongTimes() || inTime > 24*3600) + return inTime; + + return inTime; +} + + +void oEvent::getPayModes(vector< pair > &modes) { + modes.clear(); + modes.reserve(10); + vector< pair > lines; + getExtraLines("PayModes", lines); + + modes.push_back(make_pair(lang.tl("Kontant betalning"), 0)); + map id2ix; + id2ix[0] = 0; + + for (size_t k = 0; k < lines.size(); k++) { + int id = lines[k].second; + if (id2ix.count(id)) + modes[id2ix[id]].first = lines[k].first; + else { + id2ix[id] = k; + modes.push_back(make_pair(lines[k].first, id)); + } + } +} + +void oEvent::setPayMode(int id, const string &mode) { + vector< pair > lines; + getExtraLines("PayModes", lines); + + if (mode.empty()) { + // Remove + for (size_t k = 0; k < lines.size(); k++) { + if (lines[k].second == id) { + bool valid = id != 0; + for (oRunnerList::const_iterator it = Runners.begin(); + valid && it != Runners.end(); ++it) { + if (it->getPaymentMode() == id) + valid = false; + } + for (oTeamList::const_iterator it = Teams.begin(); + valid && it != Teams.end(); ++it) { + if (it->getPaymentMode() == id) + valid = false; + } + + if (!valid) + throw meosException("Betalningsättet behövs och kan inte tas bort."); + + lines.erase(lines.begin() + k); + k--; + } + } + } + else { + // Add / update + bool done = false; + for (size_t k = 0; k < lines.size(); k++) { + if (lines[k].second == id) { + lines[k].first = mode; + done = true; + break; + } + } + if (!done) { + lines.push_back(make_pair(mode, id)); + } + } + + setExtraLines("PayModes", lines); +} + +void oEvent::useDefaultProperties(bool useDefault) { + if (useDefault) { + if (savedProperties.empty()) + savedProperties.swap(eventProperties); + } + else { + if (!savedProperties.empty()) { + savedProperties.swap(eventProperties); + savedProperties.clear(); + } + } +} \ No newline at end of file diff --git a/code/oEvent.h b/code/oEvent.h new file mode 100644 index 0000000..fa80811 --- /dev/null +++ b/code/oEvent.h @@ -0,0 +1,1288 @@ +// oEvent.h: interface for the oEvent class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OEVENT_H__CDA15578_CB62_4EAD_96B9_3037355F5D48__INCLUDED_) +#define AFX_OEVENT_H__CDA15578_CB62_4EAD_96B9_3037355F5D48__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + +#include "oDataContainer.h" + +#include "oControl.h" +#include "oCourse.h" +#include "oClass.h" +#include "oClub.h" +#include "oRunner.h" +#include "oCard.h" +#include "oFreePunch.h" +#include "oTeam.h" + +#include "intkeymap.hpp" +#include +#include +#include +#include + +#define cVacantId 888888888 + +class MeOSFileLock; +class RunnerDB; +class gdioutput; +class oDataContainer; +class oListInfo; +struct oListParam; +struct oPrintPost; +enum EStdListType; +class oFreeImport; +class oWordList; +class ClassConfigInfo; +enum EPostType; +struct SocketPunchInfo; +class DirectSocket; +template class intkeymap; +class MeOSFeatures; +class GeneralResult; +class DynamicResult; +struct SpeakerString; +struct ClassDrawSpecification; +class ImportFormats; + +struct oCounter { + int level1; + int level2; + int level3; + oCounter() : level1(0), level2(0), level3(0) {} + void operator++() {level1++, level2++, level3++;} +}; + + +struct GeneralResultCtr { + string name; + string tag; + string fileSource; + + bool isDynamic() const; + + mutable GeneralResult *ptr; + + GeneralResultCtr(const char *tag, const string &name, GeneralResult *ptr); + GeneralResultCtr(string &file, DynamicResult *ptr); + GeneralResultCtr() : ptr(0) {} + + ~GeneralResultCtr(); + GeneralResultCtr(const GeneralResultCtr &ctr); + void operator=(const GeneralResultCtr &ctr); +}; + +class oTimeLine { +public: + enum TimeLineType {TLTStart, TLTFinish, TLTRadio, TLTExpected}; + enum Priority {PTop = 6, PHigh = 5, PMedium = 4, PLow = 3}; +private: + int time; + string msg; + string detail; + TimeLineType type; + Priority priority; + pair typeId; //True if teamId, otherwise runnerId + int classId; + int ID; +public: + + oTimeLine &setMessage(const string &msg_) {msg = msg_; return *this;} + oTimeLine &setDetail(const string &detail_) {detail = detail_; return *this;} + + const string &getMessage() const {return msg;} + const string &getDetail() const {return detail;} + + int getTime() const {return time;} + TimeLineType getType() const {return type;} + Priority getPriority() const {return priority;} + int getClassId() const {return classId;} + pair getSource() const {return typeId;} + oAbstractRunner *getSource(const oEvent &oe) const; + + __int64 getTag() const; + oTimeLine(int time, TimeLineType type, Priority priority, int classId, int id, oAbstractRunner *source); + virtual ~oTimeLine(); +}; + +typedef multimap TimeLineMap; +typedef TimeLineMap::iterator TimeLineIterator; + +typedef list oControlList; +typedef list oCourseList; +typedef list oClassList; +typedef list oClubList; +typedef list oRunnerList; +typedef list oCardList; +typedef list oTeamList; + +typedef list oFreePunchList; + +typedef int (*GUICALLBACK)(gdioutput *gdi, int type, void *data); + +struct ClassInfo; +struct DrawInfo; + +struct CompetitionInfo { + int Id; + string Name; + string Annotation; + string Date; + string NameId; + string FullPath; + string Server; + string ServerUser; + string ServerPassword; + string Modified; + + string url; + string firstStart; + string account; + string lastNormalEntryDate; + int ServerPort; + int numConnected; // Number of connected entities + int backupId; // Used to identify backups + bool operator<(const CompetitionInfo &ci) + { + if (Date != ci.Date) + return Date TempResultMap; +struct TimeRunner; + +struct PrintPostInfo; + +enum PropertyType { + String, + Integer, + Boolean +}; + +class oEvent : public oBase +{ +private: + oDataDefiner *firstStartDefiner; + oDataDefiner *intervalDefiner; + +protected: + // Revision number for data modified on this client. + unsigned long dataRevision; + + // Set to true if a global modification is made that should case all lists etc to regenerate. + bool globalModification; + + gdioutput &gdibase; + HMODULE hMod;//meosdb.dll + + void generateFixedList(gdioutput &gdi, const oListInfo &li); + + void startReconnectDaemon(); + int getVacantClub(); // Create vacant club if it does not exist + int getVacantClubIfExist() const; + + mutable int vacantId; //Cached vacant id + + string Name; + string Annotation; + string Date; + DWORD ZeroTime; + + mutable map date2LocalTZ; + const string &getTimeZoneString() const; + + int tCurrencyFactor; + string tCurrencySymbol; + string tCurrencySeparator; + bool tCurrencyPreSymbol; + + int tMaxTime; + + bool writeControls(xmlparser &xml); + bool writeCourses(xmlparser &xml); + bool writeClasses(xmlparser &xml); + bool writeClubs(xmlparser &xml); + bool writeRunners(xmlparser &xml, ProgressWindow &pw); + //Write free cards not bound to runner + bool writeCards(xmlparser &xml); + bool writePunches(xmlparser &xml, ProgressWindow &pw); + bool writeTeams(xmlparser &xml); + + oControlList Controls; + oCourseList Courses; + intkeymap courseIdIndex; + oClassList Classes; + oClubList Clubs; + intkeymap clubIdIndex; + + oRunnerList Runners; + intkeymap runnerById; + + RunnerDB *runnerDB; + MeOSFeatures *meosFeatures; + + oCardList Cards; + + oFreePunchList punches; + typedef stdext::hash_multimap PunchIndexType; + typedef PunchIndexType::iterator PunchIterator; + typedef PunchIndexType::const_iterator PunchConstIterator; + /** First level maps a constant based on control number + and index on course to a second maps, that maps cardNo to punches. */ + map punchIndex; + + oTeamList Teams; + intkeymap teamById; + + oDataContainer *oEventData; + oDataContainer *oControlData; + oDataContainer *oCourseData; + oDataContainer *oClassData; + oDataContainer *oClubData; + oDataContainer *oRunnerData; + oDataContainer *oTeamData; + + string sqlUpdateRunners; + string sqlUpdateClasses; + string sqlUpdateCourses; + string sqlUpdateControls; + string sqlUpdateClubs; + string sqlUpdateCards; + string sqlUpdatePunches; + string sqlUpdateTeams; + + int sqlCounterRunners; + int sqlCounterClasses; + int sqlCounterCourses; + int sqlCounterControls; + int sqlCounterClubs; + int sqlCounterCards; + int sqlCounterPunches; + int sqlCounterTeams; + + bool sqlChangedRunners; + bool sqlChangedClasses; + bool sqlChangedCourses; + bool sqlChangedControls; + bool sqlChangedClubs; + bool sqlChangedCards; + bool sqlChangedPunches; + bool sqlChangedTeams; + + + bool needReEvaluate(); + + DirectSocket *directSocket; + + int getFreeRunnerId(); + int getFreeClassId(); + int getFreeCourseId(); + int getFreeControlId(); + int getFreeClubId(); + int getFreeCardId(); + int getFreePunchId(); + int getFreeTeamId(); + + int qFreeRunnerId; + int qFreeClassId; + int qFreeCourseId; + int qFreeControlId; + int qFreeClubId; + int qFreeCardId; + int qFreePunchId; + int qFreeTeamId; + + int nextFreeStartNo; + void updateFreeId(); + void updateFreeId(oBase *ob); + + SortOrder CurrentSortOrder; + + list cinfo; + list backupInfo; + mutable map classTypeNameToType; + + MetaListContainer *listContainer; + char CurrentFile[260]; + char CurrentNameId[64]; + + static int dbVersion; + string MySQLServer; + string MySQLUser; + string MySQLPassword; + int MySQLPort; + + string serverName;//Verified (connected) server name. + + MeOSFileLock *openFileLock; + + bool HasDBConnection; + bool HasPendingDBConnection; + bool msSynchronize(oBase *ob); + void resetChangeStatus(bool onlyChangable=true); + void storeChangeStatus(bool onlyChangable=true); + + string clientName; + vector connectedClients; + DWORD clientCheckSum() const; //Calculate a check sum for current clients + DWORD currentClientCS; //The current, stored check sum. + + //Protected speaker functions. + int computerTime; + + multimap timeLineEvents; + int timeLineRevision; + set timelineClasses; + set modifiedClasses; + + static const int dataSize = 1024; + int getDISize() const {return dataSize;} + BYTE oData[dataSize]; + BYTE oDataOld[dataSize]; + vector< vector > dynamicData; + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + //Precalculated. Used in list processing. + vector currentSplitTimes; + + void initProperties(); + + map eventProperties; + map savedProperties; + + bool tUseStartSeconds; + + set< pair > readPunchHash; + void insertIntoPunchHash(int card, int code, int time); + void removeFromPunchHash(int card, int code, int time); + bool isInPunchHash(int card, int code, int time); + + void generateStatisticsPart(gdioutput &gdi, const vector &type, + const set &feeLimit, int actualFee, bool useReducedFee, + int baseFee, int &entries_sum, int &started_sum, int &fee_sum) const; + void getRunnersPerDistrict(vector &runners) const; + void getDistricts(vector &district); + + void autoAddTeam(pRunner pr); + void autoRemoveTeam(pRunner pr); + + void exportIOFEventList(xmlparser &xml); + void exportIOFEvent(xmlparser &xml); + void exportIOFClass(xmlparser &xml); + void exportIOFStartlist(xmlparser &xml); + void exportIOFClublist(xmlparser &xml); + + void exportIOFResults(xmlparser &xml, bool selfContained, const set &classes, int leg, bool oldStylePatrol); + void exportTeamSplits(xmlparser &xml, const set &classes, bool oldStylePatrol); + + /** Set up transient data in cassss */ + void reinitializeClasses(); + + /** Analyze the result status of each class*/ + void analyzeClassResultStatus() const; + + /// Implementation versions + int setupTimeLineEvents(int classId, int currentTime); + int setupTimeLineEvents(vector &started, const vector< pair > &rc, int currentTime, bool finish); + void timeLinePrognose(TempResultMap &result, TimeRunner &tr, int prelT, + int radioNumber, const string &rname, int radioId); + int nextTimeLineEvent; // Time when next known event will occur. + + // Tables + map tables; + + // Internal list method + void generateListInternal(gdioutput &gdi, const oListInfo &li, bool formatHead); + + /** Format a string for a list. */ + const string &formatListStringAux(const oPrintPost &pp, const oListParam &par, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, oCounter &counter) const; + + /** Format a string that does not depend on team or runner*/ + const string &formatSpecialStringAux(const oPrintPost &pp, const oListParam &par, + const pTeam t, int legIndex, + const pCourse pc, const pControl ctrl, + oCounter &counter) const; + void changedObject(); + + mutable vector generalResults; + + // Temporarily disable recaluclate leader times + bool disableRecalculate; +public: + + enum NameMode { + FirstLast, + LastFirst, + Raw, + }; + +private: + NameMode currentNameMode; + +public: + NameMode getNameMode() const {return currentNameMode;}; + NameMode setNameMode(NameMode newNameMode); + + /// Get new punches since firstTime + void getLatestPunches(int firstTime, vector &punches) const; + + void resetSQLChanged(bool resetAllTeamsRunners, bool cleanClasses); + + void pushDirectChange(); + + void getPayModes(vector< pair > &modes); + void setPayMode(int id, const string &mode); + + bool hasDirectSocket() const {return directSocket != 0;} + DirectSocket &getDirectSocket(); + + bool advancePunchInformation(const vector &gdi, vector &pi, + bool getPunch, bool getFinish); + + // Sets and returns extra lines (string, style) to be printed on the split print, invoice, ... + void setExtraLines(const char *attrib, const vector > &lines); + void getExtraLines(const char *attrib, vector > &lines) const; + + RunnerDB &getRunnerDatabase() const {return *runnerDB;} + + MeOSFeatures &getMeOSFeatures() const {return *meosFeatures;} + void getDBRunnersInEvent(intkeymap &runners) const; + MetaListContainer &getListContainer() const; + string getNameId(int id) const; + const string &getFileNameFromId(int id) const; + + // Adjust team size to class size and create multi runners. + void adjustTeamMultiRunners(pClass cls); + + //Get list of runners in a class + void getRunners(int classId, int courseId, vector &r, bool sortRunners = true); + void getRunnersByCard(int cardNo, vector &r); + + void getTeams(int classId, vector &t, bool sortTeams = true); + + bool hasRank() const; + bool hasBib(bool runnerBib, bool teamBib) const; + bool hasTeam() const; + + /// Speaker timeline + int setupTimeLineEvents(int currentTime); + void renderTimeLineEvents(gdioutput &gdi) const; + int getTimeLineEvents(const set &classes, vector &events, + set<__int64> &stored, int currentTime); + /// Notification that a class has been changed. If only a punch changed + void classChanged(pClass cls, bool punchOnly); + + // Rogaining + bool hasRogaining() const; + + // Maximal time + string getMaximalTimeS() const; + int getMaximalTime() const; + void setMaximalTime(const string &time); + + void saveProperties(const char *file); + void loadProperties(const char *file); + + // Get window handle + HWND hWnd() const; + + /** Get number of classes*/ + int getNumClasses() const {return Classes.size();} + + /** Get number of runners */ + int getNumRunners() const {return runnerById.size();} + + + // Show an warning dialog if database is not sane + void sanityCheck(gdioutput &gdi, bool expectResult, int checkOnlyClass = -1); + + // Automatic draw of all classes + void automaticDrawAll(gdioutput &gdi, const string &firstStart, + const string &minIntervall, const string &vacances, + bool lateBefore, bool softMethod, int pairSize); + + // Restore a backup by renamning the file to .meos + void restoreBackup(); + + void generateVacancyList(gdioutput &gdi, GUICALLBACK callBack); + + // Returns true if there is a multi runner class. + bool hasMultiRunner() const; + + void updateTabs(bool force = false, bool hide = false) const; + bool useRunnerDb() const; + void useRunnerDb(bool use); + + int getFirstClassId(bool teamClass) const; + + void generateCompetitionReport(gdioutput &gdi); + + + // To file if n > 10. + enum InvoicePrintType {IPTAllPrint=1, IPTAllHTML=11, IPTNoMailPrint=2, + IPTNonAcceptedPrint=3, IPTElectronincHTML=12, IPTAllPDF=13}; + + void printInvoices(gdioutput &gdi, InvoicePrintType type, + const string &basePath, bool onlySummary); + void selectRunners(const string &classType, int lowAge, + int highAge, const string &firstDate, + const string &lastDate, bool includeWithFee, + vector &output) const; + + void applyEventFees(bool updateClassFromEvent, + bool updateFees, bool updateCardFees, + const set &classFilter); + + void listConnectedClients(gdioutput &gdi); + void validateClients(); + bool hasClientChanged() const; + + enum PredefinedTypes {PNoSettings, PPool, PForking, PPoolDrawn, PHunting, + PPatrol, PPatrolOptional, PPatrolOneSI, PRelay, PTwinRelay, + PYouthRelay, PNoMulti}; + + void fillPredefinedCmp(gdioutput &gdi, const string &name) const; + + // Sets up class and ajust multirunner in teams and synchronizes. + void setupRelay(oClass &cls, PredefinedTypes type, + int nleg, const string &start); + void setupRelayInfo(PredefinedTypes type, + bool &useNLeg, bool &useNStart); + + void fillLegNumbers(const set &cls, bool isTeamList, + bool includeSubLegs, vector< pair > &out); + + void reCalculateLeaderTimes(int classId); + + void testFreeImport(gdioutput &gdi); + void getFreeImporter(oFreeImport &fi); + + bool importXMLNames(const char *file, + oFreeImport &fi, string &info) const; + + + void calculateSplitResults(int controlIdFrom, int controlIdTo); + // Get total number of completed runner for given class and leg. + void getNumClassRunners(int id, int leg, int &total, int &finished, int &dns) const; + + pTeam findTeam(const string &s, int lastId, stdext::hash_set &filter) const; + pRunner findRunner(const string &s, int lastId, const stdext::hash_set &inputFilter, stdext::hash_set &filter) const; + + static const string &formatStatus(RunnerStatus status); + + inline bool useStartSeconds() const {return tUseStartSeconds;} + void calcUseStartSeconds(); + + void assignCardInteractive(gdioutput &gdi, GUICALLBACK cb); + + int getPropertyInt(const char *name, int def); + const string &getPropertyString(const char *name, const string &def); + string getPropertyStringDecrypt(const char *name, const string &def); + + void setProperty(const char *name, int prop); + void setProperty(const char *name, const string &prop); + void setPropertyEncrypt(const char *name, const string &prop); + + void listProperties(bool userProps, vector< pair > &propNames) const; + + // Get classes that have not yet been drawn. + // someMissing (true = all classes where some runner has no start time) + // (false = all classeds where no runner has a start time) + void getNotDrawnClasses(set &classes, bool someMissing); + void getAllClasses(set &classes); + bool deleteCompetition(); + + void clear(); + + // Drop the open database. + void dropDatabase(); + bool connectToMySQL(const string &server, const string &user, + const string &pwd, int port); + bool connectToServer(); + bool reConnect(char *errorMsg256); + void closeDBConnection(); + + const string &getServerName() const; + + // Upload competition to server + bool uploadSynchronize(); + // Download competition from server + bool readSynchronize(const CompetitionInfo &ci); + + void playPrewarningSounds(const string &basedir, set &controls); + void clearPrewarningSounds(); + void tryPrewarningSounds(const string &basedir, int number); + + int getFreeStartNo() const; + void generatePreReport(gdioutput &gdi); + + void generateList(gdioutput &gdi, bool reEvaluate, const oListInfo &li, bool updateScrollBars); + + void generateListInfo(oListParam &par, int lineHeight, oListInfo &li); + void generateListInfo(vector &par, int lineHeight, oListInfo &li); + void generateListInfo(EStdListType lt, const gdioutput &gdi, int classId, oListInfo &li); + void generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li, const string &name); + + /** Format a string for a list. Returns true of output is not empty*/ + const string &formatListString(const oPrintPost &pp, const oListParam &par, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, oCounter &counter) const; + + const string &formatSpecialString(const oPrintPost &pp, const oListParam &par, + const pTeam t, int legIndex, + const pCourse crs, const pControl ctrl, oCounter &counter) const; + + void calculatePrintPostKey(const list &ppli, gdioutput &gdi, const oListParam &par, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, oCounter &counter, string &key); + const string &formatListString(EPostType type, const pRunner r) const; + const string &formatListString(EPostType type, const pRunner r, const string &format) const; + + + + /** Format a print post. Returns true of output is not empty*/ + bool formatPrintPost(const list &ppli, PrintPostInfo &ppi, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, const pCourse crs, const pControl ctrl, int legIndex); + void listGeneratePunches(const list &ppli, gdioutput &gdi, const oListParam &par, + pTeam t, pRunner r, pClub club, pClass cls); + void getListTypes(map &listMap, int filter); + void getListType(EStdListType type, oListInfo &li); + + void fillListTypes(gdioutput &gdi, const string &name, int filter); + + + void checkOrderIdMultipleCourses(int ClassId); + + void addBib(int ClassId, int leg, const string &firstNumber); + void addAutoBib(); + + //Speaker functions. + void speakerList(gdioutput &gdi, int classId, int leg, int controlId, + int previousControlId, bool totalResults, bool shortNames); + int getComputerTime() const {return (computerTime+500)/1000;} + int getComputerTimeMS() const {return computerTime;} + + void updateComputerTime(); + + // Get set of controls with registered punches + void getFreeControls(set &controlId) const; + // Returns the added punch, of null of already added. + pFreePunch addFreePunch(int time, int type, int card, bool updateRunner); + pFreePunch addFreePunch(oFreePunch &fp); + + bool useLongTimes() const; + void useLongTimes(bool use); + + /** Use the current computer time to convert the specified time to a long time, if long times are used. */ + int convertToFullTime(int inTime); + + /** Internal version of start order optimizer */ + void optimizeStartOrder(vector< vector > > &StartField, DrawInfo &drawInfo, + vector &cInfo, int useNControls, int alteration); + + struct ResultEvent { + ResultEvent() {} + ResultEvent(pRunner r, int time, int control, RunnerStatus status): + r(r), time(time), control(control), status(status), + resultScore(0), place(-1), runTime(0), partialCount(0), legNumber(short(r->tLeg)) {} + + pRunner r; + int time; + int control; + RunnerStatus status; + + int localIndex; + int resultScore; + int runTime; + unsigned short place; + /* By default zero. Used for parallel results etc. + -1 : Ignore + 1,2,3 (how many runners are missing on the leg) + */ + short partialCount; + short legNumber; + + inline int classId() const {return r->getClassId();} + inline int leg() const {return legNumber;} + }; + + void getResultEvents(const set &classFilter, const set &controlFilter, vector &results) const; +protected: + // Returns hash key for punch based on control id, and leg. Class is marked as changed if oldHashKey != newHashKey. + int getControlIdFromPunch(int time, int type, int card, + bool markClassChanged, oFreePunch &punch); + + static void drawSOFTMethod(vector &runners, bool handleBlanks=true); + bool enumerateBackups(const char *file, const char *filetype, int type); + stdext::hash_multimap cardHash; + mutable multimap bibStartNoToRunnerTeam; + int tClubDataRevision; + bool readOnly; + mutable int tLongTimesCached; + + map, oFreePunch> advanceInformationPunches; + +public: + + void useDefaultProperties(bool useDefault); + + bool isReadOnly() const {return readOnly;} + void setReadOnly() {readOnly = true;} + + enum IOFVersion {IOF20, IOF30}; + + void setCurrency(int factor, const string &symbol, const string &separator, bool preSymbol); + string formatCurrency(int c, bool includeSymbol = true) const; + int interpretCurrency(const string &c) const; + int interpretCurrency(double val, const string &cur); + + void setupClubInfoData(); //Precalculate temporary data in club object + + // Clears map if clear is true. A cleared map is not used. Map must be cleared after use, is not updated. + void setupCardHash(bool clear = false); + + void remove(); + bool canRemove() const; + + /// Return revision number for current data + long getRevision() const {return dataRevision;} + + /// Calculate total missed time and other statistics for each control + void setupControlStatistics() const; + + // Get information on classes + void getClassConfigurationInfo(ClassConfigInfo &cnf) const; + + /** Add numbers to make team names unique */ + void makeUniqueTeamNames(); + + void removeVacanies(int classId); + + string getInfo() const {return Name;} + bool verifyConnection(); + bool isClient() const {return HasDBConnection;} + const string &getClientName() const {return clientName;} + void setClientName(const string &n) {clientName=n;} + + void removeFreePunch(int id); + pFreePunch getPunch(int id) const; + pFreePunch getPunch(int runnerId, int courseControlId, int card) const; + void getPunchesForRunner(int runnerId, vector &punches) const; + + //Returns true if data is changed. + bool autoSynchronizeLists(bool syncPunches); + bool synchronizeList(oListId id, bool preSyncEvent = true, bool postSyncEvent = true); + + void generateInForestList(gdioutput &gdi, GUICALLBACK cb, + GUICALLBACK cb_nostart); + + pRunner dbLookUpById(__int64 extId) const; + pRunner dbLookUpByCard(int CardNo) const; + pRunner dbLookUpByName(const string &name, int clubId, + int classId, int birthYear) const; + + void updateRunnerDatabase(); + void updateRunnerDatabase(pRunner r, map &clubIdMap); + + bool exportONattResults(gdioutput &gdi, const string &file); + int getFirstStart(int ClassId=0); + void convertTimes(SICard &sic) const; + + pCard getCard(int Id) const; + pCard getCardByNumber(int cno) const; + bool isCardRead(const SICard &card) const; + void getCards(vector &cards); + + /** Try to find the class that best matches the card. + Negative return = missing controls + Positve return = extra controls + Zero = exact match */ + int findBestClass(const SICard &card, vector &classes) const; + string getCurrentTimeS() const; + + //void reEvaluateClass(const set &classId, bool doSync); + void reEvaluateCourse(int courseId, bool doSync); + void reEvaluateAll(const set &classId, bool doSync); + void reEvaluateChanged(); + + void exportIOFSplits(IOFVersion version, const char *file, bool oldStylePatrolExport, + bool useUTC, + const set &classes, + int leg, + bool teamsAsIndividual, + bool unrollLoops, + bool includeStageData, + bool forceSplitFee); + + void exportIOFStartlist(IOFVersion version, const char *file, + bool useUTC, const set &classes, + bool teamsAsIndividual, + bool includeStageInfo, + bool forceSplitFee); + + bool exportOECSV(const char *file, int LanguageTypeIndex, bool includeSplits); + bool save(); + void duplicate(); + void newCompetition(const string &Name); + void clearListedCmp(); + bool enumerateCompetitions(const char *path, const char *extension); + + bool fillCompetitions(gdioutput &gdi, const string &name, + int type, const string &select = ""); + + bool enumerateBackups(const char *path); + bool listBackups(gdioutput &gdi, GUICALLBACK cb); + const BackupInfo &getBackup(int id) const; + void deleteBackups(const BackupInfo &bu); + + // Check if competition is empty + bool empty() const; + + void generateMinuteStartlist(gdioutput &gdi); + void generateMinuteStartlist(const string &file); + + bool classHasTeams(int Id) const; + bool classHasResults(int Id) const; + bool isCourseUsed(int Id) const; + bool isClassUsed(int Id) const; + bool isControlUsed(int Id) const; + bool isRunnerUsed(int Id) const; + bool isClubUsed(int Id) const; + + void removeRunner(const vector &Ids); + void removeCourse(int Id); + void removeClass(int Id); + void removeControl(int Id); + void removeTeam(int Id); + void removeClub(int Id); + void removeCard(int Id); + + /// Convert a clock time string to time relative zero time + int getRelativeTime(const string &absoluteTime) const; + + /// Convert a clock time string to time relative zero time + int getRelativeTime(const string &date, const string &absoluteTime, const string &timeZone) const; + + /// Convert a clock time string (SI5 12 Hour clock) to time relative zero time + int getRelativeTimeFrom12Hour(const string &absoluteTime) const; + + /// Convert c clock time string to absolute time (after 00:00:00) + static int convertAbsoluteTime(const string &m); + + /// Get clock time from relative time + const string &getAbsTime(DWORD relativeTime) const; + string getAbsDateTimeISO(DWORD relativeTime, bool includeDate, bool useGMT) const; + + const string &getAbsTimeHM(DWORD relativeTime) const; + + const string &getName() const; + string getTitleName() const; + void setName (const string &m); + + const string &getAnnotation() const {return Annotation;} + void setAnnotation(const string &m); + + const string &getDate() const {return Date;} + void setDate(const string &m); + + int getZeroTimeNum() const {return ZeroTime;} + string getZeroTime() const; + void setZeroTime(string m); + + /** Get the automatic bib gap between classes. */ + int getBibClassGap() const; + + /** Set the automatic bib gap between classes. */ + void setBibClassGap(int numStages); + + bool openRunnerDatabase(char *file); + bool saveRunnerDatabase(char *file, bool onlyLocal); + + enum ResultType {RTClassResult, RTTotalResult, RTCourseResult, RTClassCourseResult}; + void calculateResults(ResultType result); + void calculateRogainingResults(); + + void calculateResults(list &rl); + void calculateTeamResults(bool totalMultiday); + bool calculateTeamResults(int leg, bool totalMultiday); + + bool sortRunners(SortOrder so); + /** If linear leg is true, leg is interpreted as actual leg numer, otherwise w.r.t to parallel legs. */ + bool sortTeams(SortOrder so, int leg, bool linearLeg); + + pCard allocateCard(pRunner owner); + + /** Optimize the start order based on drawInfo. Result in cInfo */ + void optimizeStartOrder(gdioutput &gdi, DrawInfo &drawInfo, vector &cInfo); + + void loadDrawSettings(const set &classes, DrawInfo &drawInfo, vector &cInfo) const; + + enum DrawType { + drawAll, remainingBefore, remainingAfter, + }; + + void drawRemaining(bool useSOFTMethod, bool placeAfter); + void drawList(const vector &spec, + bool useSOFTMethod, int pairSize, DrawType drawType); + void drawListClumped(int classID, int firstStart, int interval, int vacances); + void drawPersuitList(int classId, int firstTime, int restartTime, + int ropeTime, int interval, int pairSize, + bool reverse, double scale); + + string getAutoTeamName() const; + pTeam addTeam(const oTeam &t, bool autoAssignStartNo); + pTeam addTeam(const string &pname, int clubId=0, int classId=0); + pTeam getTeam(int Id) const; + pTeam getTeamByName(const string &pname) const; + const vector< pair > &fillTeams(vector< pair > &out, int classId=0); + const vector< pair > &fillStatus(vector< pair > &out); + const vector< pair > &fillControlStatus(vector< pair > &out) const; + + void fillTeams(gdioutput &gdi, const string &id, int ClassId=0); + void fillStatus(gdioutput &gdi, const string &id); + void fillControlStatus(gdioutput &gdi, const string &id) const; + + + string getAutoRunnerName() const; + pRunner addRunner(const string &pname, int clubId, int classId, + int cardNo, int birthYear, bool autoAdd); + + pRunner addRunner(const string &pname, const string &pclub, int classId, + int cardNo, int birthYear, bool autoAdd); + + pRunner addRunnerFromDB(const pRunner db_r, int classId, bool autoAdd); + pRunner addRunner(const oRunner &r, bool updateStartNo); + pRunner addRunnerVacant(int classId); + + pRunner getRunner(int Id, int stage) const; + /** Get a competitor by cardNo. + @param cardNo card number to look for. + @param time if non-zero, try to find a runner actually running on the specified time, if there are multiple runners using the same card. + @param onlyRunnerWithNoCard returns only a runner that has no card tied. + @param ignoreRunnersWithNoStart If true, never return a runner with status NoStart + @return runner of null. + */ + pRunner getRunnerByCardNo(int cardNo, int time, + bool onlyRunnerWithNoCard = false, + bool ignoreRunnersWithNoStart = false) const; + /** Get all competitors for a cardNo. + @param cardNo card number to look for. + @param ignoreRunnersWithNoStart If true, skip runners with status DNS + @param skipDuplicates if true, only return the main instance of each runner (if several races) + @param out runners using the card + */ + void getRunnersByCardNo(int cardNo, bool ignoreRunnersWithNoStart, + bool skipDuplicates, vector &out) const; + /** Finds a runner by start number (linear search). If several runners has same bib/number try to get the right one: + findWithoutCardNo false : find first that has not finished + findWithoutCardNo true : find first with no card. + */ + pRunner getRunnerByBibOrStartNo(const string &bib, bool findWithoutCardNo) const; + + pRunner getRunnerByName(const string &pname, const string &pclub="") const; + + enum FillRunnerFilter {RunnerFilterShowAll = 1, + RunnerFilterOnlyNoResult = 2, + RunnerFilterWithResult = 4, + RunnerCompactMode = 8}; + + const vector< pair > &fillRunners(vector< pair > &out, + bool longName, int filter, + const stdext::hash_set &personFilter); + void fillRunners(gdioutput &gdi, const string &id, bool longName = false, int filter = 0); + + Table *getRunnersTB();//Table mode + Table *getClubsTB(); + Table *getPunchesTB(); + Table *getClassTB(); + Table *getControlTB(); + Table *getCardsTB(); + Table *getTeamsTB(); + Table *getCoursesTB(); + + + void generateTableData(const string &tname, Table &table, TableUpdateInfo &ui); + + void generateControlTableData(Table &table, oControl *addControl); + void generateRunnerTableData(Table &table, oRunner *addRunner); + void generateClassTableData(Table &table, oClass *addClass); + void generateCardTableData(Table &table, oCard *addCard); + void generateClubTableData(Table &table, oClub *club); + void generatePunchTableData(Table &table, oFreePunch *punch); + + void generateCourseTableData(Table &table, oCourse *course); + void generateTeamTableData(Table &table, oTeam *team); + + pClub addClub(const string &pname, int createId=0); + pClub addClub(const oClub &oc); + + void getClubRunners(int clubId, vector &runners) const; + void getClubTeams(int clubId, vector &teams) const; + + //Get club, first by id then by name, and create if it does not exist + pClub getClubCreate(int Id, const string &CreateName); + + void mergeClub(int clubIdPri, int clubIdSec); + pClub getClub(int Id) const; + pClub getClub(const string &pname) const; + const vector< pair > &fillClubs(vector< pair > &out); + void fillClubs(gdioutput &gdi, const string &id); + void getClubs(vector &c, bool sort); + + void viewClubMembers(gdioutput &gdi, int clubId); + + void updateClubsFromDB(); + void updateRunnersFromDB(); + + void fillFees(gdioutput &gdi, const string &name, bool withAuto) const; + string getAutoClassName() const; + pClass addClass(const string &pname, int CourseId = 0, int classId = 0); + pClass addClass(oClass &c); + pClass getClassCreate(int Id, const string &CreateName); + pClass getClass(const string &Name) const; + void getClasses(vector &classes, bool sync) const; + pClass getBestClassMatch(const string &Name) const; + bool getClassesFromBirthYear(int year, PersonSex sex, vector &classes) const; + pClass getClass(int Id) const; + + void getStartBlocks(vector &blocks, vector &starts) const; + + enum ClassFilter { + filterNone, + filterOnlyMulti, + filterOnlySingle, + filterOnlyDirect, + }; + + enum ClassExtra { + extraNone, + extraDrawn, + extraNumMaps, + }; + + const vector< pair > &fillClasses(vector< pair > &out, + ClassExtra extended, ClassFilter filter); + void fillClasses(gdioutput &gdi, const string &id, ClassExtra extended, ClassFilter filter); + + bool fillClassesTB(gdioutput &gdi); + const vector< pair > &fillStarts(vector< pair > &out); + const vector< pair > &fillClassTypes(vector< pair > &out); + void fillStarts(gdioutput &gdi, const string &id); + void fillClassTypes(gdioutput &gdi, const string &id); + + + + string getAutoCourseName() const; + pCourse addCourse(const string &pname, int plength = 0, int id = 0); + pCourse addCourse(const oCourse &oc); + + pCourse getCourseCreate(int Id); + pCourse getCourse(const string &name) const; + pCourse getCourse(int Id) const; + + void getCourses(vector &courses) const; + /** Get controls. If calculateCourseControls, duplicate numbers are calculated for each control and course. */ + void getControls(vector &controls, bool calculateCourseControls) const; + + void fillCourses(gdioutput &gdi, const string &id, bool simple = false); + const vector< pair > &fillCourses(vector< pair > &out, bool simple = false); + + void calculateNumRemainingMaps(); + + pControl getControl(int Id) const; + pControl getControl(int Id, bool create); + enum ControlType {CTAll, CTRealControl, CTCourseControl}; + + const vector< pair > &fillControls(vector< pair > &out, ControlType type); + const vector< pair > &fillControlTypes(vector< pair > &out); + + bool open(int id); + bool open(const string &file, bool import=false); + bool open(const xmlparser &xml); + + bool save(const string &file); + pControl addControl(int Id, int Number, const string &Name); + pControl addControl(const oControl &oc); + int getNextControlNumber() const; + + pCard addCard(const oCard &oc); + + /** Import entry data */ + void importXML_EntryData(gdioutput &gdi, const char *file, bool updateClass, bool removeNonexisting); + +protected: + pClass getXMLClass(const xmlobject &xentry); + pClub getClubCreate(int clubId); + + bool addXMLCompetitorDB(const xmlobject &xentry, int ClubId); + bool addOECSVCompetitorDB(const vector &row); + pRunner addXMLPerson(const xmlobject &person); + pRunner addXMLStart(const xmlobject &xstart, pClass cls); + pRunner addXMLEntry(const xmlobject &xentry, int ClubId, bool setClass); + bool addXMLTeamEntry(const xmlobject &xentry, int ClubId); + bool addXMLClass(const xmlobject &xclub); + bool addXMLClub(const xmlobject &xclub, bool importToDB); + bool addXMLRank(const xmlobject &xrank, map<__int64, int> &externIdToRunnerId); + bool addXMLEvent(const xmlobject &xevent); + + bool addXMLCourse(const xmlobject &xcourse, bool addClasses); + /** type: 0 control, 1 start, 2 finish*/ + bool addXMLControl(const xmlobject &xcontrol, int type); + +public: + + GeneralResult &getGeneralResult(const string &tag, string &sourceFileOut) const; + void getGeneralResults(bool onlyEditable, vector< pair > > &tagNameList, bool includeDateInName) const; + void loadGeneralResults(bool forceReload) const; + + void getPredefinedClassTypes(map &types) const; + + string cloneCompetition(bool cloneRunners, bool cloneTimes, + bool cloneCourses, bool cloneResult, bool addToDate); + + enum ChangedClassMethod { + ChangeClassVacant, + ChangeClass, + TransferNoResult, + TransferAnyway, + }; + + void transferResult(oEvent &ce, + const set &allowNewEntries, + ChangedClassMethod changeClassMethod, + bool transferAllNoCompete, + vector &changedClass, + vector &changedClassNoResult, + vector &assignedVacant, + vector &newEntries, + vector ¬Transfered, + vector &noAssignmentTarget); + + void transferResult(oEvent &ce, + ChangedClassMethod changeClassMethod, + vector &newEntries, + vector ¬Transfered, + vector &noAssignmentTarget); + + enum MultiStageType { + MultiStageNone = 0, + MultiStageSeparateEntry = 1, + MultiStageSameEntry = 2, + }; + + MultiStageType getMultiStageType() const; + bool hasNextStage() const; + bool hasPrevStage() const; + + int getNumStages() const; + void setNumStages(int numStages); + + int getStageNumber() const; + void setStageNumber(int num); + + /** Check that all necessary features are present, (fix by adding features)*/ + void checkNecessaryFeatures(); + + /** Show dialog and return false if card is not used. */ + bool checkCardUsed(gdioutput &gdi, oRunner &runnerToAssignCard, int CardNo); + + void analyseDNS(vector &unknown_dns, vector &known_dns, + vector &known, vector &unknown); + + void importOECSV_Data(const char * oecsvfile, bool clear); + void importXML_IOF_Data(const char *clubfile, const char *competitorfile, bool clear); + + void generateTestCard(SICard &sic) const; + pClass generateTestClass(int nlegs, int nrunners, + char *name, const string &start); + pCourse generateTestCourse(int nCtrl); + void generateTestCompetition(int nClasses, int nRunners, bool generateTeams); + //Returns number of changed, non-saved elements. + int checkChanged(vector &out) const; + void checkDB(); //Check database for consistancy... + oEvent(gdioutput &gdi); + oEvent &operator=(const oEvent &oe); + virtual ~oEvent(); + friend class oAbstractRunner; + friend class oCourse; + friend class oClass; + friend class oClub; + friend class oRunner; + friend class oBase; + friend class oControl; + friend class oTeam; + friend class oCard; + friend class oFreePunch; + + friend class oListInfo; + friend class MeosSQL; + friend class MySQLReconnect; + + friend class TestMeOS; +}; + +#endif // !defined(AFX_OEVENT_H__CDA15578_CB62_4EAD_96B9_3037355F5D48__INCLUDED_) \ No newline at end of file diff --git a/code/oEventDraw.cpp b/code/oEventDraw.cpp new file mode 100644 index 0000000..4a88a88 --- /dev/null +++ b/code/oEventDraw.cpp @@ -0,0 +1,1435 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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 fro more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" +#include "oDataContainer.h" + +#include "random.h" + +#include "meos.h" +#include "meos_util.h" +#include "localizer.h" +#include "gdifonts.h" +#include "oEventDraw.h" +#include "meosexception.h" + +int ClassInfo::sSortOrder=0; + +DrawInfo::DrawInfo() { + vacancyFactor = 0.05; + extraFactor = 0.1; + minVacancy = 1; + maxVacancy = 10; + baseInterval = 60; + minClassInterval = 120; + maxClassInterval = 180; + nFields = 10; + firstStart = 3600; + maxCommonControl = 3; + allowNeighbourSameCourse = true; + coursesTogether = false; + // Statistics output from optimize start order + numDistinctInit = -1; + numRunnerSameInitMax = -1; + minimalStartDepth = -1; +} + +bool ClassInfo::operator <(ClassInfo &ci) +{ + if (sSortOrder==0) { + return sortFactor > ci.sortFactor; + } + else if (sSortOrder == 2) { + return pc->getSortIndex() < ci.pc->getSortIndex(); + } + else if (sSortOrder == 3) { + if (unique != ci.unique) { + if (ci.nRunnersGroup != nRunnersGroup) + return nRunnersGroup > ci.nRunnersGroup; + else + return unique < ci.unique; + } + else + return firstStart > > &StartField, int nFields, + int FirstPos, int PosInterval, ClassInfo &cInfo) +{ + int Type = cInfo.unique; + int courseId = cInfo.courseId; + + int nEntries = cInfo.nRunners; + bool disallowNeighbors = !di.allowNeighbourSameCourse; + // Adjust first pos to make room for extra (before first start) + if (cInfo.nExtra>0) { + int newFirstPos = FirstPos - cInfo.nExtra * PosInterval; + while (newFirstPos<0) + newFirstPos += PosInterval; + int extra = (FirstPos - newFirstPos) / PosInterval; + nEntries += extra; + FirstPos = newFirstPos; + } + + //Check if free at all... + for(int k = 0; k < nEntries; k++){ + bool hasFree=false; + for(int f=0;f 1 && ix+1 < StartField[f].size()) + nextT = StartField[f][ix + 1].second; + if (PosInterval > 1 && ix>0) + prevT = StartField[f][ix - 1].second; + + if ((nextT > 0 && nextT == courseId) || (prevT > 0 && prevT == courseId)) + return false; + } + if (t == 0) + hasFree=true; + else if (t == Type) + return false;//Type of course occupied. Cannot put it here; + } + + if (!hasFree) return false;//No free start position. + } + + return true; +} + +bool insertStart(vector< vector< pair > > &StartField, int nFields, ClassInfo &cInfo) +{ + int Type = cInfo.unique; + int courseId = cInfo.courseId; + int nEntries = cInfo.nRunners; + int FirstPos = cInfo.firstStart; + int PosInterval = cInfo.interval; + + // Adjust first pos to make room for extra (before first start) + if (cInfo.nExtra>0) { + int newFirstPos = FirstPos - cInfo.nExtra * PosInterval; + while (newFirstPos<0) + newFirstPos += PosInterval; + int extra = (FirstPos - newFirstPos) / PosInterval; + nEntries += extra; + FirstPos = newFirstPos; + } + + for (int k=0; k &cInfo) +{ + if (Classes.size()==0) + return; + + struct StartParam { + int nControls; + int alternator; + double badness; + int last; + StartParam() : nControls(1), alternator(1), badness(1000), last(90000000) {} + }; + + StartParam opt; + bool found = false; + int nCtrl = 1;//max(1, di.maxCommonControl-2); + const int maxControlDiff = di.maxCommonControl < 1000 ? di.maxCommonControl : 10; + bool checkOnlyClass = di.maxCommonControl == 1000; + while (!found) { + + StartParam optInner; + for (int alt = 0; alt <= 20 && !found; alt++) { + vector< vector > > startField(di.nFields); + optimizeStartOrder(startField, di, cInfo, nCtrl, alt); + + int overShoot = 0; + int overSum = 0; + int numOver = 0; + for (size_t k=0;k0) { + numOver++; + overShoot = max (overShoot, ci.overShoot); + overSum += ci.overShoot; + } + //laststart=max(laststart, ci.firstStart+ci.nRunners*ci.interval); + } + double avgShoot = double(overSum)/cInfo.size(); + double badness = overShoot==0 ? 0 : overShoot / avgShoot; + + if (badnessmaxControlDiff) //We need some limit + found = true; + } + + vector< vector > > startField(di.nFields); + optimizeStartOrder(startField, di, cInfo, opt.nControls, opt.alternator); + + gdi.addString("", 0, "Identifierar X unika inledningar på banorna.#" + itos(di.numDistinctInit)); + gdi.addString("", 0, "Största gruppen med samma inledning har X platser.#" + itos(di.numRunnerSameInitMax)); + gdi.addString("", 0, "Antal löpare på vanligaste banan X.#" + itos(di.numRunnerSameCourseMax)); + gdi.addString("", 0, "Kortast teoretiska startdjup utan krockar är X minuter.#" + itos(di.minimalStartDepth/60)); + gdi.dropLine(); + //Find last starter + int last = opt.last; + + int laststart=0; + for (size_t k=0;kgetAbsTime(laststart*di.baseInterval+di.firstStart)); + + gdi.dropLine(); + + int nr; + int T=0; + int sum=0; + gdi.addString("", 1, "Antal startande per intervall (inklusive redan lottade):"); + string str=""; + int empty=4; + + while (T <= last) { + nr=0; + for(size_t k=0;k > &classes) { + sort(classes.begin(), classes.end()); + + vector chaining(interval, 0); + + for (int k = int(classes.size())-1 ; k >= 0; k--) { + int ix = 0; + // Find free position + for (int i = 1; i 0) + nr += classes[k].second; + + chaining[ix] += 1 + interval*(nr-1); + } + + int last = chaining[0]; + for (int i = 1; i &classes, DrawInfo &drawInfo, vector &cInfo) const { + drawInfo.firstStart = 3600 * 22; + drawInfo.minClassInterval = 3600; + drawInfo.maxClassInterval = 1; + drawInfo.minVacancy = 10; + drawInfo.maxVacancy = 1; + set reducedStart; + for (set::const_iterator it = classes.begin(); it != classes.end(); ++it) { + pClass pc = oe->getClass(*it); + if (pc) { + int fs = pc->getDrawFirstStart(); + int iv = pc->getDrawInterval(); + if (iv > 0 && fs > 0) { + drawInfo.firstStart = min(drawInfo.firstStart, fs); + drawInfo.minClassInterval = min(drawInfo.minClassInterval, iv); + drawInfo.maxClassInterval = max(drawInfo.maxClassInterval, iv); + drawInfo.minVacancy = min(drawInfo.minVacancy, pc->getDrawVacant()); + drawInfo.maxVacancy = max(drawInfo.maxVacancy, pc->getDrawVacant()); + reducedStart.insert(fs%iv); + } + } + } + + drawInfo.baseInterval = drawInfo.minClassInterval; + int lastStart = -1; + for (set::iterator it = reducedStart.begin(); it != reducedStart.end(); ++it) { + if (lastStart == -1) + lastStart = *it; + else { + drawInfo.baseInterval = min(drawInfo.baseInterval, *it-lastStart); + lastStart = *it; + } + } + + map runnerPerGroup; + map runnerPerCourse; + + cInfo.clear(); + cInfo.resize(classes.size()); + int i = 0; + for (set::const_iterator it = classes.begin(); it != classes.end(); ++it) { + pClass pc = oe->getClass(*it); + if (pc) { + int fs = pc->getDrawFirstStart(); + int iv = pc->getDrawInterval(); + if (iv <= 0) + iv = drawInfo.minClassInterval; + if (fs <= 0) + fs = drawInfo.firstStart; //Fallback + + cInfo[i].pc = pc; + cInfo[i].classId = *it; + cInfo[i].courseId = pc->getCourseId(); + cInfo[i].firstStart = fs; + cInfo[i].unique = pc->getCourseId(); + if (cInfo[i].unique == 0) + cInfo[i].unique = pc->getId() * 10000; + cInfo[i].firstStart = (fs - drawInfo.firstStart) / drawInfo.baseInterval; + cInfo[i].interval = iv / drawInfo.baseInterval; + cInfo[i].nVacant = pc->getDrawVacant(); + cInfo[i].nExtra = pc->getDrawNumReserved(); + + cInfo[i].nRunners = pc->getNumRunners(true, true, true) + cInfo[i].nVacant; + + if (cInfo[i].nRunners>0) { + runnerPerGroup[cInfo[i].unique] += cInfo[i].nRunners; + runnerPerCourse[cInfo[i].courseId] += cInfo[i].nRunners; + } + drawInfo.classes[*it] = cInfo[i]; + i++; + } + } + + for (size_t k = 0; k > > &StartField, DrawInfo &di, + vector &cInfo, int useNControls, int alteration) +{ + + if (di.firstStart<=0) + di.firstStart = 0; + + if (di.minClassInterval < di.baseInterval) { + throw meosException("Startintervallet får inte vara kortare än basintervallet."); + } + + map otherClasses; + cInfo.clear(); + oClassList::iterator c_it; + map runnerPerGroup; + map runnerPerCourse; + int nRunnersTot = 0; + for (c_it=Classes.begin(); c_it != Classes.end(); ++c_it) { + bool drawClass = di.classes.count(c_it->getId())>0; + ClassInfo *cPtr = 0; + + if (!drawClass) { + otherClasses[c_it->getId()] = ClassInfo(&*c_it); + cPtr = &otherClasses[c_it->getId()]; + } + else + cPtr = &di.classes[c_it->getId()]; + + ClassInfo &ci = *cPtr; + pCourse pc = c_it->getCourse(); + + if (pc && useNControls < 1000) { + if (useNControls>0 && pc->nControls>0) + ci.unique = 1000000 + pc->getIdSum(useNControls); + else + ci.unique = 10000 + pc->getId(); + + ci.courseId = pc->getId(); + } + else + ci.unique = ci.classId; + + if (!drawClass) + continue; + + int nr = c_it->getNumRunners(true, true, true); + if (ci.nVacant == -1 || !ci.nVacantSpecified) { + // Auto initialize + int nVacancies = int(nr * di.vacancyFactor + 0.5); + nVacancies = max(nVacancies, di.minVacancy); + nVacancies = min(nVacancies, di.maxVacancy); + nVacancies = max(nVacancies, 0); + + if (di.vacancyFactor == 0) + nVacancies = 0; + + ci.nVacant = nVacancies; + } + + if (!ci.nExtraSpecified) { + // Auto initialize + ci.nExtra = max(int(nr * di.extraFactor + 0.5), 1); + + if (di.extraFactor == 0) + ci.nExtra = 0; + } + + ci.nRunners = nr + ci.nVacant; + + if (ci.nRunners>0) { + nRunnersTot += ci.nRunners + ci.nExtra; + cInfo.push_back(ci); + runnerPerGroup[ci.unique] += ci.nRunners + ci.nExtra; + runnerPerCourse[ci.courseId] += ci.nRunners + ci.nExtra; + } + } + + int maxGroup = 0; + int maxCourse = 0; + int maxNRunner = 0; + int a = 1 + (alteration % 7); + int b = (alteration % 3); + int c = alteration % 5; + + for (size_t k = 0; k::iterator it = runnerPerGroup.begin(); it != runnerPerGroup.end(); ++it) { + vector< pair > classes; + for (size_t k = 0; kfirst) + classes.push_back(make_pair(cInfo[k].nRunners, cInfo[k].nExtra)); + } + int optTime = optimalLayout(di.minClassInterval/di.baseInterval, classes); + bestEndPos = max(optTime, bestEndPos); + } + + if (nRunnersTot > 0) + bestEndPos = max(bestEndPos, nRunnersTot / di.nFields); + + bestEndPos = max(bestEndPos, maxCourse * 2); + + di.minimalStartDepth = bestEndPos * di.baseInterval; + + ClassInfo::sSortOrder = 0; + sort(cInfo.begin(), cInfo.end()); + + int maxSize = di.minClassInterval * maxNRunner; + + // Special case for constant time start + if (di.baseInterval==0) { + di.baseInterval = 1; + di.minClassInterval = 0; + } + + // Calculate an estimated maximal class intervall + for (size_t k = 0; k < cInfo.size(); k++) { + int quotient = maxSize/(cInfo[k].nRunners*di.baseInterval); + + if (quotient*di.baseInterval > di.maxClassInterval) + quotient=di.maxClassInterval/di.baseInterval; + + if (cInfo[k].nRunnersGroup >= maxGroup) + quotient = di.minClassInterval / di.baseInterval; + + if (!cInfo[k].hasFixedTime) + cInfo[k].interval = quotient; + } + + for(int m=0;m < di.nFields;m++) + StartField[m].resize(3000); + + int alternator = 0; + + // Fill up with non-drawn classes + for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { + int st = it->getStartTime(); + int relSt = st-di.firstStart; + int relPos = relSt / di.baseInterval; + + if (st>0 && relSt>=0 && relPos<3000 && (relSt%di.baseInterval) == 0) { + if (otherClasses.count(it->getClassId())==0) + continue; + + if (!di.startName.empty() && it->Class && it->Class->getStart()!=di.startName) + continue; + + ClassInfo &ci = otherClasses[it->getClassId()]; + int k = 0; + while(true) { + if (k==StartField.size()) { + StartField.push_back(vector< pair >()); + StartField.back().resize(3000); + } + if (StartField[k][relPos].first==0) { + StartField[k][relPos].first = ci.unique; + StartField[k][relPos].second = ci.courseId; + break; + } + k++; + } + } + } + + // Fill up classes with fixed starttime + for (size_t k = 0; k < cInfo.size(); k++) { + if (cInfo[k].hasFixedTime) { + insertStart(StartField, di.nFields, cInfo[k]); + } + } + + if (di.minClassInterval == 0) { + // Set fixed start time + for (size_t k = 0; k < cInfo.size(); k++) { + if (cInfo[k].hasFixedTime) + continue; + cInfo[k].firstStart = di.firstStart; + cInfo[k].interval = 0; + } + } + else { + // Do the distribution + for (size_t k = 0; k < cInfo.size(); k++) { + if (cInfo[k].hasFixedTime) + continue; + + int minPos = 1000000; + int minEndPos = 1000000; + int minInterval=cInfo[k].interval; + + for (int i = di.minClassInterval/di.baseInterval; i<=cInfo[k].interval; i++) { + + int startpos = alternator % max(1, (bestEndPos - cInfo[k].nRunners * i)/3); + startpos = 0; + int ipos = startpos; + int t = 0; + + while( !isFree(di, StartField, di.nFields, ipos, i, cInfo[k]) ) { + t++; + + // Algorithm to randomize start position + // First startpos -> bestEndTime, then 0 -> startpos, then remaining + if (t<(bestEndPos-startpos)) + ipos = startpos + t; + else { + ipos = t - (bestEndPos-startpos); + if (ipos>=startpos) + ipos = t; + } + } + + int endPos = ipos + i*cInfo[k].nRunners; + if (endPos < minEndPos || endPos < bestEndPos) { + minEndPos = endPos; + minPos = ipos; + minInterval = i; + } + } + + cInfo[k].firstStart = minPos; + cInfo[k].interval = minInterval; + cInfo[k].overShoot = max(minEndPos - bestEndPos, 0); + insertStart(StartField, di.nFields, cInfo[k]); + + alternator += alteration; + } + } + +} + +void oEvent::drawRemaining(bool useSOFTMethod, bool placeAfter) +{ + DrawType drawType = placeAfter ? remainingAfter : remainingBefore; + + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { + vector spec; + spec.push_back(ClassDrawSpecification(it->getId(), 0, 0, 0, 0)); + + drawList(spec, useSOFTMethod, 1, drawType); + } +} + +void oEvent::drawList(const vector &spec, + bool useSOFTMethod, int pairSize, DrawType drawType) { + + autoSynchronizeLists(false); + assert(pairSize > 0); + oRunnerList::iterator it; + + int VacantClubId=getVacantClub(); + map clsId2Ix; + set clsIdClearVac; + + const bool multiDay = hasPrevStage(); + + for (size_t k = 0; k < spec.size(); k++) { + pClass pc = getClass(spec[k].classID); + + if (!pc) + throw std::exception("Klass saknas"); + + if (spec[k].vacances>0 && pc->getClassType()==oClassRelay) + throw std::exception("Vakanser stöds ej i stafett."); + + if (spec[k].vacances>0 && spec[k].leg>0) + throw std::exception("Det går endast att sätta in vakanser på sträcka 1."); + + if (size_t(spec[k].leg) < pc->legInfo.size()) { + pc->legInfo[spec[k].leg].startMethod = STDrawn; //Automatically change start method + } + clsId2Ix[spec[k].classID] = k; + if (!multiDay && spec[k].leg == 0) + clsIdClearVac.insert(spec[k].classID); + } + + vector runners; + runners.reserve(Runners.size()); + + if (drawType == drawAll) { + + if (!clsIdClearVac.empty()) { + //Only remove vacances on leg 0. + vector toRemove; + //Remove old vacances + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (clsIdClearVac.count(it->getClassId())) { + if (it->isRemoved()) + continue; + if (it->tInTeam) + continue; // Cannot remove team runners + if (it->getClubId()==VacantClubId) { + toRemove.push_back(it->getId()); + } + } + } + + removeRunner(toRemove); + toRemove.clear(); + //loop over specs, check clsIdClearVac... + + for (size_t k = 0; k < spec.size(); k++) { + if (!clsIdClearVac.count(spec[k].classID)) + continue; + for (int i = 0; i < spec[k].vacances; i++) { + oe->addRunnerVacant(spec[k].classID); + } + } + } + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && clsId2Ix.count(it->getClassId())) { + if (it->getStatus() == StatusNotCompetiting) + continue; + int ix = clsId2Ix[it->getClassId()]; + if (it->legToRun() == spec[ix].leg ) { + runners.push_back(&*it); + spec[ix].ntimes++; + } + } + } + } + else { + // Find first/last start in class and interval: + vector first(spec.size(), 7*24*3600); + vector last(spec.size(), 0); + set cinterval; + int baseInterval = 10*60; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && clsId2Ix.count(it->getClassId())) { + if (it->getStatus() == StatusNotCompetiting) + continue; + + int st = it->getStartTime(); + int ix = clsId2Ix[it->getClassId()]; + + if (st>0) { + first[ix] = min(first[ix], st); + last[ix] = max(last[ix], st); + cinterval.insert(st); + } + else { + spec[ix].ntimes++; + runners.push_back(&*it); + } + } + } + + // Find start interval + int t=0; + for (set::iterator sit = cinterval.begin(); sit!=cinterval.end();++sit) { + if ( (*sit-t) > 0) + baseInterval = min(baseInterval, (*sit-t)); + t = *sit; + } + + for (size_t k = 0; k < spec.size(); k++) { + if (drawType == remainingBefore) + spec[k].firstStart = first[k] - runners.size()*baseInterval; + else + spec[k].firstStart = last[k] + baseInterval; + + spec[k].interval = baseInterval; + + if (last[k] == 0 || spec[k].firstStart<=0 || baseInterval == 10*60) { + // Fallback if incorrect specification. + spec[k].firstStart = 3600; + spec[k].interval = 2*60; + } + } + } + + if (runners.empty()) + return; + + vector stimes(runners.size()); + int nr = 0; + for (size_t k = 0; k < spec.size(); k++) { + for (int i = 0; i < spec[k].ntimes; i++) { + int kx = i/pairSize; + stimes[nr++] = spec[k].firstStart + spec[k].interval * kx; + } + } + + if (spec.size() > 1) + sort(stimes.begin(), stimes.end()); + + if (gdibase.isTest()) + InitRanom(0,0); + + if (useSOFTMethod) + drawSOFTMethod(runners); + else + permute(stimes); + + int minStartNo = Runners.size(); + for(unsigned k=0;ksetStartTime(stimes[k], true, false); + minStartNo = min(minStartNo, runners[k]->getStartNo()); + } + + CurrentSortOrder = SortByStartTime; + sort(runners.begin(), runners.end()); + + if (minStartNo == 0) + minStartNo = nextFreeStartNo + 1; + + for(size_t k=0; ksetStartNo(k+minStartNo, false); + runners[k]->synchronize(); + } + + nextFreeStartNo = max(nextFreeStartNo, minStartNo + stimes.size()); +} + + +void getLargestClub(map > &clubRunner, vector &largest) +{ + size_t maxClub=0; + for (map >::iterator it = + clubRunner.begin(); it!=clubRunner.end(); ++it) { + maxClub = max(maxClub, it->second.size()); + } + + for (map >::iterator it = + clubRunner.begin(); it!=clubRunner.end(); ++it) { + if (it->second.size()==maxClub) { + swap(largest, it->second); + clubRunner.erase(it); + return; + } + } +} + +void getRange(int size, vector &p) +{ + p.resize(size); + for (size_t k=0;k &runners, bool handleBlanks) +{ + if (runners.empty()) + return; + + //Group runners per club + map > clubRunner; + + for (size_t k=0;kgetClubId() : -1; + clubRunner[clubId].push_back(runners[k]); + } + + vector< vector > runnerGroups(1); + + // Find largest club + getLargestClub(clubRunner, runnerGroups[0]); + + int largeSize = runnerGroups[0].size(); + int ngroups = (runners.size()+largeSize-1) / largeSize; + runnerGroups.resize(ngroups); + + while (!clubRunner.empty()) { + // Find the smallest available group + unsigned small = runners.size()+1; + int cgroup = -1; + for (size_t k=1;k largest; + getLargestClub(clubRunner, largest); + runnerGroups[cgroup].insert(runnerGroups[cgroup].end(), largest.begin(), largest.end()); + } + + unsigned maxGroup=runnerGroups[0].size(); + + //Permute the first group + vector pg(maxGroup); + getRange(pg.size(), pg); + permute(pg); + vector pr(maxGroup); + for (unsigned k=0;k p(runnerGroups.size()); + getRange(p.size(), p); + permute(p); + + // Write back result + int index = 0; + for (unsigned level = 0; level0 && pc->getClassType()!=oClassIndividual) + throw std::exception("Lottningsmetoden stöds ej i den här klassen."); + + oRunnerList::iterator it; + int nRunners=0; + + autoSynchronizeLists(false); + + while (Vacances>0) { + addRunnerVacant(ClassID); + Vacances--; + } + + for (it=Runners.begin(); it != Runners.end(); ++it) + if (it->Class && it->Class->Id==ClassID) nRunners++; + + if (nRunners==0) return; + + int *stimes=new int[nRunners]; + + + //Number of start groups + //int ngroups=(nRunners/5) + int ginterval; + + if (nRunners>=Interval) + ginterval=10; + else if (Interval/nRunners>60){ + ginterval=40; + } + else if (Interval/nRunners>30){ + ginterval=20; + } + else if (Interval/nRunners>20){ + ginterval=15; + } + else if (Interval/nRunners>10){ + ginterval=1; + } + else ginterval=10; + + int nGroups=Interval/ginterval+1; //15 s. per interval. + int k; + + if (nGroups>0){ + + int MaxRunnersGroup=max((2*nRunners)/nGroups, 4)+GetRandomNumber(2); + int *sgroups=new int[nGroups]; + + for(k=0;k5){ + //Remove second group... + sgroups[1]=sgroups[nGroups-1]; + nGroups--; + } + + if (nGroups>9 && ginterval<60 && (GetRandomBit() || GetRandomBit() || GetRandomBit())){ + //Remove third group... + sgroups[2]=sgroups[nGroups-1]; + nGroups--; + + if (nGroups>13 && ginterval<30 && (GetRandomBit() || GetRandomBit() || GetRandomBit())){ + //Remove third group... + sgroups[3]=sgroups[nGroups-1]; + nGroups--; + + + int ng=4; //Max two minutes pause + while(nGroups>10 && (nRunners/nGroups)5){ + permute(sgroups+2, nGroups-2); + + //Remove some random groups (except first and last). + for(k=2;k5){ + sgroups[k]=sgroups[nGroups-1]; + nGroups--; + } + } + } + + //Premute all groups; + permute(sgroups, nGroups); + + int *counters=new int[nGroups]; + memset(counters, 0, sizeof(int)*nGroups); + + stimes[0]=FirstStart; + stimes[1]=FirstStart+Interval; + + for(k=2;kMaxRunnersGroup){ + g=(g+3)%nGroups; + } + + if (sgroups[g]==FirstStart){ + //Avoid first start + if (GetRandomBit() || GetRandomBit()) + g=(g+1)%nGroups; + } + + if (counters[g]>MaxRunnersGroup){ + g=(g+2)%nGroups; + } + + if (counters[g]>MaxRunnersGroup){ + g=(g+2)%nGroups; + } + + stimes[k]=sgroups[g]; + counters[g]++; + } + + delete[] sgroups; + delete[] counters; + + } + else{ + for(k=0;kClass && it->Class->Id==ClassID){ + it->setStartTime(stimes[k++], true, false); + it->StartNo=k; + it->synchronize(); + } + + delete[] stimes; +} + +void oEvent::automaticDrawAll(gdioutput &gdi, const string &firstStart, + const string &minIntervall, const string &vacances, + bool lateBefore, bool softMethod, int pairSize) +{ + gdi.refresh(); + const int leg = 0; + const double extraFactor = 0.0; + int drawn = 0; + + int baseInterval = convertAbsoluteTimeMS(minIntervall)/2; + + if (baseInterval == 0) { + gdi.fillDown(); + int iFirstStart = getRelativeTime(firstStart); + + if (iFirstStart>0) + gdi.addString("", 1, "Gemensam start"); + else { + gdi.addString("", 1, "Nollställer starttider"); + iFirstStart = 0; + } + gdi.refreshFast(); + gdi.dropLine(); + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (it->isRemoved()) + continue; + vector spec; + spec.push_back(ClassDrawSpecification(it->getId(), 0, iFirstStart, 0, 0)); + oe->drawList(spec, false, 1, drawAll); + } + return; + } + + if (baseInterval<1 || baseInterval>60*60) + throw std::exception("Felaktigt tidsformat för intervall"); + + int iFirstStart = getRelativeTime(firstStart); + + if (iFirstStart<=0) + throw std::exception("Felaktigt tidsformat för första start"); + + double vacancy = atof(vacances.c_str())/100; + + gdi.fillDown(); + gdi.addString("", 1, "Automatisk lottning").setColor(colorGreen); + gdi.addString("", 0, "Inspekterar klasser..."); + gdi.refreshFast(); + + set notDrawn; + getNotDrawnClasses(notDrawn, false); + + set needsCompletion; + getNotDrawnClasses(needsCompletion, true); + + for(set::iterator it = notDrawn.begin(); it!=notDrawn.end(); ++it) + needsCompletion.erase(*it); + + //Start with not drawn classes + map starts; + map runnersPerClass; + + // Count number of runners per start + for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { + if (it->skip()) + continue; + if (it->tLeg != leg) + continue; + if (it->isVacant() && notDrawn.count(it->getClassId())==1) + continue; + pClass pc = it->Class; + + if (pc && pc->hasFreeStart()) + continue; + + if (pc) + ++starts[pc->getStart()]; + + ++runnersPerClass[pc]; + } + + while ( !starts.empty() ) { + // Select smallest start + int runnersStart = Runners.size()+1; + string start; + for ( map::iterator it = starts.begin(); it != starts.end(); ++it) { + if (runnersStart > it->second) { + start = it->first; + runnersStart = it->second; + } + } + starts.erase(start); + + // Estimate parameters for start + DrawInfo di; + int maxRunners = 0; + + // Find largest class in start; + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (it->getStart() != start) + continue; + if (it->hasFreeStart()) + continue; + + maxRunners = max(maxRunners, runnersPerClass[&*it]); + } + + if (maxRunners==0) + continue; + + int maxParallell = 15; + + if (runnersStart < 100) + maxParallell = 4; + else if (runnersStart < 300) + maxParallell = 6; + else if (runnersStart < 700) + maxParallell = 10; + else if (runnersStart < 1000) + maxParallell = 12; + else + maxParallell = 15; + + int optimalParallel = runnersStart / (maxRunners*2); // Min is every second interval + + di.nFields = max(3, min (optimalParallel + 2, 15)); + di.baseInterval = baseInterval; + di.extraFactor = extraFactor; + di.firstStart = iFirstStart; + di.minClassInterval = baseInterval * 2; + di.maxClassInterval = di.minClassInterval; + + di.minVacancy = 1; + di.maxVacancy = 100; + di.vacancyFactor = vacancy; + + di.startName = start; + + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (it->getStart() != start) + continue; + if (notDrawn.count(it->getId())==0) + continue; // Only not drawn classes + if (it->hasFreeStart()) + continue; + + di.classes[it->getId()] = ClassInfo(&*it); + } + + if (di.classes.size()==0) + continue; + + gdi.dropLine(); + gdi.addStringUT(1, lang.tl("Optimerar startfördelning") + " " + start); + gdi.refreshFast(); + gdi.dropLine(); + vector cInfo; + optimizeStartOrder(gdi, di, cInfo); + + + int laststart=0; + for (size_t k=0;kgetClassType() == oClassRelay) { + gdi.addString("", 0, "Hoppar över stafettklass: X#" + + getClass(ci.classId)->getName()).setColor(colorRed); + continue; + } + + gdi.addString("", 0, "Lottar: X#" + getClass(ci.classId)->getName()); + vector spec; + spec.push_back(ClassDrawSpecification(ci.classId, leg, + di.firstStart + di.baseInterval * ci.firstStart, + di.baseInterval * ci.interval, ci.nVacant)); + + drawList(spec, softMethod, pairSize, oEvent::drawAll); + gdi.scrollToBottom(); + gdi.refreshFast(); + drawn++; + } + } + + // Classes that need completion + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (needsCompletion.count(it->getId())==0) + continue; + if (it->hasFreeStart()) + continue; + + gdi.addStringUT(0, lang.tl("Lottar efteranmälda") + ": " + it->getName()); + + vector spec; + spec.push_back(ClassDrawSpecification(it->getId(), leg, 0, 0, 0)); + drawList(spec, softMethod, 1, lateBefore ? remainingBefore : remainingAfter); + + gdi.scrollToBottom(); + gdi.refreshFast(); + drawn++; + } + + gdi.dropLine(); + + if (drawn==0) + gdi.addString("", 1, "Klart: inga klasser behövde lottas.").setColor(colorGreen); + else + gdi.addString("", 1, "Klart: alla klasser lottade.").setColor(colorGreen); + // Relay classes? + gdi.dropLine(); + gdi.refreshFast(); +} + +void oEvent::drawPersuitList(int classId, int firstTime, int restartTime, + int maxTime, int interval, + int pairSize, bool reverse, double scale) { + if (classId<=0) + return; + + pClass pc=getClass(classId); + + if (!pc) + throw std::exception("Klass saknas"); + + const int leg = 0; + if (size_t(leg) < pc->legInfo.size()) { + pc->legInfo[leg].startMethod = STDrawn; //Automatically change start method + } + + vector trunner; + getRunners(classId, 0, trunner); + + vector runner; + runner.reserve(trunner.size()); + for (size_t k = 0; k< trunner.size(); k++) // Only treat specified leg + if (trunner[k]->tLeg == leg) + runner.push_back(trunner[k]); + + if (runner.empty()) + return; + + // Make sure patrol members use the same time + vector adjustedTimes(runner.size()); + for (size_t k = 0; kinputStatus == StatusOK && runner[k]->inputTime>0) { + int it = runner[k]->inputTime; + if (runner[k]->tInTeam) { + for (size_t j = 0; j < runner[k]->tInTeam->Runners.size(); j++) { + int it2 = runner[k]->tInTeam->Runners[j]->inputTime; + if (it2 > 0) + it = max(it, it2); + } + } + adjustedTimes[k] = it; + } + } + + vector< pair > times(runner.size()); + + for (size_t k = 0; kinputStatus == StatusOK && adjustedTimes[k]>0) { + if (scale != 1.0) + times[k].first = int(floor(double(adjustedTimes[k]) * scale + 0.5)); + else + times[k].first = adjustedTimes[k]; + } + else { + times[k].first = 3600 * 24 * 7 + runner[k]->inputStatus; + if (runner[k]->isVacant()) + times[k].first += 10; // Vacansies last + } + } + // Sorted by name in input + stable_sort(times.begin(), times.end()); + + int delta = times[0].first; + + if (delta >= 3600*24*7) + delta = 0; + + int reverseDelta = 0; + if (reverse) { + for (size_t k = 0; ksetStartTime(firstTime + times[k].first - delta, true, false); + else + r->setStartTime(firstTime - times[k].first + reverseDelta, true, false); + } + else if (!reverse) { + if (breakIndex == -1) + breakIndex = k; + + r->setStartTime(restartTime + ((k - breakIndex)/pairSize) * interval, true, false); + } + else { + if (breakIndex == -1) { + breakIndex = times.size() - 1; + odd = times.size() % 2; + } + + r->setStartTime(restartTime + ((breakIndex - k + odd)/pairSize) * interval, true, false); + } + r->synchronize(true); + } +} diff --git a/code/oEventDraw.h b/code/oEventDraw.h new file mode 100644 index 0000000..66ddf9a --- /dev/null +++ b/code/oEventDraw.h @@ -0,0 +1,121 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +struct ClassDrawSpecification { + int classID; + int leg; + mutable int firstStart; + mutable int interval; + int vacances; + mutable int ntimes; + + ClassDrawSpecification() : ntimes(0) {} + ClassDrawSpecification(int classID, int leg, int firstStart, int interval, int vacances) : + classID(classID), leg(leg), firstStart(firstStart), + interval(interval), vacances(vacances), ntimes(0) {} +}; + +enum DrawMethod { + NOMethod = -1, + + DMRandom = 1, + DMSOFT = 2, + DMClumped = 3, + DMSimultaneous = 4, + DMSeeded = 5, + + DMPursuit = 11, + DMReversePursuit = 12 +}; + + +/** Struct with info to draw a class */ +struct ClassInfo { + int classId; + pClass pc; + + int firstStart; + int interval; + + int unique; + int courseId; + int nRunners; + int nRunnersGroup; // Number of runners in group + int nRunnersCourse; // Number of runners on this course + + bool nVacantSpecified; + int nVacant; + + bool nExtraSpecified; + int nExtra; + + int sortFactor; + + // Algorithm status. Extra time needed to start this class. + int overShoot; + + bool hasFixedTime; + + ClassInfo() { + memset(this, 0, sizeof(ClassInfo)); + nVacant = -1; + } + + ClassInfo(pClass pClass) { + memset(this, 0, sizeof(ClassInfo)); + pc = pClass; + classId = pc->getId(); + nVacant = -1; + } + + // Selection of sorting method + static int sSortOrder; + bool operator<(ClassInfo &ci); +}; + + +/**Structure for optimizing start order */ +struct DrawInfo { + DrawInfo(); + double vacancyFactor; + double extraFactor; + int minVacancy; + int maxVacancy; + int baseInterval; + int minClassInterval; + int maxClassInterval; + int nFields; + int firstStart; + int maxCommonControl; + bool allowNeighbourSameCourse; + bool coursesTogether; + // Statistics output from optimize start order + int numDistinctInit; + int numRunnerSameInitMax; + int numRunnerSameCourseMax; + int minimalStartDepth; + + map classes; + string startName; +}; diff --git a/code/oEventResult.cpp b/code/oEventResult.cpp new file mode 100644 index 0000000..c4476c0 --- /dev/null +++ b/code/oEventResult.cpp @@ -0,0 +1,513 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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 fro more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include +#include +#include +#include + +#include "oEvent.h" +#include "oDataContainer.h" + +#include "meosException.h" +#include "TabBase.h" +#include "meos.h" +#include "meos_util.h" +#include "generalresult.h" +#include "metalist.h" +#include "TabList.h" +#include "listeditor.h" + + +void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo) +{ + oRunnerList::iterator it; + + for (it=Runners.begin(); it!=Runners.end(); ++it) { + int st = 0; + if (controlIdFrom > 0) { + RunnerStatus stat; + it->getSplitTime(controlIdFrom, stat, st); + if (stat != StatusOK) { + it->tempStatus = stat; + it->tempRT = 0; + continue; + } + } + if (controlIdTo == 0) { + it->tempRT = max(0, it->FinishTime - (st + it->tStartTime) ); + if (it->tempRT > 0) + it->tempRT += it->getTimeAdjustment(); + it->tempStatus = it->tStatus; + } + else { + int ft = 0; + it->getSplitTime(controlIdTo, it->tempStatus, ft); + if (it->tempStatus==StatusOK && it->tStatus > StatusOK) + it->tempStatus=it->tStatus; + + it->tempRT = max(0, ft - st); + } + } + + Runners.sort(oRunner::sortSplit); + int cClassId=-1; + int cPlace=0; + int vPlace=0; + int cTime=0; + + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (it->getClassId()!=cClassId){ + cClassId=it->getClassId(); + cPlace=0; + vPlace=0; + cTime=0; + it->Class->tLegLeaderTime=9999999; + } + + if (it->tempStatus==StatusOK) { + cPlace++; + + if (it->Class) + it->Class->tLegLeaderTime=min(it->tempRT, it->Class->tLegLeaderTime); + + if (it->tempRT>cTime) + vPlace=cPlace; + + cTime=it->tempRT; + + it->tPlace=vPlace; + } + else + it->tPlace=99000+it->tStatus; + } +} + +void oEvent::calculateResults(ResultType resultType) { + const bool totalResults = resultType == RTTotalResult; + const bool courseResults = resultType == RTCourseResult; + const bool classCourseResults = resultType == RTClassCourseResult; + + if (classCourseResults) + sortRunners(ClassCourseResult); + else if (courseResults) + sortRunners(CourseResult); + else if (!totalResults) + sortRunners(ClassResult); + else + sortRunners(ClassTotalResult); + + oRunnerList::iterator it; + + int cClassId=-1; + int cPlace=0; + int vPlace=0; + int cTime=0; + int cDuplicateLeg=0; + int cLegEquClass = 0; + bool invalidClass = false; + bool useResults = false; + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + // Start new "class" + if (classCourseResults) { + const pCourse crs = it->getCourse(false); + int crsId = it->getClassId() * 997 + (crs ? crs->getId() : 0); + if (crsId != cClassId) { + cClassId = crsId; + cPlace=0; + vPlace=0; + cTime=0; + useResults = it->Class ? !it->Class->getNoTiming() : false; + invalidClass = it->Class ? it->Class->getClassStatus() != oClass::Normal : false; + } + } + else if (courseResults) { + const pCourse crs = it->getCourse(false); + int crsId = crs ? crs->getId() : 0; + if (crsId != cClassId) { + cClassId = crsId; + useResults = crs != 0; + cPlace=0; + vPlace=0; + cTime=0; + } + } + else if (it->getClassId() != cClassId || it->tDuplicateLeg!=cDuplicateLeg || it->tLegEquClass != cLegEquClass) { + cClassId=it->getClassId(); + useResults = it->Class ? !it->Class->getNoTiming() : false; + cPlace=0; + vPlace=0; + cTime=0; + cDuplicateLeg = it->tDuplicateLeg; + cLegEquClass = it->tLegEquClass; + + invalidClass = it->Class ? it->Class->getClassStatus() != oClass::Normal : false; + } + + // Calculate results + if (invalidClass) { + it->tTotalPlace = 0; + it->tPlace = 0; + } + else if (!totalResults) { + int tPlace = 0; + + if (it->tStatus==StatusOK){ + cPlace++; + + int rt = it->getRunningTime() + it->getNumShortening() * 3600 * 24* 8; + + if (rt > cTime) + vPlace=cPlace; + + cTime = rt; + + if (useResults && cTime > 0) + tPlace = vPlace; + } + else + tPlace = 99000 + it->tStatus; + + if (!classCourseResults) + it->tPlace = tPlace; + else + it->tCoursePlace = tPlace; + } + else { + int tt = it->getTotalRunningTime(it->FinishTime); + + if (it->getTotalStatus() == StatusOK && tt>0) { + cPlace++; + + if (tt > cTime) + vPlace = cPlace; + + cTime = tt; + + if (useResults) + it->tTotalPlace = vPlace; + else + it->tTotalPlace = 0; + } + else + it->tTotalPlace = 99000 + it->tStatus; + } + } +} + +void oEvent::calculateRogainingResults() { + sortRunners(ClassPoints); + oRunnerList::iterator it; + + int cClassId=-1; + int cPlace = 0; + int vPlace = 0; + int cTime = numeric_limits::min(); + int cDuplicateLeg=0; + bool useResults = false; + bool isRogaining = false; + bool invalidClass = false; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + + if (it->getClassId()!=cClassId || it->tDuplicateLeg!=cDuplicateLeg) { + cClassId = it->getClassId(); + useResults = it->Class ? !it->Class->getNoTiming() : false; + cPlace = 0; + vPlace = 0; + cTime = numeric_limits::min(); + cDuplicateLeg = it->tDuplicateLeg; + isRogaining = it->Class ? it->Class->isRogaining() : false; + invalidClass = it->Class ? it->Class->getClassStatus() != oClass::Normal : false; + } + + if (!isRogaining) + continue; + + if (invalidClass) { + it->tTotalPlace = 0; + it->tPlace = 0; + } + else if (it->tStatus==StatusOK) { + cPlace++; + + int cmpRes = 3600 * 24 * 7 * it->tRogainingPoints - it->getRunningTime(); + + if (cmpRes != cTime) + vPlace = cPlace; + + cTime = cmpRes; + + if (useResults) + it->tPlace = vPlace; + else + it->tPlace = 0; + } + else + it->tPlace = 99000 + it->tStatus; + } +} + +bool oEvent::calculateTeamResults(int leg, bool totalMultiday) +{ + oTeamList::iterator it; + + bool hasRunner; + if (totalMultiday) + hasRunner = sortTeams(ClassTotalResult, leg, true); + else + hasRunner = sortTeams(ClassResult, leg, true); + + if (!hasRunner) + return false; + + int cClassId=0; + int cPlace=0; + int vPlace=0; + int cTime=0; + bool invalidClass = false; + + for (it=Teams.begin(); it != Teams.end(); ++it){ + if (it->isRemoved()) + continue; + + if (it->Class && it->Class->Id!=cClassId){ + cClassId=it->Class->Id; + cPlace=0; + vPlace=0; + cTime=0; + invalidClass = it->Class->getClassStatus() != oClass::Normal; + } + + int sleg; + if (leg==-1) + sleg=it->Runners.size()-1; + else + sleg=leg; + int p; + if (invalidClass) { + p = 0; + } + else if (it->_cachedStatus == StatusOK){ + cPlace++; + + if (it->_sortTime>cTime) + vPlace=cPlace; + + cTime = it->_sortTime; + + p = vPlace; + } + else { + p = 99000+it->_sortStatus; //XXX Set to zero!? + } + + if (totalMultiday) + it->_places[sleg].totalP = p; + else + it->_places[sleg].p = p; + } + return true; +} + +void oEvent::calculateTeamResults(bool multidayTotal) +{ + for(int i=0;i0) + loadGeneralResults(false); + for (size_t k = 0; k < generalResults.size(); k++) { + if (tag == generalResults[k].tag) { + if (generalResults[k].ptr == 0) + throw meosException("Internal error"); + sourceFileOut = generalResults[k].fileSource; + if (sourceFileOut == "*") + sourceFileOut = ""; + + return *generalResults[k].ptr; + } + } + } + throw meosException("Result module not found: " + tag); +} + +void oEvent::loadGeneralResults(bool forceReload) const { +// OutputDebugString("Load General Results\n"); + char bf[260]; + getUserFile(bf, ""); + vector res; + expandDirectory(bf, "*.rules", res); + vector res2; + expandDirectory(bf, "*.brules", res2); + + DynamicResult dr; + pair err; + + vector newGeneralResults; + set loaded; + set tags; + set loadedRes; + for (size_t k = 0; k < generalResults.size(); k++) { + if (forceReload) { + if (!generalResults[k].isDynamic()) + newGeneralResults.push_back(generalResults[k]); + } + else if (generalResults[k].isDynamic()) { + loaded.insert(generalResults[k].fileSource); + tags.insert(generalResults[k].tag); + loadedRes.insert(dynamic_cast(*generalResults[k].ptr).getHashCode()); + } + } + if (forceReload) + generalResults.clear(); + else + swap(generalResults, newGeneralResults); + + size_t builtIn = res2.size(); + for (size_t k = 0; k < res.size(); k++) + res2.push_back(res[k]); + + for (size_t k = 0; k < res2.size(); k++) { + try { + if (loaded.count(res2[k])) + continue; + + dr.load(res2[k]); + while (tags.count(dr.getTag())) { + dr.setTag(dr.getTag() + "x"); + } + + tags.insert(dr.getTag()); + DynamicResult *drp = new DynamicResult(dr); + if (k < builtIn) + drp->setBuiltIn(); + + loadedRes.insert(drp->getHashCode()); + newGeneralResults.push_back(GeneralResultCtr(res2[k], drp)); + } + catch (std::exception &ex) { + if (err.first.empty()) { + err.first = res2[k]; + err.second = ex.what(); + } + } + } + vector rmAll; + for (int k = 0; k < getListContainer().getNumLists(); k++) { + vector rm; + //if (!getListContainer().isExternal(k)) + // continue; + getListContainer().getList(k).getDynamicResults(rm); + + if (!getListContainer().isExternal(k)) { + for (size_t j = 0; j < rm.size(); j++) { + if (rm[j].res) + rm[j].res->setReadOnly(); + } + } + + rmAll.insert(rmAll.end(), rm.begin(), rm.end()); + } + + // Get the open list from list editor + TabList &tl = dynamic_cast(*gdibase.getTabs().get(TListTab)); + ListEditor *le = tl.getListeditor(); + if (le) { + MetaList *editorList = le->getCurrentList(); + if (editorList) { + vector rm; + editorList->getDynamicResults(rm); + rmAll.insert(rmAll.end(), rm.begin(), rm.end()); + } + } + + for (size_t ii = 1; ii <= rmAll.size(); ii++) { + size_t i = rmAll.size() - ii; + if (!rmAll[i].res) + continue; + long long hash = rmAll[i].res->getHashCode(); + string newTag = rmAll[i].res->getTag(); + + string db = "Load result " + newTag + ", h=" + itos(hash) + "\n"; +// OutputDebugString(db.c_str()); + + if (loadedRes.count(hash) && tags.count(newTag)) + continue; // Already loaded + + if (tags.count(newTag)) { + int n = 1; + newTag = DynamicResult::undecorateTag(newTag); + while(tags.count(newTag + "-v" + itos(n))) { + n++; + } + newTag += "-v" + itos(n); + + string db = "Retag " + newTag + "\n"; +// OutputDebugString(db.c_str()); + + rmAll[i].ctr->retagResultModule(newTag, true); + } + + tags.insert(rmAll[i].res->getTag()); + DynamicResult *drp = new DynamicResult(*rmAll[i].res); + if (rmAll[i].res->isReadOnly()) + drp->setReadOnly(); + drp->setAnnotation(rmAll[i].ctr->getListName()); + string file = "*"; + newGeneralResults.push_back(GeneralResultCtr(file, drp)); + } + + swap(newGeneralResults, generalResults); + if (!err.first.empty()) + throw meosException("Error loading X (Y)#" + err.first + "#" + err.second); +} + + +void oEvent::getGeneralResults(bool onlyEditable, vector< pair > > &tagNameList, bool includeDate) const { + tagNameList.clear(); + for (size_t k = 0; k < generalResults.size(); k++) { + if (!onlyEditable || generalResults[k].isDynamic()) { + tagNameList.push_back(make_pair(100 + k, make_pair(generalResults[k].tag, lang.tl(generalResults[k].name)))); + if (includeDate && generalResults[k].isDynamic()) { + const DynamicResult &dr = dynamic_cast(*generalResults[k].ptr); + const string &date = dr.getTimeStamp(); + if (!date.empty()) + tagNameList.back().second.second += " [" + date + "]"; + } + + } + } +} diff --git a/code/oEventSQL.cpp b/code/oEventSQL.cpp new file mode 100644 index 0000000..e1930cc --- /dev/null +++ b/code/oEventSQL.cpp @@ -0,0 +1,975 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oEvent.cpp: implementation of the oEvent class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" + +#include +#include "oEvent.h" +#include "gdioutput.h" +#include "oDataContainer.h" +#include "csvparser.h" + +#include "TabAuto.h" + +#include "random.h" +#include "SportIdent.h" +#include "meosdb/sqltypes.h" +#include "meosexception.h" +#include "meos_util.h" + +#include "meos.h" +#include +typedef bool (__cdecl* OPENDB_FCN)(void); +typedef int (__cdecl* SYNCHRONIZE_FCN)(oBase *obj); + + + +bool oEvent::connectToServer() +{ + if (isThreadReconnecting()) + return false; + +#ifdef BUILD_DB_DLL + if (msOpenDatabase) + return true; +#endif + +#ifdef BUILD_DB_DLL + hMod=LoadLibrary("meosdb.dll"); + + msOpenDatabase = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msOpenDatabase"); + msConnectToServer = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msConnectToServer"); + msSynchronizeUpdate = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msSynchronizeUpdate"); + msSynchronizeRead = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msSynchronizeRead"); + msSynchronizeList = (SYNCHRONIZELIST_FCN)GetProcAddress(hMod, "msSynchronizeList"); + msRemove = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msRemove"); + msMonitor = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msMonitor"); + msDropDatabase = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msDropDatabase"); + msUploadRunnerDB = (SYNCHRONIZE_FCN)GetProcAddress(hMod, "msUploadRunnerDB"); + + msGetErrorState = (ERRORMESG_FCN)GetProcAddress(hMod, "msGetErrorState"); + msResetConnection = (OPENDB_FCN)GetProcAddress(hMod, "msResetConnection"); + msReConnect = (OPENDB_FCN)GetProcAddress(hMod, "msReConnect"); + + if (!msOpenDatabase || !msSynchronizeUpdate || !msSynchronizeRead + || !msConnectToServer || !msReConnect || !msGetErrorState + || !msMonitor || !msDropDatabase || !msUploadRunnerDB) { + MessageBox(NULL, "Cannot load MySQL library.", NULL, MB_OK); + // handle the error + FreeLibrary(hMod); + hMod=0; + return false;//SOME_ERROR_CODE; + } +#else/* + msOpenDatabase = (SYNCHRONIZE_FCN)::msOpenDatabase; + msConnectToServer = (SYNCHRONIZE_FCN)::msConnectToServer; + msSynchronizeUpdate = (SYNCHRONIZE_FCN)::msSynchronizeUpdate; + msSynchronizeRead = (SYNCHRONIZE_FCN)::msSynchronizeRead; + msSynchronizeList = (SYNCHRONIZELIST_FCN)::msSynchronizeList; + msRemove = (SYNCHRONIZE_FCN)::msRemove; + msMonitor = (SYNCHRONIZE_FCN)::msMonitor; + msDropDatabase = (SYNCHRONIZE_FCN)::msDropDatabase; + msUploadRunnerDB = (SYNCHRONIZE_FCN)::msUploadRunnerDB; + msGetErrorState = (ERRORMESG_FCN)::msGetErrorState; + msResetConnection = (OPENDB_FCN)::msResetConnection; + msReConnect = (OPENDB_FCN)::msReConnect;*/ +#endif + return true; +} + +void oEvent::startReconnectDaemon() +{ + if (isThreadReconnecting()) + return; + + char bf[256]; + msGetErrorState(bf); + + MySQLReconnect msqlr(lang.tl("warning:dbproblem#" + string(bf))); + msqlr.interval=5; + HasDBConnection = false; + HasPendingDBConnection = true; + tabAutoAddMachinge(msqlr); + + gdibase.setDBErrorState(false); + gdibase.setWindowTitle(oe->getTitleName()); + if (!isReadOnly()) { + // Do not show in kiosk-mode + gdibase.alert("warning:dbproblem#" + string(bf)); + } +} + +bool oEvent::msSynchronize(oBase *ob) +{ + //if (!msSynchronizeRead) return true; + if (!HasDBConnection && !HasPendingDBConnection) + return true; + + int ret = msSynchronizeRead(ob); + + char err[256]; + if (msGetErrorState(err)) + gdibase.addInfoBox("sqlerror", err, 15000); + + if (ret==0) { + verifyConnection(); + return false; + } + + if (typeid(*ob)==typeid(oTeam)) { + static_cast(ob)->apply(false, 0, false); + } + + if (ret==1) { + gdibase.RemoveFirstInfoBox("sqlwarning"); + gdibase.addInfoBox("sqlwarning", "Varning: ändringar i X blev överskrivna#" + ob->getInfo(), 5000); + } + return ret!=0; +} + +void oEvent::resetChangeStatus(bool onlyChangable) +{ + if (HasDBConnection) { + if (!onlyChangable) { + // The object here has no dependeces that makes it necessary to set/rest + + for (list::iterator it=oe->punches.begin(); + it!=oe->punches.end(); ++it) + it->resetChangeStatus(); + + //synchronize changed objects + for (list::iterator it=oe->Cards.begin(); + it!=oe->Cards.end(); ++it) + it->resetChangeStatus(); + + for (list::iterator it=oe->Clubs.begin(); + it!=oe->Clubs.end(); ++it) + it->resetChangeStatus(); + + for (list::iterator it=oe->Controls.begin(); + it!=oe->Controls.end(); ++it) + it->resetChangeStatus(); + + for (list::iterator it=oe->Courses.begin(); + it!=oe->Courses.end(); ++it) + it->resetChangeStatus(); + + for (list::iterator it=oe->Classes.begin(); + it!=oe->Classes.end(); ++it) + it->resetChangeStatus(); + } + + for (list::iterator it=oe->Runners.begin(); + it!=oe->Runners.end(); ++it) + it->resetChangeStatus(); + + for (list::iterator it=oe->Teams.begin(); + it!=oe->Teams.end(); ++it) + it->resetChangeStatus(); + } +} + +void oEvent::storeChangeStatus(bool onlyChangable) +{ + if (HasDBConnection) { + if (!onlyChangable) { + // The object here has no dependeces that makes it necessary to set/rest + for (list::iterator it=oe->punches.begin(); + it!=oe->punches.end(); ++it) + it->storeChangeStatus(); + + for (list::iterator it=oe->Cards.begin(); + it!=oe->Cards.end(); ++it) + it->storeChangeStatus(); + + for (list::iterator it=oe->Clubs.begin(); + it!=oe->Clubs.end(); ++it) + it->storeChangeStatus(); + + for (list::iterator it=oe->Controls.begin(); + it!=oe->Controls.end(); ++it) + it->storeChangeStatus(); + + for (list::iterator it=oe->Courses.begin(); + it!=oe->Courses.end(); ++it) + it->storeChangeStatus(); + + for (list::iterator it=oe->Classes.begin(); + it!=oe->Classes.end(); ++it) + it->storeChangeStatus(); + } + + for (list::iterator it=oe->Runners.begin(); + it!=oe->Runners.end(); ++it) + it->storeChangeStatus(); + + for (list::iterator it=oe->Teams.begin(); + it!=oe->Teams.end(); ++it) + it->storeChangeStatus(); + } +} + + +bool oEvent::synchronizeList(oListId id, bool preSyncEvent, bool postSyncEvent) { + if (!HasDBConnection) + return true; + + if (preSyncEvent) { + msSynchronize(this); + resetSQLChanged(true, false); + } + + if ( !msSynchronizeList(this, id) ) { + verifyConnection(); + return false; + } + + if (id == oLPunchId) + advanceInformationPunches.clear(); + + if (postSyncEvent) { + reEvaluateChanged(); + resetChangeStatus(); + return true; + } + + return true; +} + +bool oEvent::needReEvaluate() { + return sqlChangedRunners | + sqlChangedClasses | + sqlChangedCourses | + sqlChangedControls | + sqlChangedCards | + sqlChangedTeams; +} + +void oEvent::resetSQLChanged(bool resetAllTeamsRunners, bool cleanClasses) { + sqlChangedRunners = false; + sqlChangedClasses = false; + sqlChangedCourses = false; + sqlChangedControls = false; + sqlChangedClubs = false; + sqlChangedCards = false; + sqlChangedPunches = false; + sqlChangedTeams = false; + + if (resetAllTeamsRunners) { + for (list::iterator it=oe->Runners.begin(); + it!=oe->Runners.end(); ++it) { + it->storeChangeStatus(); + it->sqlChanged = false; + } + for (list::iterator it=oe->Teams.begin(); + it!=oe->Teams.end(); ++it) { + it->storeChangeStatus(); + it->sqlChanged = false; + } + } + if (cleanClasses) { + // This data is used to redraw lists/speaker etc. + for (list::iterator it=oe->Classes.begin(); + it!=oe->Classes.end(); ++it) { + it->storeChangeStatus(); + it->sqlChangedControlLeg.clear(); + it->sqlChangedLegControl.clear(); + } + globalModification = false; + } +} + +bool BaseIsRemoved(const oBase &ob){return ob.isRemoved();} + +//Returns true if data is changed. +bool oEvent::autoSynchronizeLists(bool SyncPunches) +{ + if (!HasDBConnection) + return false; + + bool changed=false; + string ot; + + int mask = getListMask(*this); + if (mask == 0) + return false; + + // Reset change data and store update status on objects + // (which might be incorrectly changed during sql update) + resetSQLChanged(true, false); + + //Synchronize ourself + if (mask & oLEventId) { + ot=sqlUpdated; + msSynchronize(this); + if (sqlUpdated!=ot) { + changed=true; + gdibase.setWindowTitle(getTitleName()); + } + } + + //Controls + if (mask & oLControlId) { + int oc = sqlCounterControls; + ot = sqlUpdateControls; + synchronizeList(oLControlId, false, false); + changed |= oc!=sqlCounterControls; + changed |= ot!=sqlUpdateControls; + } + + //Courses + if (mask & oLCourseId) { + int oc = sqlCounterCourses; + ot = sqlUpdateCourses; + synchronizeList(oLCourseId, false, false); + changed |= oc!=sqlCounterCourses; + changed |= ot!=sqlUpdateCourses; + } + + //Classes + if (mask & oLClassId) { + int oc = sqlCounterClasses; + ot = sqlUpdateClasses; + synchronizeList(oLClassId, false, false); + changed |= oc!=sqlCounterClasses; + changed |= ot!=sqlUpdateClasses; + } + + //Clubs + if (mask & oLClubId) { + int oc = sqlCounterClubs; + ot = sqlUpdateClubs; + synchronizeList(oLClubId, false, false); + changed |= oc!=sqlCounterClubs; + changed |= ot!=sqlUpdateClubs; + } + + //Cards + if (mask & oLCardId) { + int oc = sqlCounterCards; + ot = sqlUpdateCards; + synchronizeList(oLCardId, false, false); + changed |= oc!=sqlCounterCards; + changed |= ot!=sqlUpdateCards; + } + + //Runners + if (mask & oLRunnerId) { + int oc = sqlCounterRunners; + ot = sqlUpdateRunners; + synchronizeList(oLRunnerId, false, false); + changed |= oc!=sqlCounterRunners; + changed |= ot!=sqlUpdateRunners; + } + + //Teams + if (mask & oLTeamId) { + int oc = sqlCounterTeams; + ot = sqlUpdateTeams; + synchronizeList(oLTeamId, false, false); + changed |= oc!=sqlCounterTeams; + changed |= ot!=sqlUpdateTeams; + } + + if (SyncPunches && (mask & oLPunchId)) { + //Punches + int oc = sqlCounterPunches; + ot = sqlUpdatePunches; + synchronizeList(oLPunchId, false, false); + changed |= oc!=sqlCounterPunches; + changed |= ot!=sqlUpdatePunches; + } + + if (changed) { + if (needReEvaluate()) + reEvaluateChanged(); + + reCalculateLeaderTimes(0); + //Restore changed staus on object that might have been changed + //during sql update, due to partial updates + resetChangeStatus(); + return true; + } + + return false; +} + + +bool oEvent::connectToMySQL(const string &server, const string &user, const string &pwd, int port) +{ + if (isThreadReconnecting()) + return false; + + if (!connectToServer()) + return false; + + MySQLServer=server; + MySQLPassword=pwd; + MySQLPort=port; + MySQLUser=user; + + //Delete non-server competitions. + list saved; + list::iterator it; + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Server.empty()) + saved.push_back(*it); + } + cinfo = saved; + + if (!msConnectToServer(this)) { + char bf[256]; + msGetErrorState(bf); + MessageBox(NULL, lang.tl(bf).c_str(), "Error", MB_OK); + return false; + } + + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Name.size() > 1 && it->Name[0] == '%') + it->Name = lang.tl(it->Name.substr(1)); + } + + return true; +} + + +bool oEvent::uploadSynchronize() +{ + if (isThreadReconnecting()) + throw std::exception("Internt fel i anslutningen. Starta om MeOS"); + string newId = makeValidFileName(CurrentNameId, true); + strcpy_s(CurrentNameId, newId.c_str()); + + for (list::iterator it = cinfo.begin(); it != cinfo.end(); ++it) { + if (it->FullPath == CurrentNameId && it->Server.length()>0) { + gdioutput::AskAnswer ans = gdibase.askCancel("ask:overwrite_server"); + + if (ans == gdioutput::AnswerCancel) + return false; + else if (ans == gdioutput::AnswerNo) { + int len = strlen(CurrentNameId); + char ex[10]; + sprintf_s(ex, "_%05XZ", (GetTickCount()/97) & 0xFFFFF); + if (len > 0) { + if (len< 7 || CurrentNameId[len-1] != 'Z') + strcat_s(CurrentNameId, ex); + else + strcpy_s(CurrentNameId + len - 7, 64 - len + 7, ex); + } + } + else { + if (!gdibase.ask("ask:overwriteconfirm")) + return false; + } + } + } + + HasDBConnection=false; + +#ifdef BUILD_DB_DLL + if (!msSynchronizeUpdate) + throw std::exception("Internt fel. Starta om MeOS"); +#endif + + if ( !msOpenDatabase(this) ){ + char bf[256]; + msGetErrorState(bf); + string error = string("Kunde inte öppna databasen (X).#") + bf; + throw std::exception(error.c_str()); + } + + if ( !msSynchronizeUpdate(this) ) { + char bf[256]; + msGetErrorState(bf); + string error = string("Kunde inte ladda upp tävlingen (X).#") + bf; + throw std::exception(error.c_str()); + } + + OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this); + + if (stat == opStatusFail) { + char bf[256]; + msGetErrorState(bf); + string error = string("Kunde inte ladda upp löpardatabasen (X).#") + bf; + throw meosException(error); + } + else if (stat == opStatusWarning) { + char bf[256]; + msGetErrorState(bf); + gdibase.addInfoBox("", string("Kunde inte ladda upp löpardatabasen (X).#") + bf, 5000); + } + + HasDBConnection=true; + + // Save local version of database + saveRunnerDatabase(CurrentNameId, false); + + return true; +} + +//Load a (new) competition from the server. +bool oEvent::readSynchronize(const CompetitionInfo &ci) +{ + if (ci.Id<=0) + throw std::exception("help:12290"); + + if (isThreadReconnecting()) + return false; + + HasDBConnection=false; + +#ifdef BUILD_DB_DLL + if (!msConnectToServer) + return false; +#endif + + MySQLServer=ci.Server; + MySQLPassword=ci.ServerPassword; + MySQLPort=ci.ServerPort; + MySQLUser=ci.ServerUser; + + //Delete non-server competitions. + list saved; + list::iterator it; + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Server.empty()) + saved.push_back(*it); + } + cinfo=saved; + + if (!msConnectToServer(this)) { + char bf[256]; + msGetErrorState(bf); + throw std::exception(bf); + return false; + } + + for (it=cinfo.begin(); it!=cinfo.end(); ++it) { + if (it->Name.size() > 1 && it->Name[0] == '%') + it->Name = lang.tl(it->Name.substr(1)); + } + + newCompetition(""); + Id=ci.Id; + strcpy_s(CurrentNameId, ci.FullPath.c_str()); + + char file[260]; + sprintf_s(file, "%s.dbmeos", CurrentNameId); + getUserFile(CurrentFile, file); + if ( !msOpenDatabase(this) ) { + char bf[256]; + msGetErrorState(bf); + throw std::exception(bf); + } + + updateFreeId(); + HasDBConnection=false; + + openRunnerDatabase(CurrentNameId); + + int ret = msSynchronizeRead(this); + if (ret == 0) { + char bf[256]; + msGetErrorState(bf); + + string err = string("Kunde inte öppna tävlingen (X)#") + bf; + throw std::exception(err.c_str()); + } + else if (ret == 1) { + // Warning + char bf[256]; + msGetErrorState(bf); + string info = "Databasvarning: X#" + lang.tl(bf); + gdibase.addInfoBox("sqlerror", info, 15000); + } + + // Cache database locally + saveRunnerDatabase(CurrentNameId, false); + + HasDBConnection=true; + + // Setup multirunner links + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) + it->createMultiRunner(false,false); + + // Remove incorrect references + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->multiRunner.size() > 0 ) { + vector &pr = it->multiRunner; + for (size_t k=0; ktParentRunner != &*it) { + it->multiRunner.clear(); + it->updateChanged(); + it->synchronize(); + break; + } + } + } + } + + // Check duplicates + vector usedInTeam(qFreeRunnerId+1); + bool teamCorrected = false; + + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (it->correctionNeeded) { + it->updateChanged(); + teamCorrected = true; + } + + for (size_t i = 0; i < it->Runners.size(); i++) { + pRunner r = it->Runners[i]; + + if (r != 0) { + int expectedIndex = -1; + if (it->Class) + expectedIndex = it->Class->getLegRunnerIndex(i); + + if (expectedIndex>=0 && expectedIndex != r->getMultiIndex()) { + int baseLeg = it->Class->getLegRunner(i); + it->setRunner(baseLeg, r->getMultiRunner(0), true); + teamCorrected = true; + } + } + } + + for (size_t i = 0; i < it->Runners.size(); i++) { + pRunner r = it->Runners[i]; + if (r != 0) { + if (usedInTeam[r->Id]) { + it->Runners[i] = 0; // Reset duplicate runners + it->updateChanged(); + teamCorrected = true; + if (r->tInTeam == &*it) + r->tInTeam = 0; + } + else + usedInTeam[r->Id] = true; + } + } + } + usedInTeam.clear(); + + if (teamCorrected) { + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + it->apply(true, 0, false); + } + } + + reEvaluateAll(set(), false); + vector out; + checkChanged(out); + assert(out.empty()); + + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->correctionNeeded) { + it->createMultiRunner(true, true); + if (it->tInTeam && it->Class) { + pTeam t = it->tInTeam; + int nr = min(int(it->Class->getNumStages())-1, int(it->multiRunner.size())); + t->setRunner(0, &*it, true); + for (int k=0; ksetRunner(k+1, it->multiRunner[k], true); + t->updateChanged(); + t->synchronize(); + } + it->synchronizeAll(); + } + } + + return true; +} + +bool oEvent::reConnect(char *errorMsg256) +{ + if (HasDBConnection) + return true; + + if (isThreadReconnecting()){ + strcpy_s(errorMsg256, 256, "Synkroniseringsfel."); + return false; + } + +#ifdef BUILD_DB_DLL + if (!msReConnect) { + strcpy_s(errorMsg256, 256, "Inte ansluten mot meosdb.dll"); + return false; + } +#endif + + if (msReConnect()) { + HasDBConnection = true; + HasPendingDBConnection = false; + //synchronize changed objects + for (list::iterator it=oe->Cards.begin(); + it!=oe->Cards.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->Clubs.begin(); + it!=oe->Clubs.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->Controls.begin(); + it!=oe->Controls.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->Courses.begin(); + it!=oe->Courses.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->Classes.begin(); + it!=oe->Classes.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->Runners.begin(); + it!=oe->Runners.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->Teams.begin(); + it!=oe->Teams.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + for (list::iterator it=oe->punches.begin(); + it!=oe->punches.end(); ++it) + if (it->isChanged()) + it->synchronize(false); + + autoSynchronizeLists(true); + + return true; + } + + msGetErrorState(errorMsg256); + return false; +} + +//Returns number of changed, non-saved elements. +int oEvent::checkChanged(vector &out) const +{ + int changed=0; + char bf[256]; + out.clear(); + + for (list::iterator it=oe->Cards.begin(); + it!=oe->Cards.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Card %d", it->cardNo); + out.push_back(bf); + it->synchronize(); + } + + for (list::iterator it=oe->Clubs.begin(); + it!=oe->Clubs.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Club %s", it->name.c_str()); + out.push_back(bf); + it->synchronize(); + } + + for (list::iterator it=oe->Controls.begin(); + it!=oe->Controls.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Control %d", it->Numbers[0]); + out.push_back(bf); + it->synchronize(); + } + + for (list::iterator it=oe->Courses.begin(); + it!=oe->Courses.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Course %s", it->Name.c_str()); + out.push_back(bf); + it->synchronize(); + } + + for (list::iterator it=oe->Classes.begin(); + it!=oe->Classes.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Class %s", it->Name.c_str()); + out.push_back(bf); + it->synchronize(); + } + + for (list::iterator it=oe->Runners.begin(); + it!=oe->Runners.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Runner %s", it->getName().c_str()); + out.push_back(bf); + it->synchronize(); + } + for (list::iterator it=oe->Teams.begin(); + it!=oe->Teams.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Team %s", it->getName().c_str()); + out.push_back(bf); + it->synchronize(); + } + for (list::iterator it=oe->punches.begin(); + it!=oe->punches.end(); ++it) + if (it->isChanged()) { + changed++; + sprintf_s(bf, "Punch SI=%d, %d", it->CardNo, it->Type); + out.push_back(bf); + it->synchronize(); + } + + return changed; +} + +bool oEvent::verifyConnection() +{ + if (!HasDBConnection) + return false; + + if (isThreadReconnecting()) + return false; + +#ifdef BUILD_DB_DLL + if (!msMonitor) + return false; +#endif + + if (!msMonitor(this)) { + startReconnectDaemon(); + return false; + } + return true; +} + +const string &oEvent::getServerName() const +{ + return serverName; +} + +void oEvent::closeDBConnection() +{ + bool hadDB=HasDBConnection; + + if (isThreadReconnecting()) { + //Don't know what to do?! + } + gdibase.setWaitCursor(true); + if (HasDBConnection) { + autoSynchronizeLists(true); + } + HasDBConnection=false; + + #ifdef BUILD_DB_DLL + if (msResetConnection) + msResetConnection(); + #else + msResetConnection(); + #endif + Id=0; + + if (!oe->empty() && hadDB) { + save(); + Name+=" (Lokal kopia från: " + serverName + ")"; + char cn[260]; + sprintf_s(cn, "%s.%s.meos", CurrentNameId, serverName.c_str()); + getUserFile(CurrentFile, cn); + serverName.clear(); + save(); + gdibase.setWindowTitle(Name); + } + else serverName.clear(); + + gdibase.setWaitCursor(false); +} + +void oEvent::listConnectedClients(gdioutput &gdi) +{ + gdi.addString("", 1, "Anslutna klienter:"); + char bf[256]; + gdi.fillRight(); + gdi.pushX(); + int x=gdi.getCX(); + for (size_t k=0;k0) + throw std::exception(bf); + + throw std::exception("Operationen misslyckades. Orsak okänd."); + } + clear(); +} + diff --git a/code/oEventSpeaker.cpp b/code/oEventSpeaker.cpp new file mode 100644 index 0000000..46bf295 --- /dev/null +++ b/code/oEventSpeaker.cpp @@ -0,0 +1,1874 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include + +#include "oEvent.h" +#include "oSpeaker.h" +#include "gdioutput.h" + +#include "SportIdent.h" +#include "mmsystem.h" +#include "meos_util.h" +#include "localizer.h" +#include "meos.h" +#include "gdifonts.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + +oTimeLine::oTimeLine(int time_, TimeLineType type_, Priority priority_, int classId_, int ID_, oAbstractRunner *source) : + time(time_), type(type_), priority(priority_), classId(classId_), ID(ID_) +{ + if (source) { + typeId.second = source->getId(); + typeId.first = typeid(*source)==typeid(oTeam); + } + else { + typeId.first = false; + typeId.second = 0; + } +} + +pCourse deduceSampleCourse(pClass pc, vector &stages, int leg) { + int courseLeg = leg; + for (size_t k = 0; k hasMultiCourse()) + return pc->getCourse(courseLeg, 0, true); + else + return pc->getCourse(true); +} + +oAbstractRunner *oTimeLine::getSource(const oEvent &oe) const { + //assert(typeId.second != 0); + if (typeId.second > 0) { + if (typeId.first) + return oe.getTeam(typeId.second); + else + return oe.getRunner(typeId.second, 0); + } + return 0; +} + + +__int64 oTimeLine::getTag() const { + __int64 cs = type != TLTExpected ? time : 0; + cs = 997 * cs + type; + cs = 997 * cs + priority; + cs = 997 * cs + classId; + cs = 997 * cs + ID; + cs = 997 * cs + typeId.second; + + return cs; +} + +//Order by preliminary times and priotity for speaker list +bool CompareSpkSPList(const oSpeakerObject &a, const oSpeakerObject &b) +{ + if (a.priority!=b.priority) + return a.priority>b.priority; + else if (a.status<=1 && b.status<=1){ + int at=a.runningTime.preliminary; + int bt=b.runningTime.preliminary; + + if (at==bt) { //Compare leg times instead + at=a.runningTimeLeg.preliminary; + bt=b.runningTimeLeg.preliminary; + } + + if (at == bt) { + if (a.runningTimeSinceLast.preliminary > 0 && b.runningTimeSinceLast.preliminary > 0) { + if (a.runningTimeSinceLast.preliminary != b.runningTimeSinceLast.preliminary) + return a.runningTimeSinceLast.preliminary > b.runningTimeSinceLast.preliminary; + } + else if (a.runningTimeSinceLast.preliminary>0) + return true; + else if (b.runningTimeSinceLast.preliminary>0) + return false; + } + + if (a.missingStartTime != b.missingStartTime) + return a.missingStartTime < b.missingStartTime; + + if (at==bt) { + if (a.parallelScore != b.parallelScore) + return a.parallelScore > b.parallelScore; + + if (a.bib != b.bib) { + return compareBib(a.bib, b.bib); + } + return a.names=0 && bt>=0) { + if (a.priority == 0) + return bt=0 && bt<0) + return true; + else if (at<0 && bt>=0) + return false; + else return at>bt; + } + else if (a.status!=b.status) + return a.status b.parallelScore; + + if (a.bib != b.bib) { + return compareBib(a.bib, b.bib); + } + + return a.namesgetData("oEvent", *LPDWORD(&oe)); + + if (!oe) + return false; + + DWORD classId=0, controlId=0, previousControlId, leg=0, totalResult=0, shortNames = 0; + gdi->getData("ClassId", classId); + gdi->getData("ControlId", controlId); + gdi->getData("PreviousControlId", previousControlId); + gdi->getData("LegNo", leg); + gdi->getData("TotalResult", totalResult); + gdi->getData("ShortNames", shortNames); + + if (classId>0 && controlId>0) { + pClass pc = oe->getClass(classId); + bool update = false; + if (type == GUI_TIMEOUT) + update = true; + else if (pc) { + vector stages; + pc->getTrueStages(stages); + int trueIndex = -1; + int start = 0; + for (size_t k = 0; k < stages.size(); k++) { + if (leg <= DWORD(stages[k].first)) { + trueIndex = k; + if (k > 0) + start = stages[k-1].first + 1; + break; + } + } + int cid = oControl::getIdIndexFromCourseControlId(controlId).first; + if (trueIndex != -1) { + /// Check all legs corresponding to the true leg. + for (int k = start; k <= stages[trueIndex].first; k++) { + if (pc->wasSQLChanged(k, cid)) { + update = true; + break; + } + } + } + else if (pc->wasSQLChanged(-1, cid)) + update = true; + } + + if (update) + oe->speakerList(*gdi, classId, leg, controlId, previousControlId, + totalResult != 0, shortNames != 0); + } + + return true; +} + +int MovePriorityCB(gdioutput *gdi, int type, void *data) { + if (type==GUI_LINK){ + + oEvent *oe=0; + gdi->getData("oEvent", *LPDWORD(&oe)); + if (!oe) return false; + + TextInfo *ti=(TextInfo *)data; + //gdi->alert(ti->id); + if (ti->id.size()>1){ + //int rid=atoi(ti->id.substr(1).c_str()); + int rid = ti->getExtraInt(); + oRunner *r= oe->getRunner(rid, 0); + if (!r) return false; + + DWORD classId=0, controlId=0, previousControlId = 0; + if (gdi->getData("ClassId", classId) && gdi->getData("ControlId", controlId) && gdi->getData("PreviousControlId", previousControlId)){ + DWORD leg = 0, totalResult = 0, shortNames = 0; + gdi->getData("LegNo", leg); + gdi->getData("TotalResult", totalResult); + gdi->getData("ShortNames", shortNames); + + if (ti->id[0]=='D'){ + r->setPriority(controlId, -1); + } + else if (ti->id[0]=='U'){ + r->setPriority(controlId, 1); + } + else if (ti->id[0]=='M'){ + r->setPriority(controlId, 0); + } + oe->speakerList(*gdi, classId, leg, controlId, previousControlId, totalResult != 0, shortNames != 0); + } + } + } + return true; +} + +void renderRowSpeakerList(const oSpeakerObject &r, const oSpeakerObject *next_r, + int leaderTime, int type, vector &row, bool shortName) { + + if (r.place > 0) + row.push_back(SpeakerString(textRight, itos(r.place))); + else + row.push_back(SpeakerString()); + + string names; + for (size_t k = 0; k < r.names.size(); k++) { + if (names.empty()) { + if (!r.bib.empty()) + names += r.bib + ": "; + } + else { + names += "/"; + } + if (!shortName) { + names += r.names[k]; + } + else { + vector splt; + split(r.names[k], " ", splt); + for (size_t j = 0; j < splt.size(); j++) { + if (j == 0) { + if (splt.size()>1 && splt[j].length() > 1) + names += splt[j].substr(0, 1) + "."; + else + names += splt[j]; + } + else + names += " " + splt[j]; + } + } + } + + if (r.runnersFinishedLeg < r.runnersTotalLeg && r.runnersFinishedLeg>0) { + // Fraction of runners has finished on leg + names += " (" + itos(r.runnersFinishedLeg) + "/" + itos(r.runnersTotalLeg) + ")"; + } + + for (size_t k = 0; k < r.outgoingnames.size(); k++) { + if (k == 0) { + names += " > "; + } + else + names += "/"; + + if (!shortName) { + names += r.outgoingnames[k]; + } + else { + vector splt; + split( r.outgoingnames[k], " ", splt); + for (size_t j = 0; j < splt.size(); j++) { + if (j == 0) { + if (splt.size()>1 && splt[j].length() > 1) + names += splt[j].substr(0, 1) + "."; + else + names += splt[j]; + } + else + names += " " + splt[j]; + } + } + } + + if (r.finishStatus<=1 || r.finishStatus==r.status) + row.push_back(SpeakerString(normalText, names)); + else + row.push_back(SpeakerString(normalText, names + " ("+ oEvent::formatStatus(r.finishStatus) +")")); + + row.push_back(SpeakerString(normalText, r.club)); + + if (r.status == StatusOK) { + row.push_back(SpeakerString(textRight, formatTime(r.runningTime.preliminary))); + + if (r.runningTime.time != r.runningTimeLeg.time) + row.push_back(SpeakerString(textRight, formatTime(r.runningTimeLeg.time))); + else + row.push_back(SpeakerString()); + + if (leaderTime!=100000 && leaderTime>0){ + row.push_back(SpeakerString(textRight, gdioutput::getTimerText(r.runningTime.time-leaderTime, + timerCanBeNegative))); + } + else + row.push_back(SpeakerString()); + /* + if (r.timeSinceChange < 10 && r.timeSinceChange>=0) { + RECT rc; + rc.left=x+dx[1]-4; + rc.right=x+dx[7]+gdi.scaleLength(60); + rc.top=y-1; + rc.bottom=y+lh+1; + gdi.addRectangle(rc, colorLightGreen, false); + }*/ + } + else if (r.status == StatusUnknown) { + DWORD TimeOut=NOTIMEOUT; + + if (r.runningTimeLeg.preliminary>0 && !r.missingStartTime) { + + if (next_r && next_r->status==StatusOK && next_r->runningTime.preliminary > r.runningTime.preliminary) + TimeOut = next_r->runningTime.preliminary; + + row.push_back(SpeakerString(textRight, r.runningTime.preliminary, TimeOut)); + + if (r.runningTime.preliminary != r.runningTimeLeg.preliminary) + row.push_back(SpeakerString(textRight, r.runningTimeLeg.preliminary)); + else + row.push_back(SpeakerString()); + + if (leaderTime != 100000) + row.push_back(SpeakerString(timerCanBeNegative|textRight, r.runningTime.preliminary - leaderTime)); + else + row.push_back(SpeakerString()); + + //gdi.addTimer(y, x+dx[5], timerCanBeNegative|textRight, r.runningTime.preliminary - leaderTime); + } + else{ + //gdi.addStringUT(y, x+dx[4], textRight, "["+r.startTimeS+"]"); + row.push_back(SpeakerString(textRight, "["+r.startTimeS+"]")); + + if (!r.missingStartTime) + row.push_back(SpeakerString(timerCanBeNegative|textRight, r.runningTimeLeg.preliminary)); + //gdi.addTimer(y, x+dx[5], timerCanBeNegative|textRight, r.runningTimeLeg.preliminary, 0, SpeakerCB, NOTIMEOUT); + else + row.push_back(SpeakerString()); + + row.push_back(SpeakerString()); + } + } + else{ + //gdi.addStringUT(y, x+dx[4], textRight, oEvent::formatStatus(r.status)).setColor(colorDarkRed); + row.push_back(SpeakerString()); + row.push_back(SpeakerString(textRight, oEvent::formatStatus(r.status))); + row.back().color = colorDarkRed; + row.push_back(SpeakerString()); + } + + int ownerId = r.owner ? r.owner->getId(): 0; + if (type==1) { + row.push_back(SpeakerString(normalText, lang.tl("[Bort]"))); + row.back().color = colorRed; + row.back().moveKey = "D" + itos(ownerId); + } + else if (type==2) { + row.push_back(SpeakerString(normalText, lang.tl("[Bevaka]"))); + row.back().color = colorGreen; + row.back().moveKey = "U" + itos(ownerId); + + row.push_back(SpeakerString(normalText, lang.tl("[Bort]"))); + row.back().color = colorRed; + row.back().moveKey = "D" + itos(ownerId); + } + else if (type == 3) { + if (r.status <= StatusOK) { + if (r.priority < 0) { + row.push_back(SpeakerString(normalText, lang.tl("[Återställ]"))); + row.back().moveKey = "M" + itos(ownerId); + } + else{ + row.push_back(SpeakerString(normalText, lang.tl("[Bevaka]"))); + row.back().moveKey = "U" + itos(ownerId); + } + } + } +} + +void renderRowSpeakerList(gdioutput &gdi, int type, const oSpeakerObject &r, int x, int y, + const vector &row, const vector &pos) { + int lh=gdi.getLineHeight(); + bool highlight = false; + if (r.timeSinceChange < 20 && r.timeSinceChange>=0) { + RECT rc; + rc.left = x+pos[1] - 4; + rc.right=x+pos.back()+gdi.scaleLength(60); + rc.top=y-1; + rc.bottom=y+lh+1; + gdi.addRectangle(rc, colorLightGreen, false); + highlight = true; + } + + for (size_t k = 0; k < row.size(); k++) { + int limit = pos[k+1]-pos[k]-3; + if (limit < 0) + limit = 0; + if (!row[k].hasTimer) { + if (!row[k].str.empty()) { + if (row[k].moveKey.empty()) { + + TextInfo &ti = gdi.addStringUT(y, x+pos[k], row[k].format, row[k].str, limit); + if (row[k].color != colorDefault) + ti.setColor(row[k].color); + } + else { + TextInfo &ti = gdi.addStringUT(y, x+pos[k], row[k].format, row[k].str, limit, MovePriorityCB); + ti.id = row[k].moveKey; + ti.setExtra(r.owner->getId()); + if (!highlight && row[k].color != colorDefault) + ti.setColor(row[k].color); + } + } + } + else { + gdi.addTimer(y, x + pos[k], row[k].format, row[k].timer, limit, + row[k].timeout != NOTIMEOUT ? SpeakerCB : 0, row[k].timeout); + } + } +} + +void oEvent::calculateResults(list &rl) +{ + rl.sort(CompareSOResult); + list::iterator it; + + int cPlace=0; + int vPlace=0; + int cTime=0; + + for (it=rl.begin(); it != rl.end(); ++it) { + if (it->status==StatusOK) { + cPlace++; + int rt = it->runningTime.time; + if (rt>cTime) + vPlace=cPlace; + cTime=rt; + it->place=vPlace; + } + else + it->place = 0; + } +} + +void oEvent::speakerList(gdioutput &gdi, int ClassId, int leg, int ControlId, + int PreviousControlId, bool totalResults, bool shortNames) { +#ifdef _DEBUG + OutputDebugString("SpeakerListUpdate\n"); +#endif + + DWORD clsIds = 0, ctrlIds = 0, cLegs = 0, cTotal = 0, cShort = 0; + gdi.getData("ClassId", clsIds); + gdi.getData("ControlId", ctrlIds); + gdi.getData("LegNo", cLegs); + gdi.getData("TotalResult", cTotal); + gdi.getData("ShortNames", cShort); + + bool refresh = clsIds == ClassId && ctrlIds == ControlId && leg == cLegs && + (totalResults ? 1 : 0) == cTotal && (shortNames ? 1 : 0) == cShort; + + if (refresh) + gdi.takeShownStringsSnapshot(); + + int storedY = gdi.GetOffsetY(); + int storedHeight = gdi.getHeight(); + + gdi.restoreNoUpdate("SpeakerList"); + gdi.setRestorePoint("SpeakerList"); + + gdi.pushX(); gdi.pushY(); + gdi.updatePos(0,0,0, storedHeight); + gdi.popX(); gdi.popY(); + gdi.SetOffsetY(storedY); + + gdi.setData("ClassId", ClassId); + gdi.setData("ControlId", ControlId); + gdi.setData("PreviousControlId", PreviousControlId); + gdi.setData("LegNo", leg); + gdi.setData("TotalResult", totalResults ? 1 : 0); + gdi.setData("ShortNames", shortNames ? 1 : 0); + + gdi.setData("oEvent", DWORD(this)); + + gdi.registerEvent("DataUpdate", SpeakerCB); + gdi.setData("DataSync", 1); + gdi.setData("PunchSync", 1); + + list speakerList; + + //For preliminary times + updateComputerTime(); + + speakerList.clear(); + if (classHasTeams(ClassId)) { + oTeamList::iterator it=Teams.begin(); + while(it!=Teams.end()){ + if (it->getClassId()==ClassId && !it->skip()) { + oSpeakerObject so; + it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so); + if (so.owner) + speakerList.push_back(so); + } + ++it; + } + } + else { + oRunnerList::iterator it=Runners.begin(); + while(it!=Runners.end()){ + if (it->getClassId()==ClassId && !it->skip()) { + oSpeakerObject so; + it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so); + if (so.owner) + speakerList.push_back(so); + } + ++it; + } + } + if (speakerList.empty()) { + gdi.dropLine(); + gdi.addString("", fontMediumPlus, "Inga deltagare"); + gdi.refresh(); + return; + } + + list::iterator sit; + for (sit=speakerList.begin(); sit != speakerList.end(); ++sit) { + if (sit->status==StatusOK && sit->priority>=0) + sit->priority=1; + else if (sit->status > StatusOK && sit->priority<=0) + sit->priority=-1; + } + + //Calculate place... + calculateResults(speakerList); + + //Calculate preliminary times and sort by this and prio. + speakerList.sort(CompareSpkSPList); + + //char bf[256]; + pClass pCls=oe->getClass(ClassId); + + if (!pCls) + return; + + vector stages; + pCls->getTrueStages(stages); + + pCourse crs = deduceSampleCourse(pCls, stages, leg); + + //char bf2[64]=""; + string legName, cname = pCls->getName(); + size_t istage = -1; + for (size_t k = 0; k < stages.size(); k++) { + if (stages[k].first >= leg) { + istage = k; + break; + } + } + if (stages.size()>1 && istage < stages.size()) + cname += lang.tl(", Sträcka X#" + itos(stages[istage].second)); + + if (ControlId != oPunch::PunchFinish && crs) { + cname += ", " + crs->getRadioName(ControlId); + } + else { + cname += lang.tl(", Mål"); + } + + int y=gdi.getCY()+5; + int x=30; + + gdi.addStringUT(y, x, fontMediumPlus, cname).setColor(colorGreyBlue); + int lh=gdi.getLineHeight(); + + y+=lh*2; + int LeaderTime=100000; + + //Calculate leader-time + for(sit=speakerList.begin(); sit != speakerList.end(); ++sit) { + int rt = sit->runningTime.time; + if (sit->status==StatusOK && rt>0) + LeaderTime=min(LeaderTime, rt); + } + + vector< pair > > toRender(speakerList.size()); + /*const int dx_c[8]={0, 40, 280, 530-40, 590-40, 650-40, 660-40, 730-40}; + vector dx; + for (int k=0;k<8;k++) + dx.push_back(gdi.scaleLength(dx_c[k]));*/ + int ix = 0; + sit = speakerList.begin(); + size_t maxRow = 0; + while (sit != speakerList.end()) { + oSpeakerObject *so = toRender[ix].first = &*sit; + ++sit; + oSpeakerObject *next = sit != speakerList.end() ? &*sit : 0; + int type = 3; + if (so->priority > 0 || (so->status==StatusOK && so->priority>=0)) + type = 1; + else if (so->status == StatusUnknown && so->priority==0) + type = 2; + + renderRowSpeakerList(*toRender[ix].first, next, LeaderTime, type, toRender[ix].second, shortNames); + maxRow = max(maxRow, toRender[ix].second.size()); + ix++; + } + + vector dx_new(maxRow); + for (size_t k = 0; k < toRender.size(); k++) { + const vector &row = toRender[k].second; + for (size_t j = 0; j < row.size(); j++) { + if (!row[j].str.empty()) { + double len = row[j].str.length(); + double factor = 5.6; + if (len < 4) + factor = 7; + else if (len <10) + factor = 5.8; + dx_new[j] = max(28, max(dx_new[j], int(len * factor)+15)); + } + else if (row[j].hasTimer) { + dx_new[j] = max(dx_new[j], 60); + } + } + } + bool rendered; + int limit = gdi.scaleLength(280); + vector dx(maxRow+1); + for (size_t k = 1; k < dx.size(); k++) { + dx[k] = dx[k-1] + min(limit, gdi.scaleLength(dx_new[k-1])); + } + + rendered = false; + for (size_t k = 0; k < toRender.size(); k++) { + oSpeakerObject *so = toRender[k].first; + if (so && (so->priority > 0 || (so->status==StatusOK && so->priority>=0))) { + if (rendered == false) { + gdi.addString("", y, x, boldSmall, "Resultat"); + y+=lh+5, rendered=true; + } + renderRowSpeakerList(gdi, 1, *so, x, y, toRender[k].second, dx); + y+=lh; + toRender[k].first = 0; + } + } + + rendered = false; + for (size_t k = 0; k < toRender.size(); k++) { + oSpeakerObject *so = toRender[k].first; + if (so && so->status == StatusUnknown && so->priority==0) { + if (rendered == false) { + gdi.addString("", y+4, x, boldSmall, "Inkommande"); + y+=lh+5, rendered=true; + } + renderRowSpeakerList(gdi, 2, *so, x, y, toRender[k].second, dx); + y+=lh; + toRender[k].first = 0; + } + } + + rendered = false; + for (size_t k = 0; k < toRender.size(); k++) { + oSpeakerObject *so = toRender[k].first; + if (so) { + if (rendered == false) { + gdi.addString("", y+4, x, boldSmall, "Övriga"); + y+=lh+5, rendered=true; + } + renderRowSpeakerList(gdi, 3, *so, x, y, toRender[k].second, dx); + y+=lh; + toRender[k].first = 0; + } + } + + if (refresh) + gdi.refreshSmartFromSnapshot(false); + else + gdi.refresh(); +} + +void oEvent::updateComputerTime() +{ + SYSTEMTIME st; + GetLocalTime(&st); + computerTime=(((24+2+st.wHour)*3600+st.wMinute*60+st.wSecond-ZeroTime)%(24*3600)-2*3600) * 1000 + st.wMilliseconds; +} + +void oEvent::clearPrewarningSounds() +{ + oFreePunchList::reverse_iterator it; + for (it=punches.rbegin(); it!=punches.rend(); ++it) + it->hasBeenPlayed=true; +} + +void oEvent::tryPrewarningSounds(const string &basedir, int number) +{ + char wave[20]; + sprintf_s(wave, "%d.wav", number); + + string file=basedir+"\\"+wave; + + if (_access(file.c_str(), 0)==-1) + gdibase.alert("Fel: hittar inte filen X.#" + file); + + PlaySound(file.c_str(), 0, SND_SYNC|SND_FILENAME ); +} + +void oEvent::playPrewarningSounds(const string &basedir, set &controls) +{ + oFreePunchList::reverse_iterator it; + for (it=punches.rbegin(); it!=punches.rend() && !it->hasBeenPlayed; ++it) { + + if (controls.count(it->Type)==1 || controls.empty()) { + pRunner r = getRunnerByCardNo(it->CardNo, it->getAdjustedTime()); + + if (r){ + char wave[20]; + sprintf_s(wave, "%d.wav", r->getStartNo()); + + string file=basedir+"\\"+r->getDI().getString("Nationality")+"\\"+wave; + + if (_access(file.c_str(), 0)==-1) + file=basedir+"\\"+wave; + + PlaySound(file.c_str(), 0, SND_SYNC|SND_FILENAME ); + it->hasBeenPlayed=true; + } + } + } +} + +static bool compareFinishTime(pRunner a, pRunner b) { + return a->getFinishTime() < b->getFinishTime(); +} + +struct TimeRunner { + TimeRunner(int t, pRunner r) : time(t), runner(r) {} + int time; + pRunner runner; + bool operator<(const TimeRunner &b) const {return time 0) { + for (int k = 0; k < nt-1; k++) { + if (t == times[k] && times[k+1] < maxtime) + return times[k+1]; + else if (t < times[k] && times[k] < maxtime) + return times[k]; // Will not happen with current implementation of besttime + } + } + return t; + } +}; + +struct PlaceRunner { + PlaceRunner(int p, pRunner r) : place(p), runner(r) {} + int place; + pRunner runner; +}; + +// ClassId -> (Time -> Place, Runner) +typedef multimap TempResultMap; + +void insertResult(TempResultMap &rm, oRunner &r, int time, + int &place, bool &sharedPlace, vector &preRunners) { + TempResultMap::iterator it = rm.insert(make_pair(time, PlaceRunner(0, &r))); + place = 1; + sharedPlace = false; + preRunners.clear(); + + if (it != rm.begin()) { + TempResultMap::iterator p_it = it; + --p_it; + if (p_it->first < it->first) + place = p_it->second.place + 1; + else { + place = p_it->second.place; + sharedPlace = true; + } + int pretime = p_it->first; + while(p_it->first == pretime) { + preRunners.push_back(p_it->second.runner); + if (p_it != rm.begin()) + --p_it; + else + break; + } + } + + TempResultMap::iterator p_it = it; + if ( (++p_it) != rm.end() && p_it->first == time) + sharedPlace = true; + + + int lastplace = place; + int cplace = place; + + // Update remaining + while(it != rm.end()) { + if (time == it->first) + it->second.place = lastplace; + else { + it->second.place = cplace; + lastplace = cplace; + time = it->first; + } + ++cplace; + ++it; + } +} + +int oEvent::setupTimeLineEvents(int currentTime) +{ + if (currentTime == 0) { + updateComputerTime(); + currentTime = getComputerTime(); + } + + int nextKnownEvent = 3600*48; + vector started; + started.reserve(Runners.size()); + timeLineEvents.clear(); + + for(set::iterator it = timelineClasses.begin(); it != timelineClasses.end(); ++it) { + int ne = setupTimeLineEvents(*it, currentTime); + nextKnownEvent = min(ne, nextKnownEvent); + modifiedClasses.erase(*it); + } + return nextKnownEvent; +} + + +int oEvent::setupTimeLineEvents(int classId, int currentTime) +{ + // leg -> started on leg + vector< vector > started; + started.reserve(32); + int nextKnownEvent = 3600*48; + int classSize = 0; + + pClass pc = getClass(classId); + if (!pc) + return nextKnownEvent; + + vector skipLegs; + skipLegs.resize(max(1, pc->getNumStages())); + + for (size_t k = 1; k < skipLegs.size(); k++) { + LegTypes lt = pc->getLegType(k); + if (lt == LTIgnore) { + skipLegs[k] = true; + } + else if (lt == LTParallel || lt == LTParallelOptional) { + StartTypes st = pc->getStartType(k-1); + if (st != STChange) { + // Check that there is no forking + vector &cc1 = pc->MultiCourse[k-1]; + vector &cc2 = pc->MultiCourse[k]; + bool equal = cc1.size() == cc2.size(); + for (size_t j = 0; jId != classId) + continue; + if (r.tStatus == StatusDNS || r.tStatus == StatusNotCompetiting) + continue; +// if (r.CardNo == 0) +// continue; + if (r.tLeg == 0) + classSize++; // Count number of starts on first leg + if (size_t(r.tLeg) < skipLegs.size() && skipLegs[r.tLeg]) + continue; + if (r.tStartTime > 0 && r.tStartTime <= currentTime) { + if (started.size() <= size_t(r.tLeg)) { + started.resize(r.tLeg+1); + started.reserve(Runners.size() / (r.tLeg + 1)); + } + r.tTimeAfter = 0; //Reset time after + r.tInitialTimeAfter = 0; + started[r.tLeg].push_back(&r); + int id = r.tLeg + 100 * r.tStartTime; + ++startTimes[id]; + } + else if (r.tStartTime > currentTime) { + nextKnownEvent = min(r.tStartTime, nextKnownEvent); + } + } + + if (started.empty()) + return nextKnownEvent; + + size_t firstNonEmpty = 0; + while (started[firstNonEmpty].empty()) // Note -- started cannot be empty. + firstNonEmpty++; + + int sLimit = min(4, classSize); + + if (false && startTimes.size() == 1) { + oRunner &r = *started[firstNonEmpty][0]; + + oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, oTimeLine::PHigh, r.getClassId(), 0, 0); + TimeLineIterator it = timeLineEvents.insert(pair(r.tStartTime, tl)); + it->second.setMessage("X har startat.#" + r.getClass()); + } + else { + for (size_t j = 0; j 1) + prio = oTimeLine::PHigh; + else if (p == 1) + prio = oTimeLine::PMedium; + oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, prio, r.getClassId(), r.getId(), &r); + TimeLineIterator it = timeLineEvents.insert(pair(r.tStartTime + 1, tl)); + it->second.setMessage("har startat."); + } + else if (!startedClass) { + // The entire class started + oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, oTimeLine::PHigh, r.getClassId(), 0, 0); + TimeLineIterator it = timeLineEvents.insert(pair(r.tStartTime, tl)); + it->second.setMessage("X har startat.#" + r.getClass()); + startedClass = true; + } + } + } + } + set controlId; + getFreeControls(controlId); + + // Radio controls for each leg, pair is (courseControlId, control) + map > > radioControls; + + for (size_t leg = 0; leggetCourse(false); + if (pc) { + vector< pair > &rc = radioControls[leg]; + for (int j = 0; j < pc->nControls; j++) { + int id = pc->Controls[j]->Id; + if (controlId.count(id) > 0) { + rc.push_back(make_pair(pc->getCourseControlId(j), pc->Controls[j])); + } + } + } + } + } + } + for (size_t leg = 0; leg > &rc = radioControls[leg]; + int nv = setupTimeLineEvents(started[leg], rc, currentTime, leg + 1 == started.size()); + nextKnownEvent = min(nv, nextKnownEvent); + } + return nextKnownEvent; +} + +string getTimeDesc(int t1, int t2); + + +void getTimeAfterDetail(string &detail, int timeAfter, int deltaTime, bool wasAfter) { + string aTimeS = getTimeDesc(timeAfter, 0); + if (timeAfter > 0) { + if (!wasAfter || deltaTime == 0) + detail = "är X efter#" + aTimeS; + else { + string deltaS = getTimeDesc(deltaTime, 0); + if (deltaTime > 0) + detail = "är X efter; har tappat Y#" + aTimeS + "#" + deltaS; + else + detail = "är X efter; har tagit in Y#" + aTimeS + "#" + deltaS; + } + } + else if (timeAfter < 0) { + + if (wasAfter && deltaTime != 0) { + string deltaS = getTimeDesc(deltaTime, 0); + if (deltaTime > 0) + detail = "leder med X; har tappat Y.#" + aTimeS + "#" + deltaS; + else if (deltaTime < 0) + detail = "leder med X; sprang Y snabbare än de jagande.#" + aTimeS + "#" + deltaS; + else + detail = "leder med X#" + aTimeS; + } + } +} + +void oEvent::timeLinePrognose(TempResultMap &results, TimeRunner &tr, int prelT, + int radioNumber, const string &rname, int radioId) { + TempResultMap::iterator place_it = results.lower_bound(prelT); + int p = place_it != results.end() ? place_it->second.place : results.size() + 1; + int prio = tr.runner->getSpeakerPriority(); + + if ((radioNumber == 0 && prio > 0) || (radioNumber > 0 && p <= 10) || (radioNumber > 0 && prio > 0 && p <= 20)) { + string msg; + if (radioNumber > 0) { + if (p == 1) + msg = "väntas till X om någon minut, och kan i så fall ta ledningen.#" + rname; + else + msg = "väntas till X om någon minut, och kan i så fall ta en Y plats.#" + rname + getOrder(p); + } + else + msg = "väntas till X om någon minut.#" + rname; + + oTimeLine::Priority mp = oTimeLine::PMedium; + if (p <= (3 + prio * 3)) + mp = oTimeLine::PHigh; + else if (p>6 + prio * 5) + mp = oTimeLine::PLow; + + oTimeLine tl(tr.time, oTimeLine::TLTExpected, mp, tr.runner->getClassId(), radioId, tr.runner); + TimeLineIterator tlit = timeLineEvents.insert(pair(tl.getTime(), tl)); + tlit->second.setMessage(msg); + } +} + +int oEvent::setupTimeLineEvents(vector &started, const vector< pair > &rc, int currentTime, bool finish) +{ + int nextKnownEvent = 48*3600; + vector< vector > radioResults(rc.size()); + vector bestLegTime(rc.size() + 1); + vector bestTotalTime(rc.size() + 1); + vector bestRaceTime(rc.size()); + + for (size_t j = 0; j < rc.size(); j++) { + int id = rc[j].first; + vector &radio = radioResults[j]; + radio.reserve(started.size()); + for (size_t k = 0; k < started.size(); k++) { + int rt; + oRunner &r = *started[k]; + RunnerStatus rs; + r.getSplitTime(id, rs, rt); + if (rs == StatusOK) + radio.push_back(TimeRunner(rt + r.tStartTime, &r)); + else + radio.push_back(TimeRunner(0, &r)); + + if (rt > 0) { + bestTotalTime[j].addTime(r.getTotalRunningTime(rt + r.tStartTime)); + bestRaceTime[j].addTime(rt); + // Calculate leg time since last radio (or start) + int lt = 0; + if (j == 0) + lt = rt; + else if (radioResults[j-1][k].time>0) + lt = rt + r.tStartTime - radioResults[j-1][k].time; + + if (lt>0) + bestLegTime[j].addTime(lt); + + if (j == rc.size()-1 && r.FinishTime>0 && r.tStatus == StatusOK) { + // Get best total time + bestTotalTime[j+1].addTime(r.getTotalRunningTime(r.FinishTime)); + + // Calculate best time from last radio to finish + int ft = r.FinishTime - (rt + r.tStartTime); + if (ft > 0) + bestLegTime[j+1].addTime(ft); + } + } + } + } + + // Relative speed of a runner + vector relSpeed(started.size(), 1.0); + + // Calculate relative speeds + for (size_t k = 0; k < started.size(); k++) { + size_t j = 0; + int j_radio = -1; + int time = 0; + while(j < rc.size() && (radioResults[j][k].time > 0 || j_radio == -1)) { + if (radioResults[j][k].time > 0) { + j_radio = j; + time = radioResults[j][k].time - radioResults[j][k].runner->tStartTime; + } + j++; + } + + if (j_radio >= 0) { + int reltime = bestRaceTime[j_radio].getBestTime(); + if (reltime == time) + reltime = bestRaceTime[j_radio].getSecondBestTime(); + relSpeed[k] = double(time) / double(reltime); + } + } + + vector< vector > expectedAtNext(rc.size() + 1); + + // Time before expection to "prewarn" + const int pwTime = 60; + + // First radio + int bestLeg = bestLegTime[0].getBestTime(); + if (bestLeg > 0 && bestLeg != BestTime::maxtime){ + vector &radio = radioResults[0]; + vector &expectedRadio = expectedAtNext[0]; + expectedRadio.reserve(radio.size()); + for (size_t k = 0; k < radio.size(); k++) { + oRunner &r = *radio[k].runner; + int expected = r.tStartTime + bestLeg; + int actual = radio[k].time; + if ( (actual == 0 && (expected - pwTime) < currentTime) || (actual > (expected - pwTime)) ) { + expectedRadio.push_back(TimeRunner(expected-pwTime, &r)); + } + } + } + + // Remaining radios and finish + for (size_t j = 0; j < rc.size(); j++) { + bestLeg = bestLegTime[j+1].getBestTime(); + if (bestLeg == 0 || bestLeg == BestTime::maxtime) + continue; + + vector &radio = radioResults[j]; + vector &expectedRadio = expectedAtNext[j+1]; + expectedRadio.reserve(radio.size()); + for (size_t k = 0; k < radio.size(); k++) { + oRunner &r = *radio[k].runner; + if (radio[k].time > 0) { + int expected = radio[k].time + int(bestLeg * relSpeed[k]); + int actual = 0; + if (j + 1 < rc.size()) + actual = radioResults[j+1][k].time; + else + actual = r.FinishTime; + + if ( (actual == 0 && (expected - pwTime) <= currentTime) || (actual > (expected - pwTime)) ) { + expectedRadio.push_back(TimeRunner(expected-pwTime, &r)); + } + else if (actual == 0 && (expected - pwTime) > currentTime) { + nextKnownEvent = min(nextKnownEvent, expected - pwTime); + } + } + } + } + + vector timeAtRadio(rc.size()); + int numbered = 1; + for (size_t j = 0; j < rc.size(); j++) { + + TempResultMap &results = timeAtRadio[j]; + vector &radio = radioResults[j]; + vector &expectedRadio = expectedAtNext[j]; + + string rname;// = ->getRadioName(rc[j].first); + if (rc[j].second->Name.empty()) + rname = lang.tl("radio X#" + itos(numbered++)) + "#"; + else { + if (rc[j].second->tNumberDuplicates > 1) + rname = rc[j].second->Name + "-" + itos(numbered++) + "#"; + else + rname = rc[j].second->Name + "#"; + } + // Sort according to pass time + sort(radio.begin(), radio.end()); + sort(expectedRadio.begin(), expectedRadio.end()); + size_t expIndex = 0; + + for (size_t k = 0; k < radio.size(); k++) { + RunnerStatus ts = radio[k].runner->getTotalStatus(); + if (ts == StatusMP || ts == StatusDQ) + continue; + if (radio[k].time > 0) { + while (expIndex < expectedRadio.size() && expectedRadio[expIndex].time < radio[k].time) { + TimeRunner &tr = expectedRadio[expIndex]; + int prelT = tr.runner->getTotalRunningTime(tr.time + pwTime); + + timeLinePrognose(results, tr, prelT, j, rname, rc[j].first); + expIndex++; + } + + oRunner &r = *radio[k].runner; + int place = 1; + bool sharedPlace = false; + vector preRunners; + int time = radio[k].time - r.tStartTime; + int totTime = r.getTotalRunningTime(radio[k].time); + insertResult(results, r, totTime, place, sharedPlace, preRunners); + int leaderTime = results.begin()->first; + int timeAfter = totTime - leaderTime; + int deltaTime = timeAfter - r.tTimeAfter; + + string timeS = formatTime(time); + string msg, detail; + getTimeAfterDetail(detail, timeAfter, deltaTime, r.tTimeAfter > 0); + r.tTimeAfter = timeAfter; + + if (place == 1) { + if (results.size() == 1) + msg = "är först vid X med tiden Y.#" + rname + timeS; + else if (!sharedPlace) + msg = "tar ledningen vid X med tiden Y.#" + rname + timeS; + else + msg = "går upp i delad ledning vid X med tiden Y.#" + rname + timeS; + } + else { + if (!sharedPlace) { + msg = "stämplar vid X som Y, på tiden Z.#" + + rname + getNumber(place) + + "#" + timeS; + + } + else { + msg = "stämplar vid X som delad Y med tiden Z.#" + rname + getNumber(place) + + "#" + timeS; + } + } + + oTimeLine::Priority mp = oTimeLine::PLow; + if (place <= 2) + mp = oTimeLine::PTop; + else if (place <= 5) + mp = oTimeLine::PHigh; + else if (place <= 10) + mp = oTimeLine::PMedium; + + oTimeLine tl(radio[k].time, oTimeLine::TLTRadio, mp, r.getClassId(), rc[j].first, &r); + TimeLineIterator tlit = timeLineEvents.insert(pair(tl.getTime(), tl)); + tlit->second.setMessage(msg).setDetail(detail); + } + } + } + + TempResultMap results; + sort(started.begin(), started.end(), compareFinishTime); + + string location, locverb, thelocation; + if (finish) { + location = "i mål"; + locverb = "går i mål"; + thelocation = lang.tl("målet") + "#"; + } + else { + location = "vid växeln"; + locverb = "växlar"; + thelocation = lang.tl("växeln") + "#"; + } + + vector &expectedFinish = expectedAtNext.back(); + // Sort according to pass time + sort(expectedFinish.begin(), expectedFinish.end()); + size_t expIndex = 0; + + + for (size_t k = 0; kgetTotalRunningTime(tr.time + pwTime); + timeLinePrognose(results, tr, prelT, 1, thelocation, 0); + expIndex++; + } + + int place = 1; + bool sharedPlace = false; + vector preRunners; + int time = r.getTotalRunningTime(r.FinishTime); + + insertResult(results, r, time, place, sharedPlace, preRunners); + + int leaderTime = results.begin()->first; + int timeAfter = time - leaderTime; + int deltaTime = timeAfter - r.tInitialTimeAfter; + + string timeS = formatTime(time); + + string msg, detail; + getTimeAfterDetail(detail, timeAfter, deltaTime, r.tInitialTimeAfter > 0); + + // Transfer time after to next runner + if (r.tInTeam) { + pRunner next = r.tInTeam->getRunner(r.tLeg + 1); + if (next) { + next->tTimeAfter = timeAfter; + next->tInitialTimeAfter = timeAfter; + } + } + + if (place == 1) { + if (results.size() == 1) + msg = "är först " + location + " med tiden X.#" + timeS; + else if (!sharedPlace) + msg = "tar ledningen med tiden X.#" + timeS; + else + msg = "går upp i delad ledning med tiden X.#" + timeS; + } + else { + if (!sharedPlace) { + if (preRunners.size() == 1 && place < 10) + msg = locverb + " på X plats, efter Y, på tiden Z.#" + + getOrder(place) + + "#" + preRunners[0]->getCompleteIdentification() + + "#" + timeS; + else + msg = locverb + " på X plats med tiden Y.#" + + getOrder(place) + "#" + timeS; + + } + else { + msg = locverb + " på delad X plats med tiden Y.#" + getOrder(place) + + "#" + timeS; + } + } + + oTimeLine::Priority mp = oTimeLine::PLow; + if (place <= 5) + mp = oTimeLine::PTop; + else if (place <= 10) + mp = oTimeLine::PHigh; + else if (place <= 20) + mp = oTimeLine::PMedium; + + oTimeLine tl(r.FinishTime, oTimeLine::TLTFinish, mp, r.getClassId(), r.getId(), &r); + TimeLineIterator tlit = timeLineEvents.insert(pair(tl.getTime(), tl)); + tlit->second.setMessage(msg).setDetail(detail); + } + else if (r.getStatus() != StatusUnknown && r.getStatus() != StatusOK) { + int t = r.FinishTime; + if ( t == 0) + t = r.tStartTime; + + int place = 1000; + if (r.FinishTime > 0) { + place = results.size() + 1; + int rt = r.getTotalRunningTime(r.FinishTime); + if (rt > 0) { + TempResultMap::iterator place_it = results.lower_bound(rt); + place = place_it != results.end() ? place_it->second.place : results.size() + 1; + } + } + oTimeLine::Priority mp = r.getSpeakerPriority() > 0 ? oTimeLine::PMedium : oTimeLine::PLow; + if (place <= 3) + mp = oTimeLine::PTop; + else if (place <= 10) + mp = oTimeLine::PHigh; + else if (place <= 20) + mp = oTimeLine::PMedium; + + oTimeLine tl(r.FinishTime, oTimeLine::TLTFinish, mp, r.getClassId(), r.getId(), &r); + TimeLineIterator tlit = timeLineEvents.insert(pair(t, tl)); + string msg; + if (r.getStatus() != StatusDQ) + msg = "är inte godkänd."; + else + msg = "är diskvalificerad."; + + tlit->second.setMessage(msg); + } + } + return nextKnownEvent; +} + + +void oEvent::renderTimeLineEvents(gdioutput &gdi) const +{ + gdi.fillDown(); + for (TimeLineMap::const_iterator it = timeLineEvents.begin(); it != timeLineEvents.end(); ++it) { + int t = it->second.getTime(); + string msg = t>0 ? getAbsTime(t) : MakeDash("--:--:--"); + oAbstractRunner *r = it->second.getSource(*this); + if (r) { + msg += " (" + r->getClass() + ") "; + msg += r->getName() + ", " + r->getClub(); + } + msg += ", " + lang.tl(it->second.getMessage()); + gdi.addStringUT(0, msg); + } +} + +int oEvent::getTimeLineEvents(const set &classes, vector &events, + set<__int64> &stored, int currentTime) { + if (currentTime == 0) { + updateComputerTime(); + currentTime = getComputerTime(); + } + //OutputDebugString(("GetTimeLine at: " + getAbsTime(getComputerTime()) + "\n").c_str()); + + const int timeWindowSize = 10*60; + int eval = nextTimeLineEvent <= getComputerTime() + 1; + for (set::const_iterator it = classes.begin(); it != classes.end(); ++it) { + if (timelineClasses.count(*it) == 0) { + timelineClasses.insert(*it); + eval = true; + } + if (modifiedClasses.count(*it) != 0) + eval = true; + } + if (eval) { + OutputDebugString("SetupTimeLine\n"); + nextTimeLineEvent = setupTimeLineEvents(currentTime); + } +// else +// OutputDebugString("No change\n"); + + int time = 0; + for (int k = events.size()-1; k>=0; k--) { + int t = events[k].getTime(); + if (t > 0) { + time = t; + break; + } + } + + TimeLineMap::const_iterator it_start = timeLineEvents.lower_bound(time - timeWindowSize); + + bool filter = !events.empty(); + + if (filter) { + for (TimeLineMap::const_iterator it = it_start; it != timeLineEvents.end(); ++it) { + + + } + } + + for (TimeLineMap::const_iterator it = it_start; it != timeLineEvents.end(); ++it) { + if (it->first <= time && it->second.getType() == oTimeLine::TLTExpected) + continue; // Never get old expectations + if (classes.count(it->second.getClassId()) == 0) + continue; + + __int64 tag = it->second.getTag(); + if (stored.count(tag) == 0) { + events.push_back(it->second); + stored.insert(tag); + } + } + + return nextTimeLineEvent; +} + +void oEvent::classChanged(pClass cls, bool punchOnly) { + if (timelineClasses.count(cls->getId()) == 1) { + modifiedClasses.insert(cls->getId()); + timeLineEvents.clear(); + } +} + +static bool orderByTime(const oEvent::ResultEvent &a, const oEvent::ResultEvent &b) { + if (a.classId() != b.classId()) + return a.classId() < b.classId(); // Sort first by class. + return a.time < b.time; +} + +struct LegSetupInfo { + int baseLeg; + int parCount; + bool optional; + + LegSetupInfo():baseLeg(-1), parCount(0), optional(false) {} + LegSetupInfo(int bl, bool opt):baseLeg(bl), parCount(0), optional(opt) {} + +}; + +struct TeamLegControl { + int teamId; + int leg; + int control; + + TeamLegControl() : teamId(0), leg(0), control(0) {} + + TeamLegControl(int id, int leg, int ctrl) : teamId(id), leg(leg), control(ctrl) {} + + bool operator<(const TeamLegControl &tlc) const { + if (teamId != tlc.teamId) + return teamId < tlc.teamId; + else if (leg != tlc.leg) + return leg < tlc.leg; + else + return control < tlc.control; + } +}; + +void oEvent::getResultEvents(const set &classFilter, const set &punchFilter, vector &results) const { + results.clear(); + + vector teamLegStatusOK; + teamLegStatusOK.reserve(Teams.size() * 5); + map teamStatusPos; + for (oTeamList::const_iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (!classFilter.count(it->getClassId())) + continue; + + int base = teamLegStatusOK.size(); + teamStatusPos[it->getId()] = base; + int nr = it->getNumRunners(); + bool ok = it->getStatus() == StatusOK || it->getStatus() == StatusUnknown; + for(int k = 0; k < nr; k++) { + pRunner r = it->getRunner(k); + if (r && r->getStatus() != StatusUnknown && r->getStatus() != StatusOK) + ok = false; + + teamLegStatusOK.push_back(ok ? StatusOK : StatusUnknown); + } + if (!ok) { // A more careful analysis + for(int k = 0; k < nr; k++) { + teamLegStatusOK[base + k] = it->getLegStatus(k, true); + } + } + } + + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + const oRunner &r = *it; + if (r.isRemoved() || !classFilter.count(r.getClassId())) + continue; + if (r.prelStatusOK() || r.getStatus() != StatusUnknown) { + RunnerStatus stat = r.prelStatusOK() ? StatusOK : r.getStatus(); + results.push_back(ResultEvent(pRunner(&r), r.getFinishTime(), oPunch::PunchFinish, stat)); + } + pCard card = r.getCard(); + + RunnerStatus punchStatus = StatusOK; + if (r.tInTeam && r.tLeg > 0) { + map::iterator res = teamStatusPos.find(r.tInTeam->getId()); + if (res != teamStatusPos.end()) { + RunnerStatus prevStat = teamLegStatusOK[res->second + r.tLeg - 1]; + if (prevStat != StatusOK && prevStat != StatusUnknown) { + results.back().status = StatusNotCompetiting; + punchStatus = StatusNotCompetiting; + } + } + } + + if (card) { + oPunchList::const_iterator it; + map dupCount; + for (it = card->punches.begin(); it != card->punches.end(); ++it) { + if (punchFilter.count(it->tMatchControlId)) { + int dupC = ++dupCount[it->tMatchControlId]; + int courseControlId = oControl::getCourseControlIdFromIdIndex(it->tMatchControlId, dupC-1); + results.push_back(ResultEvent(pRunner(&r), it->getAdjustedTime(), courseControlId, punchStatus)); + } + } + } + } + + for (oFreePunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + const oFreePunch &fp = *it; + if (fp.isRemoved() || fp.tRunnerId == 0 || fp.Type == oPunch::PunchCheck || fp.Type == oPunch::PunchStart) + continue; + + pRunner r = getRunner(fp.tRunnerId, 0); + if (r == 0 || !classFilter.count(r->getClassId()) || r->getCard()) + continue; + + int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true); + int ctrl = oControl::getIdIndexFromCourseControlId(courseControlId).first; + + if (!punchFilter.count(ctrl)) + continue; + + results.push_back(ResultEvent(r, fp.Time, courseControlId, StatusOK)); + + if (r->tInTeam && r->tLeg > 0) { + map::iterator res = teamStatusPos.find(r->tInTeam->getId()); + if (res != teamStatusPos.end()) { + RunnerStatus prevStat = teamLegStatusOK[res->second + r->tLeg - 1]; + if (prevStat != StatusOK && prevStat != StatusUnknown) { + results.back().status = StatusNotCompetiting; + } + } + } + } + + for (map, oFreePunch>::const_iterator it = advanceInformationPunches.begin(); + it != advanceInformationPunches.end(); ++it) { + const oFreePunch &fp = it->second; + if (fp.isRemoved() || fp.tRunnerId == 0 || fp.Type == oPunch::PunchCheck || fp.Type == oPunch::PunchStart) + continue; + pRunner r = getRunner(fp.tRunnerId, 0); + if (r == 0 || !classFilter.count(r->getClassId())) + continue; + int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true); + int ctrl = oControl::getIdIndexFromCourseControlId(courseControlId).first; + if (!punchFilter.count(ctrl)) + continue; + + results.push_back(ResultEvent(r, fp.Time, courseControlId, StatusOK)); + + if (r->tInTeam && r->tLeg > 0) { + map::iterator res = teamStatusPos.find(r->tInTeam->getId()); + if (res != teamStatusPos.end()) { + RunnerStatus prevStat = teamLegStatusOK[res->second + r->tLeg - 1]; + if (prevStat != StatusOK && prevStat != StatusUnknown) { + results.back().status = StatusNotCompetiting; + } + } + } + } + + map< int, vector > parLegSetup; + for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (!classFilter.count(it->getId())) + continue; + + int ns = it->getNumStages(); + if (ns == 1) + continue; + + int baseLeg = 0; + for (int i = 0; i < ns; i++) { + bool optional = it->legInfo[i].isOptional(); + bool par = it->legInfo[i].isParallel(); + if (optional || par) { + vector &ls = parLegSetup[it->getId()]; + ls.resize(ns, LegSetupInfo()); + ls[i] = LegSetupInfo(baseLeg, optional); + if (i > 0) + ls[i-1] = ls[i]; + } + else { + baseLeg = i; + } + } + } + + if (parLegSetup.empty()) + return; + + for (map< int, vector >::iterator it = parLegSetup.begin(); + it != parLegSetup.end(); ++it) { + vector &setup = it->second; + size_t sx = -1; + for (size_t k = 0; k < setup.size(); k++) { + if (setup[k].baseLeg == -1) { + if (sx != -1) { + int count = k - sx; + while (sx < k) { + setup[sx++].parCount = count; + } + } + sx = -1; + } + else if (sx == -1) { + sx = k; + } + } + + if (sx != -1) { + int count = setup.size() - sx; + while (sx < setup.size()) { + setup[sx++].parCount = count; + } + } + } + + sort(results.begin(), results.end(), orderByTime); + map countTeamLeg; + + for (size_t k = 0; k < results.size(); k++) { + int clsId = results[k].classId(); + map< int, vector >::iterator res = parLegSetup.find(clsId); + if (res == parLegSetup.end()) + continue; + const vector &setup = res->second; + int leg = results[k].r->getLegNumber(); + if (setup[leg].baseLeg == -1) { + results[k].legNumber = leg; + continue; + } + if (results[k].status != StatusOK) + continue; + results[k].legNumber = setup[leg].baseLeg; + int teamId = results[k].r->getTeam()->getId(); + int val = ++countTeamLeg[TeamLegControl(teamId, setup[leg].baseLeg, results[k].control)]; + + if (setup[leg].optional) { + results[k].partialCount = val - 1; + } + else { + const int numpar = setup[leg].parCount; // XXX Count legs + results[k].partialCount = numpar - val; + } + } +} diff --git a/code/oFreeImport.cpp b/code/oFreeImport.cpp new file mode 100644 index 0000000..274a56f --- /dev/null +++ b/code/oFreeImport.cpp @@ -0,0 +1,1852 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "oFreeImport.h" +#include "oEvent.h" +#include +#include "gdioutput.h" +#include "gdifonts.h" +#include "localizer.h" + +#include "meos_util.h" + +#include "io.h" +#include "fcntl.h" +#include "sys/stat.h" +#include +#include + +void oWordDB::insert(const char *s) +{ + str.insert(s); +} + +bool oWordDB::lookup(const char *s) const +{ + return str.count(s)==1; +} + +const char *oWordDB::deserialize(const char *bf, const char *end) +{ + BYTE s=bf[0]; + bf++; + str.clear(); + for (int k=0;kend) + throw std::exception("Internal error deserializing wordlist."); + + str.insert(n); + } + return bf; +} + +char *oWordDB::serialize(char *bf) const +{ + //Randomize order for better search performace on reload. + BYTE s=BYTE(str.size()); + vector rnd(s); + int k=0; + for (set::const_iterator it=str.begin(); it!=str.end(); ++it) + rnd[k++]=*it; + + bf[0]=s; + bf++; + for (k=0;k::const_iterator it=str.begin(); it!=str.end(); ++it) + s+=it->size()+1; + + return s; +} + +pWordDatabase oWordDB::split() +{ + if (str.size()>=hashSplitSize) { + oWordIndexHash *db=new oWordIndexHash(false); + + set::iterator it; + + for(it=str.begin();it!=str.end();++it) + db->insert(it->c_str()); + + delete this; + return db; + } + else return this; +} + +size_t oWordDB::size() +{ + return str.size(); +} + +void oWordIndexHash::clear() +{ + MapTable::iterator it; + + for(it=unMapped.begin(); it!=unMapped.end(); ++it) + if (it->second) + delete it->second; + + unMapped.clear(); + + for(int k=0;kdeserialize(bf, end); + } + + DWORD i=a-indexMapStart; + if (i<=(indexMapEnd-indexMapStart)) { + if (hashTable[i]) + throw std::exception("Internal error deserilizing wordlist."); + else hashTable[i]=db; + } + else + unMapped[a]=db; + } + return bf; +} + +char *oWordIndexHash::serialize(char *bf) const +{ + int s=unMapped.size(); + for (int k=0;kfirst; + if (bf[0]) { + bf[1]=it->second->getType(); + bf=it->second->serialize(bf+2); + } + else { //Empty string. + bf[1]=0; + bf+=2; + } + } + + for (int k=0;kgetType(); + bf=hashTable[k]->serialize(bf+2); + } + } + return bf; +} + +int oWordIndexHash::serialSize() const +{ + int s=1; + for (int k=0;kserialSize()+2; + } + for(MapTable::const_iterator it=unMapped.begin(); it!=unMapped.end(); ++it) + s+=it->second ? it->second->serialSize()+2: 2; + + return s; +} + +void oWordIndexHash::insert(const char *s) +{ + DWORD i=BYTE(s[0])-indexMapStart; + + if (i<=(indexMapEnd-indexMapStart)) { + if (!hashTable[i]) { + hashTable[i]=new oWordDB(); + hashTable[i]->insert(s+1); + } + else { + hashTable[i]=hashTable[i]->split(); + hashTable[i]->insert(s+1); + } + } + else { + if (s[0]==0) + unMapped[0]=0; //Empty string + else { + MapTable::iterator it=unMapped.find(s[0]); + if (it==unMapped.end()) { + pWordDatabase db(hashAll ? pWordDatabase(new oWordIndexHash(false)): + pWordDatabase(new oWordDB())); + db->insert(s+1); + unMapped[s[0]]=db; + } + else { + if (it->second) { + it->second=it->second->split(); + it->second->insert(s+1); + } + else + assert(s[0]==0); + } + } + } +} + +bool oWordIndexHash::lookup(const char *s) const +{ + DWORD i=BYTE(s[0])-indexMapStart; + + if (i<=(indexMapEnd-indexMapStart)) { + if (!hashTable[i]) + return false; + else + return hashTable[i]->lookup(s+1); + } + else { + MapTable::const_iterator it=unMapped.find(s[0]); + if (it==unMapped.end()) + return false; + else if (s[0]==0) + return true; + else + return it->second->lookup(s+1); + } +} + +oWordIndexHash::oWordIndexHash(bool hashAll_) : hashAll(hashAll_) +{ + for(int k=0;k &serial) const +{ + int s=wh.serialSize(); + serial.resize(s); + wh.serialize(&serial[0]); +} + +void oWordList::deserialize(const vector &serial) +{ + wh.clear(); + wh.deserialize(&serial[0], &serial[0]+serial.size()); +} + +void oWordList::save(const char *file) const +{ + int f=-1; + _sopen_s(&f, file, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, + _SH_DENYWR, _S_IREAD|_S_IWRITE); + + if (f!=-1) { + vector serial; + serialize(serial); + char *hdr="MWDB"; + + _write(f, hdr, 4); + DWORD s=serial.size(); + _write(f, &s, 4); + _write(f, &serial[0], s); + + _close(f); + } + else throw std::exception("Could not save word database."); +} + +void oWordList::load(const char *file) +{ + string ex=string("Bad word database. ")+file; + int f=-1; + _sopen_s(&f, file, _O_BINARY|_O_RDONLY, + _SH_DENYWR, _S_IREAD|_S_IWRITE); + + if (f!=-1) { + char hdr[5]={0,0,0,0,0}; + _read(f, hdr, 4); + + if ( strcmp(hdr, "MWDB")!=0 ) + throw std::exception(ex.c_str()); + + DWORD s=0; + _read(f, &s, 4); + + vector serial(s); + + if (_read(f, &serial[0], s)!=s) + throw std::exception(ex.c_str()); + + _close(f); + + deserialize(serial); + } + else throw std::exception(ex.c_str()); +} + +oFreeImport::oFreeImport(void) +{ + separator[0]=0; + + for(int k=1;k<256;k++) + separator[k]=k<30 ? 1:0; + + separator[' ']=1; + separator[',']=1; + separator[';']=1; + separator['(']=1; + separator[')']=1; + separator['/']=1; + + loaded=false; +} + +oFreeImport::~oFreeImport(void) +{ +} + +char *trim(char *str) +{ + int k=strlen(str)-1; + while(k>=0 && (isspace(BYTE(str[k])) || BYTE(str[k])==BYTE(160))) + str[k--] = 0; + + while(isspace(BYTE(*str)) || BYTE(str[k])==BYTE(160)) + str++; + + return str; +} + +char *oFreeImport::extractPart(char *&str, int &wordCount) const +{ + wordCount=0; + while (separator[*LPBYTE(str)]) + str++; + + if (!*str) + return str; + + char *out=str; + + wordCount=1; + while (*str && (!separator[*LPBYTE(str)] || *str==' ')) { + if (*str==' ') { + while (*++str==' '); + if (separator[*LPBYTE(str)] || !*str) { + if (*str) + *str++=0; + return trim(out); + } + wordCount++; + } + str++; + } + if (*str) + *str++=0; + return trim(out); +} + +char *oFreeImport::extractWord(char *&str, int &count) const +{ + count=0; + while (separator[*str]) + str++; + + if (!*str) + return str; + + char *out=str; + + count=1; + while (*str && !separator[*LPBYTE(str)]) { + count++; + str++; + } + if (*str) + *str++=0; + + return out; +} + +char *oFreeImport::extractLine(char *&str, int &count) const +{ + count=0; + + while (*str=='\n') + str++; + + char *out=str; + + while (*str && *str!='\n') { + str++; + count++; + } + + if (*str) + *str++=0; + + return out; +} + + +oEntryPerson::oEntryPerson(const string &clb) +{ + club = clb; + cardNo=0; +} + +void oEntryPerson::swap() +{ + if (!name1.empty()) + std::swap(name1, name2); +} + +int oEntryPerson::nameCount() const { + if (!name2.empty()) + return countWords(name1.c_str()) + countWords(name2.c_str()); + else + return countWords(name1.c_str()); +} + +void oEntryBlock::clear(const string &rulingClub, const string &rulingClass) +{ + ePersons.clear(); + eClub = rulingClub; + eClass = rulingClass; + eStartTime.clear(); + canInsertName = true; + isClassSet = false; // Count only explicit set class + nClubsSet = rulingClub.empty() ? 0 : 1; +} + +oEntryBlock::oEntryBlock(const oFreeImport &importer) : freeImporter(importer) +{ + canInsertName=true; + nClubsSet = 0; + isClassSet = false; +} + +oEntryBlock::oEntryBlock(const oEntryBlock &eb) : freeImporter(eb.freeImporter) +{ + ePersons = eb.ePersons; + eClub = eb.eClub; + eClass = eb.eClass; + eStartTime = eb.eStartTime; + canInsertName = eb.canInsertName; + isClassSet = eb.isClassSet; + nClubsSet = eb.nClubsSet; +} + +void oEntryBlock::operator=(const oEntryBlock &eb) +{ + ePersons = eb.ePersons; + eClub = eb.eClub; + eClass = eb.eClass; + eStartTime = eb.eStartTime; + canInsertName = eb.canInsertName; + isClassSet = eb.isClassSet; + nClubsSet = eb.nClubsSet; +} + +void oEntryBlock::setClass(const char *s) +{ + eClass=s; + if (!ePersons.empty()) + canInsertName=false; + isClassSet = true; + completeName(); +} + +void oEntryBlock::setClub(const char *s) +{ + eClub = s; + nClubsSet++; + for (size_t k = 0; k=freeImporter.getExpectedNumRunners(eClass)) + canInsertName=false; + + completeName(); +} + +void oEntryBlock::completeName() { + if (!ePersons.empty() && !ePersons.back().name1.empty() + && ePersons.back().name2.empty()) + ePersons.back().name2="*"; +} + +void oEntryBlock::setStartTime(const char *s) +{ + eStartTime=s; + if (!ePersons.empty()) + canInsertName=false; + + completeName(); +} + +void oEntryBlock::setCardNo(int c) +{ + if (ePersons.empty() || ePersons.back().cardNo!=0) + ePersons.push_back(oEntryPerson(eClub)); + + for (size_t i = 0; i < ePersons.size(); i++) { + if (ePersons[i].cardNo == 0) { + ePersons[i].cardNo=c; + break; + } + } + completeName(); +} + +bool oEntryBlock::needCard() const { + if (ePersons.empty()) + return true; + + for (size_t i = 0; i < ePersons.size(); i++) { + if (ePersons[i].cardNo == 0) { + return true; + } + } + return false; +} + +string oEntryBlock::getTeamName() const +{ + set clubs; + if (!eClub.empty()) + clubs.insert(eClub); + for (size_t k = 0; k 1) { + string tname; + for (set::iterator it = clubs.begin(); it != clubs.end(); ++it) { + if (!tname.empty()) + tname += "/"; + tname += *it; + } + return tname; + } + else + return "Lag"; +} + +string oEntryBlock::getName(int k) const +{ + if (size_t(k)>=ePersons.size()) + return "N.N."; + + string n=ePersons[k].name1; + + if (!ePersons[k].name2.empty()) + n+=" "+ePersons[k].name2; + + return n; +} + +string oEntryBlock::getClub(int k) const +{ + if (size_t(k)>=ePersons.size()) + return eClub; + + const string &c=ePersons[k].club; + if (!c.empty()) + return c; + + return eClub; +} + + +int oEntryBlock::getCard(int k) const +{ + if (k oEntryBlock::getPersons() const +{ + vector names; + string n; + char bf[256]; + for (size_t k=0;k0) { + sprintf_s(bf, " (%d)", ePersons[k].cardNo); + n+=bf; + } + + + names.push_back(n); + n.clear(); + } + return names; +} + +int oEntryBlock::nameCount() +{ + if (ePersons.empty()) + return 0; + int space=0; + const string &name1=ePersons.back().name1; + const string &name2=ePersons.back().name2; + + if (!name1.empty()) { + space++; + for (size_t k=0;k=2 && countWords(s)>=2) + completeName(); + + if (complete) { + if (!ePersons.back().name1.empty()) + ePersons.push_back(oEntryPerson(eClub)); + + ePersons.back().name1=s; + } + else { + if (ePersons.back().name1.empty()) + ePersons.back().name1=s; + else if (ePersons.back().name2.empty()) + ePersons.back().name2=s; + else { + ePersons.push_back(oEntryPerson(eClub)); + ePersons.back().name1=s; + } + } +} + +bool oEntryBlock::acceptMoreClubs(int expectedNumRunners) const +{ + return nClubsSet < int(ePersons.size()) || + nClubsSet < expectedNumRunners; +} + +bool oEntryBlock::expectMoreNames(int expectedNumRunners) const +{ + return int(ePersons.size()) < expectedNumRunners || + (expectedNumRunners == ePersons.size() && + ePersons.back().nameCount()<=1); +} + + +void oEntryBlock::cleanEntry() +{ + for (size_t k=0;k &b, int &offset, int &delta) const +{ + vector d; + d.reserve(b.size()/3); + + for (size_t k=0;k1) { + int x=offset; + while(unsigned(x)=1000 && k<10000000); +} + +bool oFreeImport::isTime(const string &m) const +{ + if (m.empty() || m.length()>9) + return false; + + for(size_t k=0;k23) + return false; + + int minute=0; + int second=0; + int kp=m.find_first_of(':'); + + if (kp>0) { + string mtext=m.substr(kp+1); + minute=atoi(mtext.c_str()); + + if (minute<0 || minute>60) + return false; + + kp=mtext.find_last_of(':'); + + if (kp>0) { + second=atoi(mtext.substr(kp+1).c_str()); + if (second<0 || second>60) + return false; + } + } + int t=hour*3600+minute*60+second; + if (t<=0) + return false; + + return true; +} + +bool oFreeImport::isCrap(const char *p) const +{ + int s=strlen(p); + + for (int k=0;k='0' && p[k]<='9')) + return true; + } + return false; +} + +bool oFreeImport::isName(const char *p) const +{ + char bf[1024]; + strcpy_s(bf, p); + char *str=bf; + int c=1; + vector w; + + while(c>0) { + const char *out= extractWord(str,c); + if (c>0) + w.push_back(out); + } + if (w.size()==1) + return familyDB.lookup(w[0]) || givenDB.lookup(w[0]); + else if (w.size()<4) { + int n=0; + int t=(w.size()+1)/2; + for (size_t k=0;k=t; + } + + return false; +} + +void oFreeImport::analyzePart(char *part, const MatchPattern &ptrn, int nNamesPerPart, + oEntryBlock &entry, vector &entries, bool allowName) +{ + vector words; + int count=1; + + while (count>0) { + const char *out=extractWord(part, count); + if (count>0) + words.push_back(out); + } + + allowName &= !entry.hasName() || nNamesPerPart!=1; + + vector isNameV(words.size(), false); + vector isClub(words.size(), false); + vector isClass(words.size(), false); + vector isCardV(words.size(), false); + vector isTimeV(words.size(), false); + vector used(words.size(), false); + + int names=0; + int classes=0; + int clubs=0; + int cards=0; + int times=0; + + for (size_t j=0;j0 && (clubs+classes+cards+times)<1) { + if (!entry.canInsertName) { + entry.cleanEntry(); + entries.push_back(entry); + entry.clear(rulingClub, rulingClass); + } + string n; + for (size_t j=0;j0 && !entry.expectMoreNames(getExpectedNumRunners(entry.eClass)) + && !allowName) + lastType = Club; //Guess club + + for (size_t k=0;k2); + lastInsertedType = Name; + } +} + +void oFreeImport::test(const oRunnerList &li) +{ + oRunnerList::const_iterator it; + //classDB.insert("H21"); + //classDB.insert("Herrar"); + + for(it=li.begin();it!=li.end();++it) { + givenDB.insert(it->getGivenName().c_str()); + familyDB.insert(it->getFamilyName().c_str()); + clubDB.insert(it->getClub().c_str()); + classDB.insert(it->getClass().c_str()); + } + + + string b("0"), c("a2"), d("a"); + + const int end='z'+5; + for(int k='a';k<=end+1;k++) + if (k>end) + givenDB.insert(b.c_str()); + else { + string z=b+char(k); + for( int j='a';j<=end+1;j++) { + if (j>end) + givenDB.insert(z.c_str()); + else { + givenDB.insert( (z+char(j)+d).c_str() ); + } + } + } + + givenDB.save("test.mwd"); + oWordList wl; + wl.load("test.mwd"); + wl.save("test2.mwd"); + for(it=li.begin();it!=li.end();++it) + givenDB.insert(it->getGivenName().c_str()); + + wl.save("test3.mwd"); + //char bf[256]=" Erik Melin , 37837, OK Linné , H21\nJan Troeng, 54323, OK Linné, H21\nLinna Willdén, 810230,IF Thor,D21"; + //vector entries; + //extractEntries(bf, entries); +} + +/** Must not return 0 */ +int oFreeImport::getExpectedNumRunners(const string &cls) const +{ + string key(canonizeName(cls.c_str())); + map::const_iterator it = runnersPerClass.find(key); + + if (it != runnersPerClass.end()) + return it->second; + else + return 1; +} + +void oFreeImport::init(const oRunnerList &r, const oClubList &clb, const oClassList &cls) +{ + runnersPerClass.clear(); + vector split_vector; + string sep(" "); + + for(oRunnerList::const_iterator it=r.begin();it!=r.end();++it) { + givenDB.insert(it->getGivenName().c_str()); + string f=it->getFamilyName(); + familyDB.insert(f.c_str()); + + split(f, sep, split_vector); + if (split_vector.size()>1) + for(size_t k=0;kgetName().c_str()); + split(it->getName().c_str(), sep, split_vector); + if (split_vector.size()>1) + for(size_t k=0;kgetName().c_str()); + split(it->getName().c_str(), sep, split_vector); + if (split_vector.size()>1) + for(size_t k=0;kgetNumDistinctRunners(); + string key(canonizeName(it->getName().c_str())); + runnersPerClass[key] = numrunner; + } + + const char *clsPrefix[8] = {"h", "d", "m", "w", + "herrar", "damer", "men", "women"}; + + char bf[64]; + + vector ages; + + for (int k=10;k<=16;k++) + ages.push_back(k); + ages.push_back(18); + ages.push_back(20); + ages.push_back(21); + for (int k=35;k<=100;k+=5) + ages.push_back(k); + + for (int k=0;k<8;k++) { + classDB.insert(clsPrefix[k]); + + for (size_t j=0; j=18 && ages[j]<=21) { + sprintf_s(bf, "%s %dE", clsPrefix[k], ages[j]); + classDB.insert(bf); + sprintf_s(bf, "%s %d Elit", clsPrefix[k], ages[j]); + classDB.insert(bf); + sprintf_s(bf, "%s%dE", clsPrefix[k], ages[j]); + classDB.insert(bf); + sprintf_s(bf, "%s%d Elit", clsPrefix[k], ages[j]); + classDB.insert(bf); + } + } + } + classDB.insert("L"); + classDB.insert("Lång"); + classDB.insert("E"); + classDB.insert("Elit"); + classDB.insert("Elite"); + classDB.insert("Adult"); + classDB.insert("Vuxen"); + classDB.insert("Insk"); + classDB.insert("Insk."); + classDB.insert("Inskolning"); + classDB.insert("M"); + classDB.insert("ÖM"); + classDB.insert("Motion"); + classDB.insert("K"); + classDB.insert("Kort"); + classDB.insert("Mellan"); + classDB.insert("Svår"); + classDB.insert("Lätt"); + classDB.insert("Kortlätt"); + classDB.insert("Långsvår"); + classDB.insert("km"); + classDB.insert("Short"); + classDB.insert("Long"); + classDB.insert("Öppen"); + classDB.insert("Ö"); + classDB.insert("Ungdom"); + classDB.insert("Ung."); + classDB.insert("U"); + classDB.insert("U1"); + classDB.insert("U2"); + classDB.insert("U3"); + classDB.insert("U4"); + + for (int j=1;j<10;j++) { + sprintf_s(bf, "Ö%d", j); + classDB.insert(bf); + sprintf_s(bf, "Ö %d", j); + classDB.insert(bf); + sprintf_s(bf, "Öppen %d", j); + classDB.insert(bf); + sprintf_s(bf, "D%d", j); + classDB.insert(bf); + sprintf_s(bf, "Direkt %d", j); + classDB.insert(bf); + } +} + +bool oFreeImport::isHeaderWord(const string &word) const { + if (headerWords.empty()) { + headerWords.insert(canonizeName("namn")); + headerWords.insert(canonizeName("klass")); + headerWords.insert(canonizeName("ålder")); + headerWords.insert(canonizeName("anmälda")); + headerWords.insert(canonizeName("anmälningar")); + headerWords.insert(canonizeName("deltagare")); + headerWords.insert(canonizeName("löpare")); + headerWords.insert(canonizeName("bricka")); + headerWords.insert(canonizeName("starttid")); + headerWords.insert(canonizeName("nummer")); + headerWords.insert(canonizeName("startnummer")); + headerWords.insert(canonizeName("bricknummer")); + headerWords.insert(canonizeName("nummer")); + headerWords.insert(canonizeName("klubb")); + headerWords.insert(canonizeName("klassnamn")); + headerWords.insert(canonizeName("pinne")); + headerWords.insert(canonizeName("nummerlapp")); + headerWords.insert(canonizeName("SI")); + headerWords.insert(canonizeName("förening")); + headerWords.insert(canonizeName("rank")); + headerWords.insert(canonizeName("ranking")); + headerWords.insert(canonizeName("nr-lapp")); + headerWords.insert(canonizeName("tid")); + + headerWords.insert(canonizeName("name")); + headerWords.insert(canonizeName("age")); + headerWords.insert(canonizeName("class")); + headerWords.insert(canonizeName("start")); + headerWords.insert(canonizeName("time")); + headerWords.insert(canonizeName("club")); + headerWords.insert(canonizeName("card")); + } + return headerWords.count(canonizeName(word.c_str()))>0; +} + +bool match_char(char c, const string &sep) { + for (size_t j = 0; j &line) const +{ + if (line.empty()) + return true; + + int header = 0; + int nonheader = 0; + bool forceNoHeader = false; + vector firstWord; + const string separators = " :,.="; + for (size_t k = 0; k < line.size(); k++) { + vector words; + split(line[k], separators, words); + if (words.empty()) + firstWord.push_back(""); + else + firstWord.push_back(words.front()); + + for (size_t j = 0; j < words.size(); j++) { + if (words[j].empty()) + continue; + if (isHeaderWord(words[j]) ) + header++; + else { + nonheader++; + // If the header contains a real name, class or club, do not reject + if (isName(words[j].c_str())) + forceNoHeader = true; + + if (classDB.lookup(words[j].c_str())) + forceNoHeader = true; + if (clubDB.lookup(words[j].c_str()) || clubDB.lookup(line[k])) + forceNoHeader = true; + } + } + } + + if (!forceNoHeader && header > nonheader) + return true; + + // Remove header words + for (size_t k = line.size()-1; k < line.size(); k--) { + if (isHeaderWord(line[k])) { + line.erase(line.begin()+k); + } + else if (isHeaderWord(firstWord[k])) { + line[k] += firstWord[k].size(); + int j = 0; + while (line[k][j] && match_char(line[k][j], separators)) + j++; + line[k] += j; + } + } + return false; +} + +const int CLEARROW = 1; +const int IGNOREROW = 2; +const int COMPLETEROW = 4; + +int oFreeImport::preAnalyzeRow(vector &p, + const vector &ptrn, + vector &classified) +{ + int stat = 0; + + int names = 0; + int clubs = 0; + int cards = 0; + int classes = 0; + int unknown = 0; + + for (size_t j=0;j1) { + if (ptrn[j].isClub()) + type=0; + else if (ptrn[j].isClass()) + type=1; + else if (ptrn[j].isCard() && atoi(p[j])>0) + type=3; + } + + classified.push_back(type); + if (type == 1) + classes++; + else if (type==3) + cards++; + else if (type==4) + names++; + else if (type==0) + clubs++; + else + unknown++; + + const char *canP = canonizeName(p[j]); + if (strcmp(canP, "vakant")==0 || strcmp(canP, "vacant")==0) + stat|=IGNOREROW; + } + + if (clubs>0 && names>0 && cards>0) + stat|=COMPLETEROW; + + if (p.size()==1 && (classes>0 || clubs>0)) + stat|=CLEARROW; + + while (cards > names && names>0) { + int idx = -1; + for (size_t k = 0; k=0 ? atoi(p[idx]) : -1; + if (a==-1) + idx = k; + else { + int b = atoi(p[k]); + if (b>0 && b=0) { + classified[idx] = -2; + cards--; + unknown++; + } + } + + for (int k = p.size()-1; k>=0;k--) { + if (classified[k] == -2) { + classified.erase(classified.begin()+k); + p.erase(p.begin()+k); + } + } + return stat; +} + + +void oFreeImport::extractEntries(char *str, vector &entries) +{ + entries.clear(); + + vector< vector > parts; + parts.reserve(strlen(str)/24); + set lineTypes; + int count=1; + + while(count>0) { + char *line=extractLine(str, count); + + if (count>0) { + parts.push_back( vector() ); + + while(count>0) { + char *out=extractPart(line, count); + if (count>0) + parts.back().push_back(out); + } + if ( analyzeHeaders(parts.back()) ) { + parts.pop_back(); + count = 1; + } + else { + lineTypes.insert(parts.back().size()); + count=1; + } + } + + } + + map > patterns; + map nNames; //Number of name entries per pattern + //Analyze line types + for(set::iterator it=lineTypes.begin(); + it!=lineTypes.end();++it) { + vector mp(*it); + int limit=0; + for (size_t k=0;k &p=parts[k]; + for (int j=0;j<*it; j++) { + if (classDB.lookup(p[j])) + mp[j].nClass++; + if (clubDB.lookup(p[j])) + mp[j].nClub++; + if (isName(p[j])) { + mp[j].nName++; + if (countWords(p[j])==1) + mp[j].singleName++; + } + if (isCard(p[j])) + mp[j].nCard++; + if (isTime(p[j])) + mp[j].nTime++; + } + } + } + + if (limit==1) + limit=0; + else if (limit<=3) + limit=1; + else if (limit<=10) + limit=2; + else + limit=limit/5; + + int nn=0; + + for (size_t k=0;k=mp.size() || !mp[k+1].isName(limit)) && + (k==0 || !mp[k-1].isName(limit)) ) { + mp[k].singleName=false; + } + + nNames[*it]=nn; + swap(patterns[*it], mp); + } + + entries.reserve(parts.size()); + oEntryBlock entry(*this); + + vector words; + rulingClub = ""; + rulingClass = ""; + lastInsertedType = None; + for (size_t k=0;k &p=parts[k]; + + vector classified; + int res = preAnalyzeRow(p, patterns[p.size()], classified); + + int s = p.size(); + vector &ptrn=patterns[s]; + + if (ptrn.empty()) + ptrn.resize(s); + assert(ptrn.size() == s); + + lastInsertedType = None; + if (res & CLEARROW) { + entry.cleanEntry(); + if (entry.hasName()) { + entries.push_back(entry); + } + entry.clear(rulingClub, rulingClass); + } + else if (res & COMPLETEROW) { + entry.cleanEntry(); + if (entry.hasName()) { + entries.push_back(entry); + } + entry.clear(rulingClub, rulingClass); + } + if (res & IGNOREROW) + continue; + + for (int j=0;j1) { + if (ptrn[j].isClub()) + type = Club; + else if (ptrn[j].isClass()) + type = Class; + else if (ptrn[j].isCard() && atoi(p[j])>0) + type = Card; + } + + //We have a suggested name, but there should only + //be one name and we already got one. + if ((type == Name && entry.hasName() && (2*nNames[s])<=readNames)) + type = Unknown; + + if (type==Name && isCrap(p[j])) + type = Unknown; + + if (type == Unknown) + analyzePart(p[j], ptrn[j], nNames[s], entry, + entries, (2*nNames[s])>readNames); + else if (type == Club) { + bool moreClubs = entry.acceptMoreClubs(getExpectedNumRunners(entry.eClass)); + if (!moreClubs && lastInsertedType == Club) + continue; + + if (!moreClubs && entry.hasName()) { + readNames=0; + entry.cleanEntry(); + entries.push_back(entry); + entry.clear(rulingClub, rulingClass); + } + else if (j<=1 && s<=2) + // Set a ruling club if it first on a line containing at most 2 parts. (We allow club+class) + rulingClub = p[j]; + + lastInsertedType = Club; + entry.setClub(p[j]); + // If we have an odd number of names read + // we were expecting a completing name, + // but none came, so we complete what we have instead. + if (readNames&1) { + readNames++; + entry.completeName(); + } + } + else if (type == Class) { + if (lastInsertedType == Class) + continue; + + if (entry.hasClass() && entry.hasName()) { + readNames=0; + entry.cleanEntry(); + entries.push_back(entry); + entry.clear(rulingClub, rulingClass); + } + else if (j<=1 && s<=2) + // Set a ruling class if it first on a line containing at most 2 parts. (We allow club+class) + rulingClass = p[j]; + + lastInsertedType = Class; + entry.setClass(p[j]); + if (readNames&1) { + readNames++; + entry.completeName(); + } + } + else if (type == Time) { + if (lastInsertedType == Time) + continue; + + if (!entry.eStartTime.empty()) { + if (entry.ePersons.size()>1 && !entry.hasName()) + entry.ePersons.pop_back(); //Warning + + if (entry.hasName()) { + readNames=0; + entry.cleanEntry(); + entries.push_back(entry); + entry.clear(rulingClub, rulingClass); + } + } + lastInsertedType = Time; + entry.setStartTime(p[j]); + if (readNames&1) { + readNames++; + entry.completeName(); + } + } + else if (type == Card) { + if (lastInsertedType == Card && !entry.needCard()) + continue; + + lastInsertedType = Card; + entry.setCardNo(atoi(p[j])); + if (readNames&1) { + readNames++; + entry.completeName(); + } + } + else if (type == Name) { + lastInsertedType = Name; + bool complete = ptrn[j].isCompleteName(); + entry.addPerson(p[j], complete); + readNames += complete ? 2:1; + } + }// End loop over parts + + if (entry.hasName()) { + entry.cleanEntry(); + entries.push_back(entry); + entry.clear(rulingClub, rulingClass); + } + else if (res & COMPLETEROW) { + entry.cleanEntry(); + if (entry.hasName()) + entries.push_back(entry); // Else lost data + entry.clear(rulingClub, rulingClass); + } + } + + for (size_t k=1;k=0; k--) { + if (entries[k].eClub.empty()) + entries[k].eClub=entries[k+1].eClub; + + if (entries[k].eClass.empty()) + entries[k].eClass=entries[k+1].eClass; + } +} + +void oFreeImport::showEntries(gdioutput &gdi, const vector &entries) +{ + gdi.setCX(20); + for (size_t k=0;k names = entries[k].getPersons(); + for (size_t j=0;j &entries) +{ + map teamno; //For automatic name generation Club/Class + for (size_t k=0;kgetClass(entries[k].eClass); + + if (!pc) { + pc=oe->addClass(entries[k].eClass); + if (entries[k].getNumPersons()>1) + pc->setNumStages(entries[k].getNumPersons()); + pc->synchronize(); + } + + if (pc) { + int nr=pc->getNumDistinctRunners(); + if (nr==1) { + pRunner r=oe->addRunner(entries[k].getName(0), + entries[k].getClub(0), pc->getId(), + entries[k].getCard(0), 0, true); + + r->setStartTimeS(entries[k].eStartTime); + r->setCardNo(entries[k].getCard(0), false); + + r->addClassDefaultFee(false); + r->synchronize(); + } + else { + pClub club=oe->getClubCreate(0, entries[k].eClub); + string team = entries[k].getTeamName(); + //int id=pc->getId() + 10000 * (club ? club->getId() : 0); + + //char tname[256]; + //sprintf_s(tname, "%s %d", entries[k].eClub.c_str(), ++teamno[id]); + pTeam t=oe->addTeam(team, club ? club->getId() : 0, pc->getId()); + if (t) { + t->setStartNo(t->getId(), false); + + for (int j=0;jaddRunner(entries[k].getName(j), entries[k].getClub(j), + pc->getId(), entries[k].getCard(j), 0, false); + r->setCardNo(entries[k].getCard(j), false); + r->addClassDefaultFee(false); + t->setRunner(j, r, true); + } + + t->apply(true, 0, false); + } + } + } + } + oe->makeUniqueTeamNames(); +} + +void oFreeImport::load() +{ + char bf[260]; + bool warn=false; + getUserFile(bf, "family.mwd"); + try { + familyDB.load(bf); + } catch(std::exception &) {warn=true;} + getUserFile(bf, "given.mwd"); + try { + givenDB.load(bf); + } catch(std::exception &) {warn=true;} + getUserFile(bf, "club.mwd"); + try { + clubDB.load(bf); + } catch(std::exception &) {warn=true;} + getUserFile(bf, "class.mwd"); + try { + classDB.load(bf); + } catch(std::exception &) {warn=true;} + + loaded=true; +} + +void oFreeImport::save() const +{ + char bf[260]; + string bu; + getUserFile(bf, "family.mwd"); + bu=string(bf)+".old"; + remove(bu.c_str()); + rename(bf, bu.c_str()); + familyDB.save(bf); + getUserFile(bf, "given.mwd"); + bu=string(bf)+".old"; + remove(bu.c_str()); + rename(bf, bu.c_str()); + givenDB.save(bf); + getUserFile(bf, "club.mwd"); + bu=string(bf)+".old"; + remove(bu.c_str()); + rename(bf, bu.c_str()); + clubDB.save(bf); + getUserFile(bf, "class.mwd"); + bu=string(bf)+".old"; + remove(bu.c_str()); + rename(bf, bu.c_str()); + classDB.save(bf); +} diff --git a/code/oFreeImport.h b/code/oFreeImport.h new file mode 100644 index 0000000..85c017b --- /dev/null +++ b/code/oFreeImport.h @@ -0,0 +1,255 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include +#include + +#include "oEvent.h" + +class oWordDatabase; +typedef oWordDatabase* pWordDatabase; +typedef map MapTable; + +const char indexMapStart='a'; +const char indexMapEnd='z'; +const int hashSplitSize=16; +const int hashTableSize=indexMapEnd-indexMapStart+1; + + +class oFreeImport; + +class oWordDatabase { +public: + virtual char getType() const = 0; + virtual const char *deserialize(const char *bf, const char *end) = 0; + virtual char *serialize(char *bf) const = 0; + virtual int serialSize() const = 0; + virtual pWordDatabase split() {return this;} + virtual void insert(const char *s) = 0; + virtual bool lookup(const char *s) const = 0; + virtual ~oWordDatabase() = 0 {} +}; + +class oWordDB : public oWordDatabase { +protected: + char getType() const {return 1;} + set str; +public: + const char *deserialize(const char *bf, const char *end); + char *serialize(char *bf) const; + int serialSize() const; + pWordDatabase split(); + void insert(const char *s); + bool lookup(const char *s) const; + size_t size(); +}; + + +class oWordIndexHash : public oWordDatabase { +protected: + char getType() const {return 2;} + pWordDatabase hashTable[hashTableSize]; + MapTable unMapped; + bool hashAll; +public: + const char *deserialize(const char *bf, const char *end); + char *serialize(char *bf) const; + int serialSize() const; + void insert(const char *s); + bool lookup(const char *s) const; + void clear(); + ~oWordIndexHash(); + oWordIndexHash(bool hashAll_); +}; + +class oWordList { +protected: + oWordIndexHash wh; +public: + void serialize(vector &serial) const; + void deserialize(const vector &serial); + + void save(const char *file) const; + void load(const char *file); + + void insert(const char *s); + bool lookup(const char *s) const; + ~oWordList(); + oWordList(); +}; + +struct oEntryPerson { + string name1; + string name2; + string club; + int cardNo; + void swap(); + int nameCount() const; + oEntryPerson(const string &clb); +}; + +struct oEntryBlock { + // Remember clear for additional data + vector ePersons; + string eClub; + string eClass; + bool isClassSet; + string eStartTime; + bool canInsertName; + int nClubsSet; + const oFreeImport &freeImporter; + + int nameCount(); + + void setClub(const char *s); + void setClass(const char *s); + void setCardNo(int c); + void setStartTime(const char *s); + void addPerson(const char *s, bool complete); + vector getPersons() const; + void clear(const string &rulingClub, const string &rulingClass); + + // Return true if more clubs can be accepted + bool acceptMoreClubs(int expectedNumRunners) const; + + bool expectMoreNames(int expectedNumRunners) const; + bool needCard() const; + bool hasClub() const {return !eClub.empty();} + /** Return true if class explicitly set. May have a ruling class anyway*/ + bool hasClass() const {return isClassSet;} + bool hasStartTime() const {return !eStartTime.empty();} + bool hasName() {return !ePersons.empty() && + !ePersons.front().name1.empty();} + void cleanEntry(); //Remove bad data. + oEntryBlock(const oFreeImport &importer); + oEntryBlock(const oEntryBlock &eb); + void operator=(const oEntryBlock &eb); + int getNumPersons() const {return ePersons.size();} + + string getTeamName() const; + string getName(int k) const; + string getClub(int k) const; + int getCard(int k) const; + + /** Make name complete */ + void completeName(); +}; + +struct MatchPattern { + short nName; + short singleName; + short nClass; + short nClub; + short nTime; + short nCard; + + bool isClass(int level=2) const {return nClass>(nClub+nTime+nCard)+level;} + bool isClub(int level=2) const {return nClub>(nClass+nTime+nCard)+level;} + bool isTime(int level=2) const {return nTime>(nClass+nClub+nCard)+level;} + bool isCard(int level=2) const {return nCard>(nClass+nTime+nTime)+level;} + bool isName(int level=2) const {return nName>(nCard+nClass+nTime+nClub)+level;} + bool isCompleteName() const {return singleName &entries, bool allowNames); + + //bool analyze(vector &b, int &offset, int &delta) const; + char *extractWord(char *&str, int &count) const; + char *extractPart(char *&str, int &wordCount) const; + char *extractLine(char *&str, int &count) const; + bool isNumber(const char *str, int &number) const; + + bool isTime(const string &m) const; + bool isName(const char *p) const; + bool isCard(const char *p) const; + bool isCrap(const char *p) const; + + bool loaded; + + int preAnalyzeRow(vector &p, + const vector &ptrn, + vector &classified); + + // Runners per class in defined classes + map runnersPerClass; + + /** Must not return 0 */ + int getExpectedNumRunners(const string &cls) const; + friend struct oEntryBlock; + + /** Check if a line is a header and remove header words, + name: , class: etc. Returns true if the entire line + is header (->ignore) */ + bool analyzeHeaders(vector &line) const; + + /** Returns true if the given word is a header word */ + bool isHeaderWord(const string &word) const; + + mutable set headerWords; + + // Expected club for all entries + string rulingClub; + string rulingClass; + Types lastInsertedType; +public: + void load(); + bool isLoaded() const {return loaded;} + void save() const; + + void init(const oRunnerList &r, const oClubList &clb, const oClassList &cls); + + void extractEntries(char *bf, vector &entries); + void showEntries(gdioutput &gdi, const vector &entries); + void addEntries(pEvent oe, const vector &entries); + + void test(const oRunnerList &li); + oFreeImport(void); + ~oFreeImport(void); + + friend class oEvent; +}; diff --git a/code/oFreePunch.cpp b/code/oFreePunch.cpp new file mode 100644 index 0000000..4327ac3 --- /dev/null +++ b/code/oFreePunch.cpp @@ -0,0 +1,720 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include +#include + +#include "oFreePunch.h" +#include "oEvent.h" +#include "Table.h" +#include "meos_util.h" +#include "Localizer.h" +#include "intkeymapimpl.hpp" +#include "socket.h" +#include "meosdb/sqltypes.h" +#include "gdioutput.h" + +bool oFreePunch::disableHashing = false; + +oFreePunch::oFreePunch(oEvent *poe, int card, int time, int type): oPunch(poe) +{ + Id=oe->getFreePunchId(); + CardNo = card; + Time = time; + Type = type; + iHashType = 0; + tRunnerId = 0; +} + +oFreePunch::oFreePunch(oEvent *poe, int id): oPunch(poe) +{ + Id=id; + oe->qFreePunchId = max(id, oe->qFreePunchId); + iHashType = 0; + tRunnerId = 0; +} + +oFreePunch::~oFreePunch(void) +{ +} + +bool oFreePunch::Write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Punch"); + xml.write("CardNo", CardNo); + xml.write("Time", Time); + xml.write("Type", Type); + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.endTag(); + + return true; +} + +void oFreePunch::Set(const xmlobject *xo) +{ + xmlList xl; + xo->getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("CardNo")){ + CardNo=it->getInt(); + } + if (it->is("Type")){ + Type=it->getInt(); + } + if (it->is("Time")){ + Time=it->getInt(); + } + else if (it->is("Id")){ + Id=it->getInt(); + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + } +} + +bool oFreePunch::setCardNo(int cno, bool databaseUpdate) { + if (cno != CardNo) { + pRunner r1 = oe->getRunner(tRunnerId, 0); + int oldControlId = tMatchControlId; + //oe->punchIndex[itype].remove(CardNo); // Remove from index + // Remove ourself from index + oEvent::PunchIndexType &pi = oe->punchIndex[iHashType]; + oEvent::PunchConstIterator it = pi.find(CardNo); + while (it != pi.end() && it->first == CardNo) { + if (it->second == this) { + pi.erase(it); + break; + } + ++it; + } + oe->removeFromPunchHash(CardNo, Type, Time); + rehashPunches(*oe, CardNo, 0); + + CardNo = cno; + oe->insertIntoPunchHash(CardNo, Type, Time); + + rehashPunches(*oe, CardNo, this); + pRunner r2 = oe->getRunner(tRunnerId, 0); + + if (r1 && oldControlId > 0) + r1->markClassChanged(oldControlId); + if (r2 && iHashType > 0) + r2->markClassChanged(tMatchControlId); + + if (!databaseUpdate) + updateChanged(); + + return true; + } + return false; +} + +void oFreePunch::remove() +{ + if (oe) + oe->removeFreePunch(Id); +} + +bool oFreePunch::canRemove() const +{ + return true; +} + +Table *oEvent::getPunchesTB()//Table mode +{ + if (tables.count("punch") == 0) { + Table *table=new Table(this, 20, "Stämplingar", "punches"); + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 150, false); + table->addColumn("Bricka", 70, true); + table->addColumn("Kontroll", 70, true); + table->addColumn("Tid", 70, false); + table->addColumn("Löpare", 170, false); + table->addColumn("Lag", 170, false); + tables["punch"] = table; + table->addOwnership(); + } + + tables["punch"]->update(); + return tables["punch"]; +} + +void oEvent::generatePunchTableData(Table &table, oFreePunch *addPunch) +{ + if (addPunch) { + addPunch->addTableRow(table); + return; + } + + synchronizeList(oLPunchId); + oFreePunchList::iterator it; + oe->setupCardHash(false); + table.reserve(punches.size()); + for (it = punches.begin(); it != punches.end(); ++it){ + if (!it->isRemoved()){ + it->addTableRow(table); + } + } + oe->setupCardHash(true); +} + +void oFreePunch::addTableRow(Table &table) const { + oFreePunch &it = *pFreePunch(this); + table.addRow(getId(), &it); + int row = 0; + table.set(row++, it, TID_ID, itos(getId()), false, cellEdit); + table.set(row++, it, TID_MODIFIED, getTimeStamp(), false, cellEdit); + table.set(row++, it, TID_CARD, itos(getCardNo()), true, cellEdit); + table.set(row++, it, TID_CONTROL, getType(), true, cellEdit); + table.set(row++, it, TID_TIME, getTime(), true, cellEdit); + pRunner r = 0; + if (CardNo > 0) + r = oe->getRunnerByCardNo(CardNo, Time, false); + + table.set(row++, it, TID_RUNNER, r ? r->getName() : "?", false, cellEdit); + + if (r && r->getTeam()) + table.set(row++, it, TID_TEAM, r->getTeam()->getName(), false, cellEdit); + else + table.set(row++, it, TID_TEAM, "", false, cellEdit); +} + +bool oFreePunch::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + synchronize(false); + switch(id) { + case TID_CARD: + setCardNo(atoi(input.c_str())); + synchronize(true); + output = itos(CardNo); + break; + + case TID_TIME: + setTime(input); + synchronize(true); + output = getTime(); + break; + + case TID_CONTROL: + setType(input); + synchronize(true); + output = getType(); + } + return false; +} + +void oFreePunch::fillInput(int id, vector< pair > &out, size_t &selected) +{ +} + +void oFreePunch::setTimeInt(int t, bool databaseUpdate) { + if (t != Time) { + oe->removeFromPunchHash(CardNo, Type, Time); + Time = t; + oe->insertIntoPunchHash(CardNo, Type, Time); + rehashPunches(*oe, CardNo, 0); + if (!databaseUpdate) + updateChanged(); + } +} + +bool oFreePunch::setType(const string &t, bool databaseUpdate) { + int type = atoi(t.c_str()); + int ttype = 0; + if (type>0 && type<10000) + ttype = type; + else { + if (t == lang.tl("Check")) + ttype = oPunch::PunchCheck; + else if (t == lang.tl("Mål")) + ttype = oPunch::PunchFinish; + if (t == lang.tl("Start")) + ttype = oPunch::PunchStart; + } + if (ttype > 0 && ttype != Type) { + oe->removeFromPunchHash(CardNo, Type, Time); + Type = ttype; + oe->insertIntoPunchHash(CardNo, Type, Time); + int oldControlId = tMatchControlId; + rehashPunches(*oe, CardNo, 0); + + pRunner r = oe->getRunner(tRunnerId, 0); + + if (r) { + r->markClassChanged(tMatchControlId); + if (oldControlId > 0) + r->markClassChanged(oldControlId); + } + + if (!databaseUpdate) + updateChanged(); + + return true; + } + return false; +} + +void oFreePunch::rehashPunches(oEvent &oe, int cardNo, pFreePunch newPunch) { + if (disableHashing || (cardNo == 0 && !oe.punchIndex.empty()) || oe.punches.empty()) + return; + vector fp; + + if (oe.punchIndex.empty()) { + // Rehash all punches. Ignore cardNo and newPunch (will be included automatically) + fp.reserve(oe.punches.size()); + for (oFreePunchList::iterator pit = oe.punches.begin(); pit != oe.punches.end(); ++pit) { + if (pit->isRemoved()) + continue; + fp.push_back(&(*pit)); + } + + sort(fp.begin(), fp.end(), FreePunchComp()); + disableHashing = true; + try { + for (size_t j = 0; j < fp.size(); j++) { + pFreePunch punch = fp[j]; + punch->iHashType = oe.getControlIdFromPunch(punch->Time, punch->Type, punch->CardNo, true, + *punch); + + oEvent::PunchIndexType &card2Punch = oe.punchIndex[punch->iHashType]; + card2Punch.insert(make_pair(punch->CardNo, punch)); + } + } + catch(...) { + disableHashing = false; + throw; + } + disableHashing = false; + return; + } + + map::iterator it; + fp.reserve(oe.punchIndex.size() + 1); + + // Get all punches for the specified card. + for(it = oe.punchIndex.begin(); it != oe.punchIndex.end(); ++it) { + pair res = it->second.equal_range(cardNo); + oEvent::PunchConstIterator pIter = res.first; + while(pIter != res.second) { + pFreePunch punch = pIter->second; + assert(punch && punch->CardNo == cardNo); + if (!punch->isRemoved()) { + fp.push_back(punch); + } + ++pIter; + } + it->second.erase(res.first, res.second); + } + + if (newPunch) + fp.push_back(newPunch); + + sort(fp.begin(), fp.end(), FreePunchComp()); + for (size_t j = 0; j < fp.size(); j++) { + if (j>0 && fp[j-1] == fp[j]) + continue; //Skip duplicates + pFreePunch punch = fp[j]; + punch->iHashType = oe.getControlIdFromPunch(punch->Time, punch->Type, cardNo, true, *punch); + oEvent::PunchIndexType &card2Punch = oe.punchIndex[punch->iHashType]; + card2Punch.insert(make_pair(punch->CardNo, punch)); + } +} + +//const int legHashConstant = 100000; +int oFreePunch::getControlHash(int courseControlId, int race) { + int newId = courseControlId + race*100000000; + return newId; +} + +int oFreePunch::getControlIdFromHash(int hash, bool courseControlId) { + int r = (hash%100000000); + if (courseControlId) + return r; + else + return oControl::getIdIndexFromCourseControlId(r).first; +} + +int oEvent::getControlIdFromPunch(int time, int type, int card, + bool markClassChanged, oFreePunch &punch) { + pRunner r = getRunnerByCardNo(card, time); + punch.tRunnerId = -1; + punch.tMatchControlId = type; + if (r!=0) { + punch.tRunnerId = r->Id; + } + int race = 0; + if (type!=oPunch::PunchFinish) { + pCourse c = r ? r->getCourse(false): 0; + + if (c!=0) { + race = r->getRaceNo(); + for (int k=0; knControls; k++) { + pControl ctrl=c->getControl(k); + if (ctrl && ctrl->hasNumber(type)) { + int courseControlId = c->getCourseControlId(k); + pFreePunch p = getPunch(r->getId(), courseControlId, card); + if (!p || (p && abs(p->Time-time)<60)) { + ctrl->tHasFreePunchLabel = true; + punch.tMatchControlId = ctrl->getId(); + punch.tIndex = k; + int newId = oFreePunch::getControlHash(courseControlId, race); + if (newId != punch.iHashType && markClassChanged && r) { + r->markClassChanged(ctrl->getId()); + if (punch.iHashType > 0) + r->markClassChanged(oFreePunch::getControlIdFromHash(punch.iHashType, false)); + } + + //Code controlId and runner race number into code + return newId; + } + } + } + } + } + + int newId = oFreePunch::getControlHash(type, 0); + + if (newId != punch.iHashType && markClassChanged && r) { + r->markClassChanged(type); + if (punch.iHashType > 0) + r->markClassChanged(oFreePunch::getControlIdFromHash(punch.iHashType, false)); + } + + return newId; +} + +void oEvent::getFreeControls(set &controlId) const +{ + controlId.clear(); + for (map::const_iterator it = punchIndex.begin(); it != punchIndex.end(); ++it) { + int id = oFreePunch::getControlIdFromHash(it->first, false); + controlId.insert(id); + } +} + +//set< pair > readPunchHash; + +void oEvent::insertIntoPunchHash(int card, int code, int time) { + if (time > 0) { + int p1 = time * 4096 + code; + int p2 = card; + readPunchHash.insert(make_pair(p1, p2)); + } +} + +void oEvent::removeFromPunchHash(int card, int code, int time) { + int p1 = time * 4096 + code; + int p2 = card; + readPunchHash.erase(make_pair(p1, p2)); +} + +bool oEvent::isInPunchHash(int card, int code, int time) { + int p1 = time * 4096 + code; + int p2 = card; + return readPunchHash.count(make_pair(p1, p2)) > 0; +} + + +pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFinish) { + if (time > 0 && isInPunchHash(card, type, time)) + return 0; + oFreePunch ofp(this, card, time, type); + + punches.push_back(ofp); + pFreePunch fp=&punches.back(); + oFreePunch::rehashPunches(*this, card, fp); + insertIntoPunchHash(card, type, time); + + if (fp->getTiedRunner() && oe->isClient() && oe->getPropertyInt("UseDirectSocket", true)!=0) { + SocketPunchInfo pi; + pi.runnerId = fp->getTiedRunner()->getId(); + pi.time = fp->getAdjustedTime(); + pi.status = fp->getTiedRunner()->getStatus(); + if (fp->getTypeCode() > 10) + pi.iHashType = fp->getIHashType(); + else + pi.iHashType = fp->getTypeCode(); + + getDirectSocket().sendPunch(pi); + } + + fp->updateChanged(); + fp->synchronize(); + + // Update start/finish time + if (updateStartFinish && type == oPunch::PunchStart || type == oPunch::PunchFinish) { + pRunner tr = fp->getTiedRunner(); + if (tr && tr->getStatus() == StatusUnknown && time > 0) { + tr->synchronize(); + if (type == oPunch::PunchStart) { + if (tr->getClassRef() && !tr->getClassRef()->ignoreStartPunch()) + tr->setStartTime(time, true, false); + } + else + tr->setFinishTime(time); + + // Direct result + if (type == oPunch::PunchFinish && tr->getClassRef() && tr->getClassRef()->hasDirectResult()) { + if (tr->getCourse(false) == 0 && tr->getCard() == 0) { + tr->setStatus(StatusOK, true, false, true); + } + else if (tr->getCourse(false) != 0 && tr->getCard() == 0) { + pCard card = allocateCard(tr); + card->setupFromRadioPunches(*tr); + vector mp; + card->synchronize(); + tr->addPunches(card, mp); + } + } + + tr->synchronize(true); + } + } + if (fp->getTiedRunner()) + pushDirectChange(); + return fp; +} + +pFreePunch oEvent::addFreePunch(oFreePunch &fp) { + insertIntoPunchHash(fp.CardNo, fp.Type, fp.Time); + punches.push_back(fp); + pFreePunch fpz=&punches.back(); + oFreePunch::rehashPunches(*this, fp.CardNo, fpz); + + if (!fpz->existInDB() && HasDBConnection) { + fpz->changed = true; + fpz->synchronize(); + } + return fpz; +} + +void oEvent::removeFreePunch(int Id) { + oFreePunchList::iterator it; + + for (it=punches.begin(); it != punches.end(); ++it) { + if (it->Id==Id) { + pRunner r = getRunner(it->tRunnerId, 0); + if (r && r->Class) { + r->markClassChanged(it->tMatchControlId); + classChanged(r->Class, true); + } + pFreePunch fp = &*it; + if (HasDBConnection) + msRemove(fp); + //punchIndex[it->itype].remove(it->CardNo); + PunchIndexType &ix = punchIndex[it->iHashType]; + pair res = ix.equal_range(it->CardNo); + while (res.first != res.second) { + if (res.first->second == fp) { + PunchConstIterator rm = res.first; + ++res.first; + ix.erase(rm); + } + else + ++res.first; + } + + int cardNo = fp->CardNo; + removeFromPunchHash(cardNo, fp->Type, fp->Time); + punches.erase(it); + oFreePunch::rehashPunches(*this, cardNo, 0); + dataRevision++; + return; + } + } +} + +pFreePunch oEvent::getPunch(int Id) const +{ + oFreePunchList::const_iterator it; + + for (it=punches.begin(); it != punches.end(); ++it) { + if (it->Id==Id) { + if (it->isRemoved()) + return 0; + return const_cast(&*it); + } + } + return 0; +} + +pFreePunch oEvent::getPunch(int runnerId, int courseControlId, int card) const +{ + //Lazy setup + oFreePunch::rehashPunches(*oe, 0, 0); + + pRunner r = oe->getRunner(runnerId, 0); + int runnerRace = r ? r->getRaceNo() : 0; + map::const_iterator it1; + + int itype = oFreePunch::getControlHash(courseControlId, runnerRace); + + it1=punchIndex.find(itype); + + if (it1!=punchIndex.end()) { + const oEvent::PunchIndexType &cIndex = it1->second; + pair res = cIndex.equal_range(card); + oEvent::PunchConstIterator pIter = res.first; + while(pIter != res.second) { + pFreePunch punch = pIter->second; + if (!punch->isRemoved()) { + assert(punch && punch->CardNo == card); + if (punch->tRunnerId == runnerId || runnerId == 0) + return punch; + ++pIter; + } + } + } + + map, oFreePunch>::const_iterator res = advanceInformationPunches.find(make_pair(itype, card)); + if (res != advanceInformationPunches.end()) + return (pFreePunch)&res->second; + + return 0; +} + +void oEvent::getPunchesForRunner(int runnerId, vector &runnerPunches) const { + runnerPunches.clear(); + pRunner r = getRunner(runnerId, 0); + if (r == 0) + return; + + // Get times for when other runners used this card + vector< pair > times; + + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->Id == runnerId) + continue; + if (it->Card && it->CardNo == r->CardNo) { + pair t = it->Card->getTimeRange(); + if (it->getStartTime() > 0) + t.first = min(it->getStartTime(), t.first); + + if (it->getFinishTime() > 0) + t.second = max(it->getFinishTime(), t.second); + + times.push_back(t); + } + } + + for (oFreePunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + if (it->CardNo == r->CardNo) { + bool other = false; + int t = it->Time; + for (size_t k = 0; k= times[k].first && t <= times[k].second) + other = true; + } + + if (!other) + runnerPunches.push_back(pFreePunch(&*it)); + } + } + + // XXX Advance punches... +} + + +bool oEvent::advancePunchInformation(const vector &gdi, vector &pi, + bool fetchPunch, bool fetchFinish) { + if (pi.empty()) + return false; + + bool m = false; + for (size_t k = 0; k < pi.size(); k++) { + pRunner r = getRunner(pi[k].runnerId, 0); + if (!r) + continue; + if (pi[k].iHashType == oPunch::PunchFinish && fetchFinish) { + if (r->getStatus() == StatusUnknown && r->getFinishTime() <= 0 && !r->isChanged()) { + r->FinishTime = pi[k].time; + r->tStatus = RunnerStatus(pi[k].status); + r->status = RunnerStatus(pi[k].status); // Will be overwritten (do not set isChanged flag) + if (r->Class) { + r->markClassChanged(oPunch::PunchFinish); + classChanged(r->Class, false); + } + m = true; + } + } + else if (fetchPunch) { + // controlId is already the encoded format including index and race + if (getPunch(pi[k].runnerId, pi[k].iHashType, r->getCardNo()) == 0) { + oFreePunch fp(this, 0, pi[k].time, pi[k].iHashType); + fp.tRunnerId = pi[k].runnerId; + fp.iHashType = pi[k].iHashType; + fp.tIndex = 0; + fp.tMatchControlId = oFreePunch::getControlIdFromHash(fp.iHashType, false); + fp.changed = false; + pair hc(pi[k].iHashType, r->getCardNo()); + advanceInformationPunches.insert(make_pair(hc,fp)); + if (r->Class) { + r->markClassChanged(oFreePunch::getControlIdFromHash(pi[k].iHashType, false)); + classChanged(r->Class, true); + } + m = true; + } + } + } + if (m) { + dataRevision++; + for (size_t k = 0; kmakeEvent("DataUpdate", "autosync", 0, 0, false); + } + } + return m; +} + +void oEvent::getLatestPunches(int firstTime, vector &punchesOut) const { + for (map< pair, oFreePunch>::const_iterator it = advanceInformationPunches.begin(); + it != advanceInformationPunches.end(); ++it) { + int time = it->second.getModificationTime(); + if (time >= firstTime) + punchesOut.push_back(&it->second); + } + + for (oFreePunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) { + int time = it->getModificationTime(); + if (time >= firstTime) + punchesOut.push_back(&*it); + } +} + +pRunner oFreePunch::getTiedRunner() const { + return oe->getRunner(tRunnerId, 0); +} + +void oFreePunch::changedObject() { + pRunner r = getTiedRunner(); + if (r && tMatchControlId>0) + r->markClassChanged(tMatchControlId); +} diff --git a/code/oFreePunch.h b/code/oFreePunch.h new file mode 100644 index 0000000..a93a727 --- /dev/null +++ b/code/oFreePunch.h @@ -0,0 +1,97 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "oBase.h" +#include "oPunch.h" +#include "xmlparser.h" + +class oFreePunch; +typedef oFreePunch* pFreePunch; +class oRunner; +typedef oRunner *pRunner; +class Table; + +class oFreePunch : public oPunch +{ +protected: + int CardNo; + int iHashType; //Index type used for lookup + int tRunnerId; // Id of runner the punch is classified to. + + /** Class used to sort punches by time. */ + class FreePunchComp { + public: + bool operator()(pFreePunch a, pFreePunch b) { + return a->Time < b->Time; + } + }; + + void changedObject(); + +public: + + // Get control hash (itype) from course controld and race number + static int getControlHash(int courseControlId, int race); + + // Get controlId or courseControlId from hash (itype) + static int getControlIdFromHash(int hash, bool courseControlId); + + // Get the id of the control currently tied to this punch + int getControlId() const {return getControlIdFromHash(iHashType, false);} + + // Get the id of the course control currently tied to this punch + int getCourseControlId() const {return getControlIdFromHash(iHashType, true);} + + // Get the id hash + int getIHashType() const {return iHashType;} + + + // Get the runner currently tied to this punch + pRunner getTiedRunner() const; + void addTableRow(Table &table) const; + void fillInput(int id, vector< pair > &out, size_t &selected); + bool inputData(int id, const string &input, int inputId, string &output, bool noUpdate); + + void remove(); + bool canRemove() const; + + int getCardNo() const {return CardNo;} + bool setCardNo(int cardNo, bool databaseUpdate = false); + bool setType(const string &t, bool databaseUpdate = false); + void setTimeInt(int newTime, bool databaseUpdate); + + static void rehashPunches(oEvent &oe, int cardNo, pFreePunch newPunch); + static bool disableHashing; + + oFreePunch(oEvent *poe, int card, int time, int type); + oFreePunch(oEvent *poe, int id); + virtual ~oFreePunch(void); + + void Set(const xmlobject *xo); + bool Write(xmlparser &xml); + + friend class oEvent; + friend class oRunner; + friend class MeosSQL; +}; diff --git a/code/oImportExport.cpp b/code/oImportExport.cpp new file mode 100644 index 0000000..6959b83 --- /dev/null +++ b/code/oImportExport.cpp @@ -0,0 +1,2713 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oEvent.cpp: implementation of the oEvent class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" + +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "meosdb/sqltypes.h" +#include "meosexception.h" +#include "inthashmap.h" + +#include "oDataContainer.h" +#include "csvparser.h" +#include "oFreeImport.h" + +#include "random.h" +#include "SportIdent.h" +#include "RunnerDB.h" +#include "meos_util.h" +#include "meos.h" +#include "importformats.h" + +#include +#include +#include "localizer.h" +#include "iof30interface.h" + +#include "meosdb/sqltypes.h" + +string conv_is(int i) +{ + char bf[256]; +// if (i==0) +// return ""; + //else + if (_itoa_s(i, bf, 10)==0) + return bf; + return ""; +} + + +int ConvertStatusToOE(int i) +{ + switch(i) + { + case StatusOK: + return 0; + case StatusDNS: // Ej start + return 1; + case StatusDNF: // Utg. + return 2; + case StatusMP: // Felst. + return 3; + case StatusDQ: //Disk + return 4; + case StatusMAX: //Maxtid + return 5; + } + return 1;//Ej start...?! +} + +string &getFirst(string &inout, int maxNames) { + int s = inout.size(); + for (int k = 0;k3 && maxNames<=1) { + inout[k] = 0; + maxNames--; + return inout; + } + } + return inout; +} + +bool oEvent::exportOECSV(const char *file, int languageTypeIndex, bool includeSplits) +{ + enum { + OEstno = 0, OEcard = 1, OEid = 2, OEsurname = 3, OEfirstname = 4, + OEbirth = 5, OEsex = 6, OEnc = 8, OEstart = 9, OEfinish = 10, OEtime = 11, OEstatus = 12, + OEclubno = 13, OEclub = 14, OEclubcity = 15, OEnat = 16, OEclassno = 17, + OEclassshortname = 18, OEclassname = 19, OErent = 35, OEfee = 36, OEpaid = 37, OEcourseno = 38, OEcourse = 39, + OElength = 40, OEclimb = 41, OEcoursecontrols = 42, OEpl = 43, OEstartpunch = 44, OEfinishpunch = 45 + }; + + csvparser csv; + + oClass::initClassId(*this); + + if (!csv.openOutput(file)) + return false; + + calculateResults(RTClassResult); + + oRunnerList::iterator it; + string maleString; + string femaleString; + + switch (languageTypeIndex) + { + case 1: // English + csv.OutputRow("Stno;Chip;Database Id;Surname;First name;YB;S;Block;nc;Start;Finish;Time;Classifier;Club no.;Cl.name;City;Nat;Cl. no.;Short;Long;Num1;Num2;Num3;Text1;Text2;Text3;Adr. name;Street;Line2;Zip;City;Phone;Fax;EMail;Id/Club;Rented;Start fee;Paid;Course no.;Course;km;m;Course controls;Pl;Start punch;Finish punch;Control1;Punch1;Control2;Punch2;Control3;Punch3;Control4;Punch4;Control5;Punch5;Control6;Punch6;Control7;Punch7;Control8;Punch8;Control9;Punch9;Control10;Punch10;(may be more) ..."); + maleString = "M"; + femaleString = "F"; + break; + case 2: // Svenska + csv.OutputRow("Startnr;Bricka;Databas nr.;Efternamn;Förnamn;År;K;Block;ut;Start;Mål;Tid;Status;Klubb nr.;Namn;Ort;Land;Klass nr.;Kort;Lång;Num1;Num2;Num3;Text1;Text2;Text3;Adr. namn;Gata;Rad 2;Post nr.;Ort;Tel;Fax;E-post;Id/Club;Hyrd;Startavgift;Betalt;Bana nr.;Bana;km;Hm;Bana kontroller;Pl;Startstämpling;Målstämpling;Kontroll1;Stämplar1;Kontroll2;Stämplar2;Kontroll3;Stämplar3;Kontroll4;Stämplar4;Kontroll5;Stämplar5;Kontroll6;Stämplar6;Kontroll7;Stämplar7;Kontroll8;Stämplar8;Kontroll9;Stämplar9;Kontroll10;Stämplar10;(kan fortsätta).."); + maleString = "M"; + femaleString = "K"; + break; + case 3: // Deutsch + csv.OutputRow("Stnr;Chip;Datenbank Id;Nachname;Vorname;Jg;G;Block;AK;Start;Ziel;Zeit;Wertung;Club-Nr.;Abk;Ort;Nat;Katnr;Kurz;Lang;Num1;Num2;Num3;Text1;Text2;Text3;Adr. Name;Straße;Zeile2;PLZ;Ort;Tel;Fax;EMail;Id/Verein;Gemietet;Startgeld;Bezahlt;Bahnnummer;Bahn;km;Hm;Bahn Posten;Pl;Startstempel;Zielstempel;Posten1;Stempel1;Posten2;Stempel2;Posten3;Stempel3;Posten4;Stempel4;Posten5;Stempel5;Posten6;Stempel6;Posten7;Stempel7;Posten8;Stempel8;Posten9;Stempel9;Posten10;Stempel10;(und weitere)..."); + maleString = "M"; + femaleString = "W"; + break; + case 4: // Dansk + csv.OutputRow("Stnr;Brik;Database ID;Efternavn;Fornavn;År;K;Blok;UFK;Start;Mål;Tid;Status;Klub nr.;Navn;Klub;Land;Klasse nr.;kort;Lang;Num1;Num2;Num3;Text1;Text2;Text3;Adr. navn;Gade;Linie2;Post nr.;Klub;Tlf.;Fax.;Email;Id/klub;Lejet;Startafgift;Betalt;Bane nr.;Bane;km;Hm;Poster på bane;Pl;Start-stempling;Mål-stempling;Post1;Klip1;Post2;Klip2;Post3;Klip3;Post4;Klip4;Post5;Klip5;Post6;Klip6;Post7;Klip7;Post8;Klip8;Post9;Klip9;Post10;Klip10;(måske mere)..."); + maleString = "M"; + femaleString = "K"; + break; + case 5: // Français + csv.OutputRow("N° dép.;Puce;Ident. base de données;Nom;Prénom;Né;S;Plage;nc;Départ;Arrivée;Temps;Evaluation;N° club;Nom;Ville;Nat;N° cat.;Court;Long;Num1;Num2;Num3;Text1;Text2;Text3;Adr. nom;Rue;Ligne2;Code Post.;Ville;Tél.;Fax;E-mail;Id/Club;Louée;Engagement;Payé;Circuit N°;Circuit;km;m;Postes du circuit;Pl;Poinçon de départ;Arrivée (P);Poste1;Poinçon1;Poste2;Poinçon2;Poste3;Poinçon3;Poste4;Poinçon4;Poste5;Poinçon5;Poste6;Poinçon6;Poste7;Poinçon7;Poste8;Poinçon8;Poste9;Poinçon9;Poste10;Poinçon10;(peut être plus) ..."); + maleString = "H"; + femaleString = "F"; + break; + case 6: // Russian + csv.OutputRow("Stnr;Chip;Datenbank Id;Nachname;Vorname;Jg;G_Sex;Block;AK_notclass;Start;Ziel;Zeit;Wertung;Club-Nr.;Abk;Ort;Nat;Katnr;Kurz;Lang;Num1;Num2;Num3;Text1;Text2;Text3;Adr. Name;Strasse;Zeile2;PLZ;Ort;Tel;Fax;EMail;Club_TIdNr;Gemietet;Startgeld;Bezahlt;Bahnnummer;Bahn;km_Kilometer;Hm_Climbmeter;Bahn Posten;Pl_Place;Startstempel;Zielstempel;Posten1;Stempel1;Posten2;Stempel2;Posten3;Stempel3;Posten4;Stempel4;Posten5;Stempel5;Posten6;Stempel6;Posten7;Stempel7;Posten8;Stempel8;Posten9;Stempel9;Posten10;Stempel10;(und weitere)..."); + maleString = "M"; + femaleString = "W"; + break; + default: + csv.OutputRow("Stno;Chip;Database Id;Surname;First name;YB;S;Block;nc;Start;Finish;Time;Classifier;Club no.;Cl.name;City;Nat;Cl. no.;Short;Long;Num1;Num2;Num3;Text1;Text2;Text3;Adr. name;Street;Line2;Zip;City;Phone;Fax;EMail;Id/Club;Rented;Start fee;Paid;Course no.;Course;km;m;Course controls;Pl;Start punch;Finish punch;Control1;Punch1;Control2;Punch2;Control3;Punch3;Control4;Punch4;Control5;Punch5;Control6;Punch6;Control7;Punch7;Control8;Punch8;Control9;Punch9;Control10;Punch10;(may be more) ..."); + maleString = "M"; + femaleString = "F"; + } + + char bf[256]; + for (it = Runners.begin(); it != Runners.end(); ++it) { + vector row; + row.resize(46); + oDataInterface di = it->getDI(); + + row[OEstno] = conv_is(it->getId()); + row[OEcard] = conv_is(it->getCardNo()); + if (it->getExtIdentifier() != 0) + row[OEid] = it->getExtIdentifierString(); + row[OEsurname] = it->getFamilyName(); + row[OEfirstname] = it->getGivenName(); + row[OEbirth] = conv_is(di.getInt("BirthYear") % 100); + + // Specialized per language + PersonSex s = it->getSex(); + switch (s) { + case sFemale: + row[OEsex] = femaleString; + break; + case sMale: + row[OEsex] = maleString; + break; + case sBoth: + case sUnknown: + default: + row[OEsex] = di.getString("Sex"); + break; + } + + // nc / Runner shall not / doesn't want to be ranked + if (it->getStatus() == StatusNotCompetiting) + row[OEnc] = "X"; + else + row[OEnc] = "0"; + + // Excel format HH:MM:SS + string dash = MakeDash("-"); + row[OEstart] = it->getStartTimeS(); + if (row[OEstart] == dash) + row[OEstart] = ""; + + // Excel format HH:MM:SS + row[OEfinish] = it->getFinishTimeS(); + if (row[OEfinish] == dash) + row[OEfinish] = ""; + + // Excel format HH:MM:SS + row[OEtime] = formatTimeHMS(it->getRunningTime()); + if (row[OEtime] == dash) + row[OEtime] = ""; + + row[OEstatus] = conv_is(ConvertStatusToOE(it->getStatus())); + row[OEclubno] = conv_is(it->getClubId()); + + if (it->getClubRef()) { + row[OEclub] = it->getClubRef()->getDI().getString("ShortName"); + row[OEclubcity] = it->getClub(); + } + row[OEnat] = di.getString("Nationality"); + row[OEclassno] = conv_is(it->getClassId()); + row[OEclassshortname] = it->getClass(); + row[OEclassname] = it->getClass(); + + row[OErent] = conv_is(di.getInt("CardFee")); + row[OEfee] = conv_is(di.getInt("Fee")); + row[OEpaid] = conv_is(di.getInt("Paid")); + + pCourse pc = it->getCourse(true); + if (pc) { + row[OEcourseno] = conv_is(pc->getId()); + row[OEcourse] = pc->getName(); + if (pc->getLength()>0) { + sprintf_s(bf, "%d.%d", pc->getLength() / 1000, pc->getLength() % 1000); + row[OElength] = bf; + } + row[OEclimb] = conv_is(pc->getDI().getInt("Climb")); + + row[OEcoursecontrols] = conv_is(pc->nControls); + } + row[OEpl] = it->getPlaceS(); + + if (includeSplits && pc != NULL) + { + // Add here split times + + // row[45]: finish time + row[OEfinishpunch] = row[OEfinish]; + + // row[46; 48; 50; ..]: control id + // row[47; 49; 51; ..]: punch time of control id row[i-1] + + const vector &sp = it->getSplitTimes(true); + + bool hasRogaining = pc->hasRogaining(); + int startIx = pc->useFirstAsStart() ? 1 : 0; + int endIx = pc->useLastAsFinish() ? pc->nControls - 1 : pc->nControls; + + for (int k = startIx, m = 0; k < endIx; k++, m += 2) { + if (pc->getControl(k)->isRogaining(hasRogaining)) + continue; + row.push_back(pc->getControl(k)->getIdS()); + if (unsigned(k) < sp.size() && sp[k].time > 0) + row.push_back(formatTimeHMS(sp[k].time - it->tStartTime)); + else + row.push_back("-----"); + } + + // Extra punches + vector punches; + + oe->getPunchesForRunner(it->getId(), punches); + for (vector::iterator punchIt = punches.begin(); punchIt != punches.end(); ++punchIt) { + pPunch punch = *punchIt; + if (!punch->isUsed && !(punch->isFinish() && !pc->useLastAsFinish()) && !(punch->isStart() && !pc->useFirstAsStart()) && !punch->isCheck()) + { + row.push_back(punch->getType()); + + int t = punch->getAdjustedTime(); + if (it->tStartTime > 0 && t > 0 && t > it->tStartTime) + row.push_back(formatTimeHMS(t - it->tStartTime)); + else + return "-----"; + } + } + + } + + csv.OutputRow(row); + } + + csv.closeOutput(); + + return true; +} + +void oEvent::importXML_EntryData(gdioutput &gdi, const char *file, bool updateClass, bool removeNonexisting) +{ + vector< pair > runnersInTeam; + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && it->tInTeam) { + runnersInTeam.push_back(make_pair(it->getId(), it->getClassId()) ); + } + } + + xmlparser xml(0); + xml.read(file); + + xmlobject xo = xml.getObject("EntryList"); + + if (xo) { + + gdi.addString("", 0, "Importerar anmälningar (IOF, xml)"); + gdi.refreshFast(); + int ent = 0, fail = 0, removed = 0; + + if (xo.getAttrib("iofVersion")) { + IOF30Interface reader(this, false); + reader.readEntryList(gdi, xo, removeNonexisting, ent, fail, removed); + } + else { + xmlList xl; + xo.getObjects(xl); + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("ClubEntry")){ + xmlList entries; + //xmlobject xentry=it->getObject("Entry"); + int ClubId = 0; + + xmlobject club = it->getObject("Club"); + + if (club) { + addXMLClub(club, false); + ClubId = club.getObjectInt("ClubId"); + } + else + ClubId = it->getObjectInt("ClubId"); + + it->getObjects("Entry", entries); + for (size_t k = 0; k0) + gdi.addString("", 0, "Antal misslyckade: X#" + itos(fail)).setColor(colorRed); + gdi.dropLine(); + gdi.refreshFast(); + } + + + xo = xml.getObject("StartList"); + + if (xo) { + + gdi.addString("", 0, "Importerar anmälningar (IOF, xml)"); + gdi.refreshFast(); + + int ent = 0, fail = 0; + + if (xo.getAttrib("iofVersion")) { + IOF30Interface reader(this, false); + reader.readStartList(gdi, xo, ent, fail); + } + else { + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("ClassStart")){ + xmlList entries; + int clsId = it->getObjectInt("ClassId"); + + pClass cls = 0; + if (clsId == 0) { + string clsName; + it->getObjectString("ClassShortName", clsName); + if (!clsName.empty()) + cls = getClassCreate(0, clsName); + } + else + cls = getClassCreate(clsId, lang.tl("Klass ") + itos(clsId)); + + it->getObjects("PersonStart", entries); + for (size_t k = 0; k0) + gdi.addString("", 0, "Antal misslyckade: X#" + itos(fail)).setColor(colorRed); + gdi.dropLine(); + gdi.refreshFast(); + } + + xo = xml.getObject("ClassData"); + + if (!xo) + xo = xml.getObject("ClassList"); + + if (xo) { + gdi.addString("", 0, "Importerar klasser (IOF, xml)"); + gdi.refreshFast(); + int imp = 0, fail = 0; + + if (xo.getAttrib("iofVersion")) { + IOF30Interface reader(this, false); + reader.readClassList(gdi, xo, imp, fail); + } + else { + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for (it=xl.begin(); it != xl.end(); ++it) { + if (it->is("Class")) { + if (addXMLClass(*it)) + imp++; + else fail++; + } + } + } + gdi.addString("", 0, "Klart. Antal importerade: X#" + itos(imp)); + if (fail>0) + gdi.addString("", 0, "Antal misslyckade: X#" + itos(fail)).setColor(colorRed); + gdi.dropLine(); + gdi.refreshFast(); + } + + xo=xml.getObject("ClubList"); + + if (xo) { + gdi.addString("", 0, "Importerar klubbar (IOF, xml)"); + gdi.refreshFast(); + int imp = 0, fail = 0; + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Club")){ + if (addXMLClub(*it, false)) + imp++; + else + fail++; + } + } + gdi.addString("", 0, "Klart. Antal importerade: X#" + itos(imp)); + if (fail>0) + gdi.addString("", 0, "Antal misslyckade: X#" + itos(fail)).setColor(colorRed); + gdi.dropLine(); + gdi.refreshFast(); + } + + xo=xml.getObject("RankList"); + + if (xo) { + gdi.addString("", 0, "Importerar ranking (IOF, xml)"); + gdi.refreshFast(); + int imp = 0, fail = 0; + + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + map<__int64, int> ext2Id; + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + __int64 ext = it->getExtIdentifier(); + if (ext != 0) + ext2Id[ext] = it->getId(); + } + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Competitor")){ + if (addXMLRank(*it, ext2Id)) + imp++; + else + fail++; + } + } + + gdi.addString("", 0, "Klart. Antal importerade: X#" + itos(imp)); + if (fail>0) + gdi.addString("", 0, "Antal ignorerade: X#" + itos(fail)); + gdi.dropLine(); + gdi.refreshFast(); + } + + xo=xml.getObject("CourseData"); + + if (xo) { + gdi.addString("", 0, "Importerar banor (IOF, xml)"); + gdi.refreshFast(); + int imp = 0, fail = 0; + + if (xo && xo.getAttrib("iofVersion")) { + IOF30Interface reader(this, false); + reader.readCourseData(gdi, xo, updateClass, imp, fail); + } + else { + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Course")){ + if (addXMLCourse(*it, updateClass)) + imp++; + else + fail++; + } + else if (it->is("Control")){ + addXMLControl(*it, 0); + } + else if (it->is("StartPoint")){ + addXMLControl(*it, 1); + } + else if (it->is("FinishPoint")){ + addXMLControl(*it, 2); + } + } + } + + gdi.addString("", 0, "Klart. Antal importerade: X#" + itos(imp)); + if (fail>0) + gdi.addString("", 0, "Antal misslyckade: X#" + itos(fail)).setColor(colorRed); + gdi.dropLine(); + gdi.refreshFast(); + } + + + xo=xml.getObject("EventList"); + + if (xo) { + gdi.addString("", 0, "Importerar tävlingsdata (IOF, xml)"); + gdi.refreshFast(); + + if (xo.getAttrib("iofVersion")) { + IOF30Interface reader(this, false); + reader.readEventList(gdi, xo); + gdi.addString("", 0, "Tävlingens namn: X#" + getName()); + gdi.dropLine(); + gdi.refreshFast(); + } + else { + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Event")){ + addXMLEvent(*it); + gdi.addString("", 0, "Tävlingens namn: X#" + getName()); + gdi.dropLine(); + gdi.refreshFast(); + break; + } + } + } + } + + vector toRemove; + for (size_t k = 0; k < runnersInTeam.size(); k++) { + int id = runnersInTeam[k].first; + int classId = runnersInTeam[k].second; + pRunner r = getRunner(id, 0); + if (r && !r->tInTeam && r->getClassId() == classId) { + toRemove.push_back(r->getId()); + } + } + removeRunner(toRemove); +} + +bool oEvent::addXMLCompetitorDB(const xmlobject &xentry, int clubId) +{ + if (!xentry) return false; + + xmlobject person = xentry.getObject("Person"); + if (!person) return false; + + string pids; + person.getObjectString("PersonId", pids); + __int64 extId = oBase::converExtIdentifierString(pids); + int pid = oBase::idFromExtId(extId); + + xmlobject pname = person.getObject("PersonName"); + if (!pname) return false; + + int cardno = 0; + string tmp; + + xmlList cards; + xentry.getObjects("CCard", cards); + + for (size_t k = 0; kgetRunnerById(extId); + + if (!rde) { + rde = runnerDB->getRunnerByCard(cardno); + + if (rde && rde->getExtId() != 0) + rde = 0; //Other runner, same card + + if (!rde) + rde = runnerDB->addRunner(name.c_str(), pid, clubId, cardno); + } + + if (rde) { + rde->setExtId(extId); + rde->setName(name.c_str()); + rde->clubNo = clubId; + rde->birthYear = extendYear(birth); + rde->sex = sex[0]; + memcpy(rde->national, national, 3); + } + return true; +} + +bool oEvent::addOECSVCompetitorDB(const vector &row) +{ + // Ident. base de données;Puce;Nom;Prénom;Né;S;N° club;Nom;Ville;Nat;N° cat.;Court;Long;Num1;Num2;Num3;E_Mail;Texte1;Texte2;Texte3;Adr. nom;Rue;Ligne2;Code Post.;Ville;Tél.;Fax;E-mail;Id/Club;Louée + enum { OEid = 0, OEcard = 1, OEsurname = 2, OEfirstname = 3, OEbirth = 4, OEsex = 5, + OEclubno = 6, OEclub = 7, OEclubcity = 8, OEnat = 9, OEclassno = 10, OEclassshort = 11, OEclasslong = 12 + }; + + int pid = atoi(row[OEid].c_str()); + + string given = row[OEfirstname]; + string family = row[OEsurname]; + + if (given.empty() && family.empty()) + return false; + + string name = family + ", " + given; + + // Depending on the OE language, man = "H" (French) or "M" (English, Svenska, Dansk, Russian, Deutsch) + // woman = "F" (English, French) or "W" (Deutsch, Russian) or "K" (Svenska, Dansk) + char sex[2]; + if (row[OEsex] == "H" || row[OEsex] == "M") + strcpy(sex, "M"); + else if (row[OEsex] == "F" || row[OEsex] == "K" || row[OEsex] == "W") + strcpy(sex, "W"); + else + strcpy(sex, ""); + + int birth = atoi(row[OEbirth].c_str()); + + // Hack to take care of inconsistency between FFCO licensees archive (France) and event registrations from FFCO (FR) + char national[4] = { 0,0,0,0 }; + if (row[OEnat] == "France") { + strcpy(national, "FRA"); + } + + // Extract club data + + int clubId = atoi(row[OEclubno].c_str()); + string clubName; + string shortClubName; + + clubName = row[OEclubcity]; + shortClubName = row[OEclub]; + + if (clubName.length() > 0 && IsCharAlphaNumeric(clubName[0])) { + + pClub pc = new oClub(this); + pc->Id = clubId; + + pc->setName(clubName); + pc->setExtIdentifier(clubId); + + oDataInterface DI = pc->getDI(); + DI.setString("ShortName", shortClubName.substr(0, 8)); + // Nationality? + + runnerDB->importClub(*pc, false); + delete pc; + } + + RunnerDBEntry *rde = runnerDB->getRunnerById(pid); + + int cardno = atoi(row[OEcard].c_str()); + if (!rde) { + rde = runnerDB->getRunnerByCard(cardno); + + if (rde && rde->getExtId() != 0) + rde = NULL; //Other runner, same card + + if (!rde) + rde = runnerDB->addRunner(name.c_str(), pid, clubId, cardno); + } + + if (rde) { + rde->setExtId(pid); + rde->setName(name.c_str()); + rde->clubNo = clubId; + rde->birthYear = extendYear(birth); + rde->sex = sex[0]; + memcpy(rde->national, national, 3); + } + return true; +} + +bool oEvent::addXMLTeamEntry(const xmlobject &xentry, int clubId) +{ + if (!xentry) return false; + + string name; + xentry.getObjectString("TeamName", name); + int id = xentry.getObjectInt("EntryId"); + + if (name.empty()) + name = lang.tl("Lag X#" + itos(id)); + + xmlList teamCmp; + xentry.getObjects("TeamCompetitor", teamCmp); + + xmlobject cls = xentry.getObject("EntryClass"); + xmlobject edate = xentry.getObject("EntryDate"); + + pClass pc = getXMLClass(xentry); + + if (!pc) + return false; + + pClub club = getClubCreate(clubId); + + pTeam t = getTeam(id); + + if (t == 0) { + if ( id > 0) { + oTeam or(this, id); + t = addTeam(or, true); + } + else { + oTeam or(this); + t = addTeam(or, true); + } + t->setStartNo(Teams.size(), false); + } + + if (!t->hasFlag(oAbstractRunner::FlagUpdateName)) + t->setName(name, false); + if (!t->Class || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) + t->setClassId(pc->getId(), false); + + t->Club = club; + oDataInterface DI = t->getDI(); + + string date; + if (edate) DI.setDate("EntryDate", edate.getObjectString("Date", date)); + + int maxleg = teamCmp.size(); + for (size_t k = 0; k < teamCmp.size(); k++) { + maxleg = max(maxleg, teamCmp[k].getObjectInt("TeamSequence")); + } + + if (pc->getNumStages() < unsigned(maxleg)) { + setupRelay(*pc, PRelay, maxleg, getAbsTime(3600)); + } + + for (size_t k = 0; k < teamCmp.size(); k++) { + int leg = teamCmp[k].getObjectInt("TeamSequence") - 1; + if (leg>=0) { + pRunner r = addXMLEntry(teamCmp[k], clubId, false); + t->setRunner(leg, r, true); + } + } + + return true; +} + +pClass oEvent::getXMLClass(const xmlobject &xentry) { + + xmlobject eclass = xentry.getObject("EntryClass"); + if (eclass) { + int cid = eclass.getObjectInt("ClassId"); + pClass pc = getClass(cid); + if ( pc == 0 && cid>0) { + oClass cls(this, cid); + cls.Name = lang.tl("Klass X#" + itos(cid)); + pc = addClass(cls);//Create class if not found + } + return pc; + } + return 0; +} + +pClub oEvent::getClubCreate(int clubId) { + if (clubId) { + pClub club = getClub(clubId); + if (!club) { + pClub dbClub = runnerDB->getClub(clubId); + if (dbClub) { + club = addClub(*dbClub); + } + if (!club) { + club = addClub(lang.tl("Klubb X#" + itos(clubId))); + } + } + return club; + } + return 0; +} + +pRunner oEvent::addXMLPerson(const xmlobject &person) { + xmlobject pname = person.getObject("PersonName"); + if (!pname) return 0; + + string pids; + person.getObjectString("PersonId", pids); + __int64 extId = oBase::converExtIdentifierString(pids); + int pid = oBase::idFromExtId(extId); + pRunner r = 0; + + if (pid) + r = getRunner(pid, 0); + + if (!r) { + if ( pid > 0) { + oRunner or(this, pid); + r = addRunner(or, true); + } + else { + oRunner or(this); + r = addRunner(or, true); + } + } + + string given, family; + pname.getObjectString("Given", given); + pname.getObjectString("Family", family); + + r->setName(family + ", " + getFirst(given, 2), false); + r->setExtIdentifier(extId); + + oDataInterface DI=r->getDI(); + string tmp; + + r->setSex(interpretSex(person.getObjectString("sex", tmp))); + xmlobject bd=person.getObject("BirthDate"); + + if (bd) r->setBirthYear(extendYear(bd.getObjectInt("Date"))); + + xmlobject nat=person.getObject("Nationality"); + + if (nat) { + char national[4]; + xmlobject natId = nat.getObject("CountryId"); + if (natId) + r->setNationality(natId.getObjectString("value", national, 4)); + } + + return r; +} + +pRunner oEvent::addXMLEntry(const xmlobject &xentry, int clubId, bool setClass) { + if (!xentry) return 0; + + xmlobject person = xentry.getObject("Person"); + if (!person) return 0; + + pRunner r = addXMLPerson(person); + + int cmpClubId = xentry.getObjectInt("ClubId"); + if (cmpClubId != 0) + clubId = cmpClubId; + + oDataInterface DI=r->getDI(); + string given = r->getGivenName(); + xmlList cards; + xentry.getObjects("CCard", cards); + string tmp; + for (size_t k= 0; ksetCardNo(cardno, false); + break; + } + } + } + + pClass oldClass = r->Class; + pClub oldClub = r->Club; + + if (setClass && !r->hasFlag(oAbstractRunner::FlagUpdateClass) ) + r->Class = getXMLClass(xentry); + + r->Club = getClubCreate(clubId); + + if (oldClass != r->Class || oldClub != r->Club) + r->updateChanged(); + + xmlobject edate=xentry.getObject("EntryDate"); + if (edate) DI.setDate("EntryDate", edate.getObjectString("Date", tmp)); + + r->addClassDefaultFee(false); + r->synchronize(); + + xmlobject adjRunner = xentry.getObject("AllocationControl"); + + if (adjRunner) { + xmlobject person2 = adjRunner.getObject("Person"); + if (person2) { + xmlobject pname2 = person2.getObject("PersonName"); + + string pids2; + person.getObjectString("PersonId", pids2); + const __int64 extId2 = oBase::converExtIdentifierString(pids2); + int pid2 = oBase::idFromExtId(extId2); + pRunner r2 = getRunner(pid2, 0); + + if (!r2) { + if ( pid2 > 0) { + oRunner or(this, pid2); + r2 = addRunner(or, true); + } + else { + oRunner or(this); + r2 = addRunner(or, true); + } + } + + string given2, family2; + if (pname2) { + pname2.getObjectString("Given", given2); + pname2.getObjectString("Family", family2); + r2->setName(family2 + ", " + getFirst(given2, 2), false); + } + + r2->setExtIdentifier(pid2); + // Create patrol + + if (r->Class) { + + bool createTeam = false; + pClass pc = r->Class; + if (pc->getNumStages() <= 1) { + setupRelay(*pc, PPatrolOptional, 2, getAbsTime(3600)); + createTeam = true; + } + + pTeam t = r->tInTeam; + if (t == 0) + t = r2->tInTeam; + + if (t == 0) { + autoAddTeam(r); + t = r2->tInTeam; + createTeam = true; + } + + if (t != 0) { + if (t->getRunner(0) == r2) { + t->setRunner(0, r2, true); + t->setRunner(1, r, true); + } + else { + t->setRunner(0, r, true); + t->setRunner(1, r2, true); + } + } + + if (createTeam && t && !t->hasFlag(oAbstractRunner::FlagUpdateName)) { + t->setName(given + " / " + given2, false); + } + } + } + } + else { + if (r->Class && r->Class->getNumStages()>=2) { + autoAddTeam(r); + } + } + return r; +} + + +pRunner oEvent::addXMLStart(const xmlobject &xstart, pClass cls) { + + if (!xstart) return 0; + + xmlobject person_ = xstart.getObject("Person"); + if (!person_) return 0; + + pRunner r = addXMLPerson(person_); + pClass oldClass = r->Class; + pClub oldClub = r->Club; + r->Class = cls; + + xmlobject xclub = xstart.getObject("Club"); + int clubId = xstart.getObjectInt("ClubId"); + string cname; + if (xclub) { + clubId = xclub.getObjectInt("ClubId"); + xclub.getObjectString("ShortName", cname); + } + + if (clubId > 0) { + r->Club = getClubCreate(clubId, cname); + } + + xmlobject xstrt = xstart.getObject("Start"); + + if (!xstrt) + return r; + + oDataInterface DI=r->getDI(); + + int cardno = xstrt.getObjectInt("CCardId"); + + if (cardno == 0) { + xmlList cards; + xstrt.getObjects("CCard", cards); + string tmp; + for (size_t k= 0; ksetCardNo(cardno, false); + break; + } + } + } + } + else + r->setCardNo(cardno, false); + + string tmp; + xmlobject xstarttime = xstrt.getObject("StartTime"); + if (xstarttime) + r->setStartTimeS(xstarttime.getObjectString("Clock", tmp)); + + if (oldClass != r->Class || oldClub != r->Club) + r->updateChanged(); + + r->addClassDefaultFee(false); + r->synchronize(); + + if (r->Class && r->Class->getNumStages()>=2) { + autoAddTeam(r); + } + return r; +} + +bool addXMLPerson(const xmlobject &xentry, oWordList &givenNames, + oWordList &familyNames) { + if (!xentry) return false; + + xmlobject person=xentry.getObject("Person"); + if (!person) return false; + + xmlobject pname=person.getObject("PersonName"); + if (!pname) return false; + + char bf[256]; + givenNames.insert(pname.getObjectString("Given", bf, sizeof(bf))); + familyNames.insert(pname.getObjectString("Family", bf, sizeof(bf))); + + return true; +} + +void importXMLNames(const xmlobject &xml, oWordList &givenNames, + oWordList &familyNames) +{ + if (!xml) + return; + + xmlobject xo = xml.getObject("CompetitorList"); + + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Competitor")){ + addXMLPerson(*it, givenNames, familyNames); + } + } + } +} + +void addXMLClub(const xmlobject *xclub, oWordList &clubs) +{ + if (!xclub) + return; + + + string Name; + xclub->getObjectString("Name", Name); + + if (Name.empty() || !IsCharAlphaNumeric(Name[0])) + return; + + clubs.insert(Name.c_str()); + return; +} + +void importXMLAllClubs(const xmlobject &xml, oWordList &clubs) +{ + if (!xml) + return; + xmlobject xo=xml.getObject("ClubList"); + + if (xo){ + xmlList xl; + xo.getObjects(xl); + + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Club")){ + addXMLClub(&*it, clubs); + } + } + } +} + +bool oEvent::importXMLNames(const char *file, + oFreeImport &fi, string &info) const +{ + xmlparser xml(0); + info.clear(); + DWORD tc=GetTickCount(), t; + + xml.read(file); + char bf[128]; + t=GetTickCount()-tc; + sprintf_s(bf, "XML read: %d.%ds ", t/1000, (t/100)%10); + info+=bf; + tc=GetTickCount(); + if (xml.getObject("meosdata")) { + oEvent oNew(gdibase); + oNew.open(xml); + + fi.init(oNew.Runners, oNew.Clubs, oNew.Classes); + } + else { + ::importXMLNames(xml.getObject("CompetitorList"), fi.givenDB, fi.familyDB); + ::importXMLAllClubs(xml.getObject("ClubList"), fi.clubDB); + } + + t=GetTickCount()-tc; + sprintf_s(bf, "Import: %d.%ds ", t/1000, (t/100)%10); + info+=bf; + + return true; +} + +void oEvent::importOECSV_Data(const char *oecsvfile, bool clear) { + // Clear DB if needed + if (clear) { + runnerDB->clearClubs(); + runnerDB->clearRunners(); + } + + csvparser cp; + list< vector > data; + + gdibase.addString("",0,"Läser löpare..."); + gdibase.refresh(); + + cp.parse(oecsvfile, data); + + gdibase.addString("", 0, "Behandlar löpardatabasen").setColor(colorGreen); + + gdibase.refresh(); + + list>::iterator it; + + for (it = ++(data.begin()); it != data.end(); ++it) { + addOECSVCompetitorDB(*it); + } + + gdibase.addString("", 0, "Klart. Antal importerade: X#" + itos(data.size())); + gdibase.refresh(); + + setProperty("DatabaseUpdate", getRelativeDay()); + + // Save DB + saveRunnerDatabase("database", true); + + if (HasDBConnection) { + gdibase.addString("", 0, "Uppdaterar serverns databas..."); + gdibase.refresh(); + + OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this); + + if (stat == opStatusFail) { + char bf[256]; + msGetErrorState(bf); + string error = string("Kunde inte ladda upp löpardatabasen (X).#") + bf; + throw meosException(error); + } + else if (stat == opStatusWarning) { + char bf[256]; + msGetErrorState(bf); + gdibase.addInfoBox("", string("Kunde inte ladda upp löpardatabasen (X).#") + bf, 5000); + } + + gdibase.addString("", 0, "Klart"); + gdibase.refresh(); + } +} + +void oEvent::importXML_IOF_Data(const char *clubfile, + const char *competitorfile, bool clear) +{ + if (clubfile && clubfile[0]) { + xmlparser xml_club(0); + xml_club.setProgress(gdibase.getHWND()); + + if (clear) + runnerDB->clearClubs(); + + gdibase.addString("",0,"Läser klubbar..."); + gdibase.refresh(); + + xml_club.read(clubfile); + + gdibase.addString("",0,"Lägger till klubbar..."); + gdibase.refresh(); + + xmlobject xo = xml_club.getObject("ClubList"); + int clubCount = 0; + + if (!xo) { + xo = xml_club.getObject("OrganisationList"); + if (xo) { + IOF30Interface reader(this, false); + reader.readClubList(gdibase, xo, clubCount); + } + } + else { + xmlList xl; + if (xo) + xo.getObjects(xl); + + xmlList::const_iterator it; + for (it=xl.begin(); it != xl.end(); ++it) + if (it->is("Club")) { + if (addXMLClub(*it, true)) + clubCount++; + } + } + gdibase.addStringUT(0, lang.tl("Antal importerade: ") + itos(clubCount)); + } + + if (competitorfile && competitorfile[0]) { + xmlparser xml_cmp(0); + xml_cmp.setProgress(gdibase.getHWND()); + gdibase.dropLine(); + gdibase.addString("",0,"Läser löpare..."); + gdibase.refresh(); + + xml_cmp.read(competitorfile); + + if (clear) { + runnerDB->clearRunners(); + } + + gdibase.addString("",0,"Lägger till löpare..."); + gdibase.refresh(); + + int personCount = 0; + xmlobject xo=xml_cmp.getObject("CompetitorList"); + + if (xo && xo.getAttrib("iofVersion")) { + IOF30Interface reader(this, false); + reader.readCompetitorList(gdibase, xo, personCount); + } + else { + xmlList xl; + if (xo) + xo.getObjects(xl); + + xmlList::const_iterator it; + + for (it=xl.begin(); it != xl.end(); ++it) { + if (it->is("Competitor")){ + int ClubId=it->getObjectInt("ClubId"); + if (addXMLCompetitorDB(*it, ClubId)) + personCount++; + } + } + } + + gdibase.addStringUT(0, lang.tl("Antal importerade: ") + itos(personCount)); + gdibase.refresh(); + + setProperty("DatabaseUpdate", getRelativeDay()); + } + + saveRunnerDatabase("database", true); + + if (HasDBConnection) { + gdibase.addString("", 0, "Uppdaterar serverns databas..."); + gdibase.refresh(); + + //msUploadRunnerDB(this); + + OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this); + + if (stat == opStatusFail) { + char bf[256]; + msGetErrorState(bf); + string error = string("Kunde inte ladda upp löpardatabasen (X).#") + bf; + throw meosException(error); + } + else if (stat == opStatusWarning) { + char bf[256]; + msGetErrorState(bf); + gdibase.addInfoBox("", string("Kunde inte ladda upp löpardatabasen (X).#") + bf, 5000); + } + + gdibase.addString("", 0, "Klart"); + gdibase.refresh(); + } +} + + +/* + + 6 + D18 Elit + D18 Elit + E + + 600 + + + 600 + + + A + Adult + 65 + + + 2001-10-18 + + +*/ + +bool oEvent::addXMLEvent(const xmlobject &xevent) +{ + if (!xevent) + return false; + + int id = xevent.getObjectInt("EventId"); + string name; + xevent.getObjectString("Name", name); + + xmlobject date = xevent.getObject("StartDate"); + + if (id>0) + setExtIdentifier(id); + + setName(name); + + if (date) { + string dateStr; + date.getObjectString("Date", dateStr); + setDate(dateStr); + } + + synchronize(); + return true; +} + +/* + + Bana 02 + 1 + D21E + + 0 + 8500 + 0 + S1 + + + 1 + 104 + 310 + + + + 2 + 102 + 360 + + + M1 + 157 + + + +*/ +int getLength(const xmlobject &xlen) { + if (xlen.isnull()) + return 0; + return xlen.getInt(); +} + +int getStartIndex(int sn) { + return sn + 211100; +} + +int getFinishIndex(int sn) { + return sn + 311100; +} + +string getStartName(const string &start) { + int num = getNumberSuffix(start); + if (num == 0 && start.length()>0) + num = int(start[start.length()-1])-'0'; + if (num > 0 && num < 10) + return lang.tl("Start ") + itos(num); + else if (start.length() == 1) + return lang.tl("Start"); + else + return start; +} +/* + + 120 + + +*/ +bool oEvent::addXMLControl(const xmlobject &xcontrol, int type) +{ + // type: 0 control, 1 start, 2 finish + if (!xcontrol) + return false; + + xmlobject pos = xcontrol.getObject("MapPosition"); + + int xp = 0, yp = 0; + if (pos) { + string x,y; + pos.getObjectString("x", x); + pos.getObjectString("y", y); + xp = int(10.0 * atof(x.c_str())); + yp = int(10.0 * atof(y.c_str())); + } + + if (type == 0) { + int code = xcontrol.getObjectInt("ControlCode"); + if (code>=30 && code<1024) { + pControl pc = getControl(code, true); + pc->getDI().setInt("xpos", xp); + pc->getDI().setInt("ypos", yp); + pc->synchronize(); + } + } + else if (type == 1) { + string start; + xcontrol.getObjectString("StartPointCode", start); + start = getStartName(trim(start)); + int num = getNumberSuffix(start); + if (num == 0 && start.length()>0) + num = int(start[start.length()-1])-'0'; + pControl pc = getControl(getStartIndex(num), true); + pc->setNumbers(""); + pc->setName(start); + pc->setStatus(oControl::StatusStart); + pc->getDI().setInt("xpos", xp); + pc->getDI().setInt("ypos", yp); + } + else if (type == 2) { + string finish; + xcontrol.getObjectString("FinishPointCode", finish); + finish = trim(finish); + int num = getNumberSuffix(finish); + if (num == 0 && finish.length()>0) + num = int(finish[finish.length()-1])-'0'; + if (num > 0) + finish = lang.tl("Mål ") + itos(num); + pControl pc = getControl(getFinishIndex(num), true); + pc->setNumbers(""); + pc->setName(finish); + pc->setStatus(oControl::StatusFinish); + pc->getDI().setInt("xpos", xp); + pc->getDI().setInt("ypos", yp); + } + + return true; +} + +bool oEvent::addXMLCourse(const xmlobject &xcrs, bool addClasses) +{ + if (!xcrs) + return false; + + int cid = xcrs.getObjectInt("CourseId"); + + string name; + xcrs.getObjectString("CourseName", name); + name = trim(name); + vector cls; + xmlList obj; + xcrs.getObjects("ClassShortName", obj); + for (size_t k = 0; k courses; + xcrs.getObjects("CourseVariation", obj); + for (size_t k = 0; k ctrlCode(ctrl.size()); + vector legLen(ctrl.size()); + for (size_t i = 0; i0 && seq<=ctrl.size()) + index = seq-1; + + ctrlCode[index] = ctrl[i].getObjectInt("ControlCode"); + legLen[index] = getLength(ctrl[i].getObject("LegLength")); + } + + legLen.push_back(getLength(obj[k].getObject("DistanceToFinish"))); + int actualId = ((cid+1)*100) + variationId; + string cname=name; + if (!varName.empty()) + cname += " " + varName; + else if (obj.size() > 1) + cname += " " + itos(k+1); + + pCourse pc = 0; + if (cid > 0) + pc = getCourseCreate(actualId); + else { + pc = getCourse(cname); + if (pc == 0) + pc = addCourse(cname); + } + + pc->setName(cname); + pc->setLength(len); + pc->importControls("", false); + for (size_t i = 0; i30 && ctrlCode[i]<1000) + pc->addControl(ctrlCode[i]); + } + if (pc->getNumControls() + 1 == legLen.size()) + pc->setLegLengths(legLen); + pc->getDI().setInt("Climb", climb); + pc->setStart(start, true); + pc->synchronize(); + + string finish; + obj[k].getObjectString("FinishPointCode", finish); + finish = trim(finish); + + pc->synchronize(); + + courses.push_back(pc); + } + + if (addClasses) { + for (size_t k = 0; kgetNumStages()==0) { + pCls->setCourse(courses[0]); + } + else { + for (size_t i = 0; igetNumStages(); i++) + pCls->addStageCourse(i, courses[0]->getId()); + } + } + else { + if (courses.size() == pCls->getNumStages()) { + for (size_t i = 0; iaddStageCourse(i, courses[i]->getId()); + } + else { + for (size_t i = 0; iaddStageCourse(0, courses[i]->getId()); + } + } + } + } + } + + return true; +} + + +bool oEvent::addXMLClass(const xmlobject &xclass) +{ + if (!xclass) + return false; + + int classid=xclass.getObjectInt("ClassId"); + string name, shortName; + xclass.getObjectString("Name", name); + xclass.getObjectString("ClassShortName", shortName); + + if (!shortName.empty()) + name = shortName; + + pClass pc=0; + + if (classid) { + pc = getClass(classid); + + if (!pc) { + oClass c(this, classid); + pc = addClass(c); + } + } + else + pc = addClass(name); + + pc->setName(name); + oDataInterface DI=pc->getDI(); + + string tmp; + DI.setInt("LowAge", xclass.getObjectInt("lowAge")); + DI.setInt("HighAge", xclass.getObjectInt("highAge")); + DI.setString("Sex", xclass.getObjectString("sex", tmp)); + DI.setString("ClassType", xclass.getObjectString("ClassTypeId", tmp)); + + xmlList xFee; + xclass.getObjects("EntryFee", xFee); + vector fee; + for (size_t k = 0; k0) { + fee.push_back(oe->interpretCurrency(f, cur)); + } + } + } + + // XXX Eventor studpid hack + if (fee.size() == 2 && fee[1]synchronize(); + return true; +} + + +bool oEvent::addXMLClub(const xmlobject &xclub, bool savetoDB) +{ + if (!xclub) + return false; + + int clubid=xclub.getObjectInt("ClubId"); + string Name, shortName; + xclub.getObjectString("Name", Name); + xclub.getObjectString("ShortName", shortName); + + if (!shortName.empty() && shortName.length() < Name.length()) + swap(Name, shortName); + + int district = xclub.getObjectInt("OrganisationId"); + + if (Name.length()==0 || !IsCharAlphaNumeric(Name[0])) + return false; + + xmlobject address=xclub.getObject("Address"); + + string str; + string co; + + if (address) { + address.getObjectString("street", str).length(); + address.getObjectString("careOf", co).length(); + } + + pClub pc=0; + + if ( !savetoDB ) { + if (clubid) + pc = getClubCreate(clubid, Name); + + if (!pc) return false; + } + else { + pc = new oClub(this); + pc->Id = clubid; + } + + pc->setName(Name); + + pc->setExtIdentifier(clubid); + + oDataInterface DI=pc->getDI(); + + string tmp; + DI.setString("CareOf", co); + DI.setString("Street", str); + if (address) { + DI.setString("City", address.getObjectString("city", tmp)); + DI.setString("ZIP", address.getObjectString("zipCode", tmp)); + } + DI.setInt("District", district); + + xmlobject tele=xclub.getObject("Tele"); + + if (tele){ + DI.setString("EMail", tele.getObjectString("mailAddress", tmp)); + DI.setString("Phone", tele.getObjectString("phoneNumber", tmp)); + } + + xmlobject country=xclub.getObject("Country"); + + if (country) { + xmlobject natId = country.getObject("CountryId"); + char national[4]; + if (natId) + DI.setString("Nationality", natId.getObjectString("value", national, 4)); + } + + if (savetoDB) { + runnerDB->importClub(*pc, false); + delete pc; + } + else { + pc->synchronize(); + } + + return true; +} + + +bool oEvent::addXMLRank(const xmlobject &xrank, map<__int64, int> &externIdToRunnerId) +{ + if (!xrank) + return false; + + xmlobject person;//xrank->getObject("Person"); + xmlobject club;//xrank->getObject("Club"); + xmlobject rank; + xmlobject vrank; + + xmlList x; + xrank.getObjects(x); + + xmlList::const_iterator cit=x.begin(); + + string tmp; + while(cit!=x.end()){ + + if (cit->is("Person")) + person=*cit; + else if (cit->is("Club")) + club=*cit; + else if (cit->is("Rank")){ + if (cit->getObjectString("Name", tmp)=="Swedish Ranking List") + rank=*cit; + else if (cit->getObjectString("Name", tmp)=="Swedish Vacancy List") + vrank=*cit; + } + ++cit; + } + + if (!person) return false; + + string pid; + person.getObjectString("PersonId", pid); + const __int64 extId = oBase::converExtIdentifierString(pid); + int id = oBase::idFromExtId(extId); + if (externIdToRunnerId.count(extId)) + id = externIdToRunnerId[extId]; + + pRunner r = getRunner(id, 0); + + if (!r){ + xmlobject pname = person.getObject("PersonName"); + + if (!pname) return false; + + string given, family; + string name=getFirst(pname.getObjectString("Given", given), 2)+" "+pname.getObjectString("Family", family); + + if (!club) + r=getRunnerByName(name); + else { + string cn, cns; + club.getObjectString("ShortName", cns); + club.getObjectString("Name", cn); + + if (cns.empty()) + cns = cn; + + if (!cn.empty() && cn.length()getDI(); + + if (rank) + DI.setInt("Rank", rank.getObjectInt("RankPosition")); + +// if (vrank) +// DI.setInt("VacRank", vrank.getObjectInt("RankPosition")); + + r->synchronize(); + + return true; +} + +void oEvent::exportIOFEventList(xmlparser &xml) +{ + xml.startTag("EventList"); + xml.write("IOFVersion", "version", "2.0.3"); + + exportIOFEvent(xml); + + xml.endTag(); //EventList +} + +void oEvent::exportIOFEvent(xmlparser &xml) +{ + // (IndSingleDay|IndMultiDay|teamSingleDay|teamMultiDay|relay) + xml.startTag("Event", "eventForm", "IndSingleDay"); + + xml.write("EventId", getExtIdentifierString()); + xml.write("Name", getName()); + + xml.write("EventClassificationId", "type", "other", "MeOS"); + + { + xml.startTag("StartDate"); + xml.write("Date", "dateFormat", "YYYY-MM-DD", getDate()); + xml.write("Clock", "clockFormat", "HH:MM:SS", getZeroTime()); + xml.endTag(); // StartDate + } + + string url = getDCI().getString("Homepage"); + if (!url.empty()) + xml.write("WebURL", url); + + string account = getDCI().getString("Account"); + if (!account.empty()) + xml.write("Account", "type", "other", account); + + xml.endTag(); //Event +} + +void oEvent::exportIOFClass(xmlparser &xml) +{ + xml.startTag("ClassData"); + + set cls; + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + if (!it->getType().empty()) + cls.insert(it->getType()); + } + + int id = 1; + map idMap; + for (set::iterator it = cls.begin(); it != cls.end(); ++it) { + xml.startTag("ClassType"); + idMap[*it] = id; + xml.write("ClassTypeId", id++); + xml.write("Name", *it); + xml.endTag(); + } + + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + vector pv; + + pClass pc = &*it; + int low = 0; + int high = 0; + pc->getAgeLimit(low, high); + + if (low>0) { + pv.push_back("lowAge"); + pv.push_back(itos(low)); + } + if (high>0) { + pv.push_back("highAge"); + pv.push_back(itos(high)); + } + + string sex = encodeSex(pc->getSex()); + if (sex.empty()) + sex = "B"; + + pv.push_back("sex"); + pv.push_back(sex); + + if (pc->getNumStages()>1) { + pv.push_back("numberInTeam"); + pv.push_back(itos(pc->getNumStages())); + } + + if (pc->getClassType() == oClassRelay) { + pv.push_back("teamEntry"); + pv.push_back("Y"); + } + + if (pc->getNoTiming()) { + pv.push_back("timePresentation"); + pv.push_back("N"); + } + + xml.startTag("Class", pv); + + xml.write("ClassId", itos(pc->getId())); + + xml.write("ClassShortName", pc->getName()); + + if (!pc->getType().empty()) + xml.write("ClassTypeId", itos(idMap[pc->getType()])); + + xml.endTag(); + } + xml.endTag(); +} + +void oEvent::exportIOFClublist(xmlparser &xml) +{ + xml.startTag("ClubList"); + xml.write("IOFVersion", "version", "2.0.3"); + + for (oClubList::iterator it = Clubs.begin(); it!=Clubs.end(); ++it) { + it->exportIOFClub(xml, true); + } + + xml.endTag(); +} + +void cWrite(xmlparser &xml, const char *tag, const string &value) { + if (!value.empty()) { + xml.write(tag, value); + } +} + +void oClub::exportClubOrId(xmlparser &xml) const +{ + if (getExtIdentifier() != 0) + xml.write("ClubId", getExtIdentifierString()); + else { + exportIOFClub(xml, true); + } +} + +void oClub::exportIOFClub(xmlparser &xml, bool compact) const +{ + xml.startTag("Club"); + if (getExtIdentifier() != 0) + xml.write("ClubId", getExtIdentifierString()); + else + xml.write("ClubId"); + + xml.write("ShortName", getName()); + + if (compact) { + xml.endTag(); + return; + } + + string country = getDCI().getString("Nationality"); + if (!country.empty()) + xml.write("CountryId", "value", country); + + int district = getDCI().getInt("District"); + if (district>0) + xml.write("OrganisationId", itos(district)); + + vector pv; + + // Address + string co = getDCI().getString("CareOf"); + string street = getDCI().getString("Street"); + string city = getDCI().getString("City"); + string zip = getDCI().getString("ZIP"); + + if (!co.empty()) { + pv.push_back("careOf"); + pv.push_back(co); + } + if (!street.empty()) { + pv.push_back("street"); + pv.push_back(street); + } + if (!city.empty()) { + pv.push_back("city"); + pv.push_back(city); + } + if (!zip.empty()) { + pv.push_back("zipCode"); + pv.push_back(zip); + } + if (!pv.empty()) { + xml.startTag("Address", pv); + xml.endTag(); + } + pv.clear(); + + //Tele + string mail = getDCI().getString("EMail"); + string phone = getDCI().getString("Phone"); + + if (!mail.empty()) { + pv.push_back("mailAddress"); + pv.push_back(mail); + } + if (!phone.empty()) { + pv.push_back("phoneNumber"); + pv.push_back(phone); + } + if (!pv.empty()) { + xml.startTag("Tele", pv); + xml.endTag(); + } + + //Club + xml.endTag(); +} + +void oEvent::exportIOFStartlist(xmlparser &xml) +{ + xml.startTag("StartList"); + xml.write("IOFVersion", "version", "2.0.3"); + + exportIOFEvent(xml); + + for (oClassList::iterator it = Classes.begin(); it!=Classes.end(); ++it) { + xml.startTag("ClassStart"); + //xml.write("ClassId", itos(it->getId())); + xml.write("ClassShortName", it->getName()); + it->exportIOFStart(xml); + xml.endTag(); + } + xml.endTag(); +} + +void oClass::exportIOFStart(xmlparser &xml) { + bool useEventor = oe->getPropertyInt("UseEventor", 0) == 1; + + if (getClassType() == oClassIndividual || getClassType() == oClassIndividRelay) { + for (oRunnerList::iterator it = oe->Runners.begin(); it!=oe->Runners.end(); ++it) { + if (it->getClassId() != getId() || it->isRemoved()) + continue; + + xml.startTag("PersonStart"); + + it->exportIOFRunner(xml, true); + + if (it->getClubId()>0) + it->Club->exportClubOrId(xml); + + int rank = it->getDCI().getInt("Rank"); + if (rank>0) { + //Ranking + xml.startTag("Rank"); + xml.write("Name", "MeOS"); + xml.write("RankPosition", itos(rank)); + xml.write("RankValue", itos(rank)); + xml.endTag(); + } + + int multi = it->getNumMulti(); + if (multi==0) + it->exportIOFStart(xml); + else { + xml.startTag("RaceStart"); + xml.write("EventRaceId", "1"); + it->exportIOFStart(xml); + xml.endTag(); + for (int k = 0; k < multi; k++) { + pRunner r = it->getMultiRunner(k+1); + if (r) { + xml.startTag("RaceStart"); + xml.write("EventRaceId", itos(k+2)); + r->exportIOFStart(xml); + xml.endTag(); + } + } + } + xml.endTag(); + } + } + else if (getClassType() == oClassRelay || getClassType() == oClassPatrol) { + + // A bug in Eventor / OLA results in an internal error if a patrol has a team name. + // Set writeTeamName to true (or remove) when this bug is fixed. + bool writeTeamName = !useEventor || getClassType() != oClassPatrol; + + for (oTeamList::iterator it = oe->Teams.begin(); it!=oe->Teams.end(); ++it) { + if (it->getClassId() != getId() || it->isRemoved()) + continue; + + xml.startTag("TeamStart"); + + if (writeTeamName) + xml.write("TeamName", it->getName()); + + string nat = it->getDCI().getString("Nationality"); + if (!nat.empty()) + xml.write("CountryId", "value", nat); + + for (size_t k=0; kRunners.size(); k++) { + if (it->Runners[k]) { + xml.startTag("PersonStart"); + + pRunner parent = it->Runners[k]->getMultiRunner(0); + if (parent != 0) + parent->exportIOFRunner(xml, true); + + if (it->Runners[k]->getClubId()>0) { + it->Runners[k]->Club->exportClubOrId(xml); + } + else if (it->getClubId()>0) { + it->Club->exportClubOrId(xml); + } + + it->Runners[k]->exportIOFStart(xml); + xml.endTag(); + } + } + + xml.endTag(); + } + } +} + +void oRunner::exportIOFStart(xmlparser &xml) +{ + xml.startTag("Start"); + int sno = getStartNo(); + if (sno>0) + xml.write("StartNumber", itos(sno)); + + xml.startTag("StartTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", + formatTimeIOF(getStartTime(), oe->ZeroTime)); + xml.endTag(); + + string bib = getBib(); + if (!bib.empty()) + xml.write("BibNumber", bib); + + if (getCardNo() > 0) + xml.write("CCardId", itos(getCardNo())); + + int len = 0; + if (getCourse(false)) { + len = getCourse(false)->getLength(); + if (len>0) + xml.write("CourseLength", "unit", "m", itos(len)); + + string start = getCourse(false)->getStart(); + if (!start.empty()) + xml.write("StartId", max(1, getNumberSuffix(start))); + } + + if (tInTeam) { + xml.write("TeamSequence", itos(tLeg+1)); + } + + xml.endTag(); +} + +void oRunner::exportIOFRunner(xmlparser &xml, bool compact) +{ + string sex = encodeSex(getSex()); + + if (sex.length()==1) + xml.startTag("Person", "sex", sex); + else + xml.startTag("Person"); + + if (getExtIdentifier() != 0) + xml.write("PersonId", getExtIdentifierString()); + else + xml.write("PersonId"); + + xml.startTag("PersonName"); + xml.write("Family", getFamilyName()); + xml.write("Given", "sequence", "1", getGivenName()); + xml.endTag(); + + int year = getBirthYear(); + + if (year>0 && !compact) { + xml.startTag("BirthDate"); + xml.write("Date", "dateFormat", "YYYY", itos(extendYear(year))); + xml.endTag(); + } + + xml.endTag(); +} + +void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set &classes, int leg, bool oldStylePatol) +{ + vector dummy; + xml.startTag("ResultList"); + + xml.write("IOFVersion", "version", "2.0.3"); + + exportIOFEvent(xml); + + bool ClassStarted=false; + int Id=-1; + bool skipClass=false; + if (oldStylePatol) { + // OLD STYLE PATROL EXPORT + for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved()) + continue; + if (it->Runners.size()>=2 && it->Runners[0] && it->Runners[1]) { + if (it->getClassId()!=Id) { + if (ClassStarted) xml.endTag(); + + if (!it->Class || it->Class->getClassType()!=oClassPatrol) { + skipClass=true; + ClassStarted=false; + continue; + } + + if ((!classes.empty() && classes.count(it->getClassId()) == 0) || leg != -1) { + skipClass=true; + ClassStarted=false; + continue; + } + + skipClass=false; + xml.startTag("ClassResult"); + ClassStarted=true; + Id=it->getClassId(); + + xml.write("ClassShortName", it->getClass()); + } + + if (skipClass) + continue; + + xml.startTag("PersonResult"); + it->Runners[0]->exportIOFRunner(xml, true); + + xml.startTag("Club"); + xml.write("ClubId", 0); + xml.write("ShortName", it->Runners[1]->getName()); + xml.write("CountryId", "value", it->getDI().getString("Nationality")); + xml.endTag(); + + xml.startTag("Result"); + xml.startTag("StartTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(it->getStartTime(), ZeroTime)); + xml.endTag(); + xml.startTag("FinishTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(it->getLegFinishTime(-1), ZeroTime)); + xml.endTag(); + + xml.write("Time", "timeFormat", "HH:MM:SS", formatTimeIOF(it->getLegRunningTime(-1, false), 0)); + xml.write("ResultPosition", it->getLegPlaceS(-1, false)); + + xml.write("CompetitorStatus", "value", it->Runners[0]->getIOFStatusS()); + + const vector &sp=it->Runners[0]->getSplitTimes(true); + + pCourse pc=it->Runners[0]->getCourse(false); + if (pc) xml.write("CourseLength", "unit", "m", pc->getLengthS()); + + pCourse pcourse=pc; + if (pcourse && it->getLegStatus(-1, false)>0 && it->getLegStatus(-1, false)!=StatusDNS) { + int no = 1; + bool hasRogaining = pcourse->hasRogaining(); + int startIx = pcourse->useFirstAsStart() ? 1 : 0; + int endIx = pcourse->useLastAsFinish() ? pcourse->nControls - 1 : pcourse->nControls; + for (int k=startIx;kControls[k]->isRogaining(hasRogaining)) + continue; + xml.startTag("SplitTime", "sequence", itos(no++)); + xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber()); + if (unsigned(k)0) + xml.write("Time", "clockFormat", "HH:MM:SS", getAbsTime((sp[k].time-it->tStartTime)-ZeroTime)); + else + xml.write("Time", "--:--:--"); + + xml.endTag(); + } + } + xml.endTag(); + xml.endTag(); + } + } + + if (ClassStarted) { + xml.endTag(); + ClassStarted = false; + } + } + // OldStylePatrol + + if (leg == -1) + exportTeamSplits(xml, classes, oldStylePatol); + + skipClass=false; + Id=-1; + + for (oRunnerList::iterator it=Runners.begin(); + it != Runners.end(); ++it) { + + if (it->isRemoved() || (leg != -1 && it->tLeg != leg) || it->isVacant()) + continue; + + if (it->getClassId()!=Id) { + if (ClassStarted) xml.endTag(); + + if (!it->Class) { + skipClass=true; + ClassStarted=false; + continue; + } + + ClassType ct = it->Class->getClassType(); + + if (leg == -1 && (ct == oClassPatrol || ct ==oClassRelay || ct == oClassIndividRelay) ) { + skipClass=true; + ClassStarted=false; + continue; + } + + if ( (!classes.empty() && classes.count(it->getClassId()) == 0) ) { + skipClass=true; + ClassStarted=false; + continue; + } + + xml.startTag("ClassResult"); + ClassStarted=true; + skipClass=false; + Id=it->getClassId(); + + xml.write("ClassShortName", it->getClass()); + } + + if (skipClass) + continue; + + xml.startTag("PersonResult"); + + it->exportIOFRunner(xml, true); + + if (it->Club) + it->Club->exportIOFClub(xml, true); + + xml.startTag("Result"); + xml.startTag("CCard"); + xml.write("CCardId", it->getCardNo()); + xml.endTag(); + xml.startTag("StartTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(it->getStartTime(), ZeroTime)); + xml.endTag(); + xml.startTag("FinishTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(it->getFinishTimeAdjusted(), ZeroTime)); + xml.endTag(); + + xml.write("Time", "timeFormat", "HH:MM:SS", formatTimeIOF(it->getRunningTime(),0)); + xml.write("ResultPosition", it->getPlaceS()); + + xml.write("CompetitorStatus", "value", it->getIOFStatusS()); + + const vector &sp=it->getSplitTimes(true); + pCourse pc=it->getCourse(false); + if (pc) xml.write("CourseLength", "unit", "m", pc->getLengthS()); + + pCourse pcourse=it->getCourse(true); + if (pcourse && it->getStatus()>0 && it->getStatus()!=StatusDNS + && it->getStatus()!=StatusNotCompetiting) { + bool hasRogaining = pcourse->hasRogaining(); + int no = 1; + int startIx = pcourse->useFirstAsStart() ? 1 : 0; + int endIx = pcourse->useLastAsFinish() ? pcourse->nControls - 1 : pcourse->nControls; + for (int k=startIx;kControls[k]->isRogaining(hasRogaining)) + continue; + xml.startTag("SplitTime", "sequence", itos(no++)); + xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber()); + if (unsigned(k)0) + xml.write("Time", "timeFormat", "HH:MM:SS", getAbsTime((sp[k].time-it->tStartTime)-ZeroTime)); + else + xml.write("Time", "--:--:--"); + + xml.endTag(); + } + } + xml.endTag(); + xml.endTag(); + } + + if (ClassStarted) { + xml.endTag(); + ClassStarted = false; + } + + xml.endTag(); +} + +void oEvent::exportTeamSplits(xmlparser &xml, const set &classes, bool oldStylePatrol) +{ + vector dummy; + bool ClassStarted=false; + int Id=-1; + bool skipClass=false; + + sortTeams(ClassResult, -1, true); + for(oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved()) + continue; + if (it->getClassId()!=Id) { + if (ClassStarted) { + xml.endTag(); + ClassStarted = false; + } + + if (!it->Class) { + skipClass=true; + continue; + } + + ClassType ct = it->Class->getClassType(); + + if (oldStylePatrol && ct == oClassPatrol) { + skipClass=true; + continue; + } + + if (ct != oClassRelay && ct != oClassIndividRelay && ct != oClassPatrol) { + skipClass=true; + continue; + } + + if (!classes.empty() && classes.count(it->getClassId()) == 0) { + skipClass=true; + continue; + } + + skipClass=false; + xml.startTag("ClassResult"); + ClassStarted=true; + Id=it->getClassId(); + + xml.write("ClassShortName", it->getClass()); + } + + if (skipClass) + continue; + + xml.startTag("TeamResult"); { + /* + Sundsvalls OK + + + 10:00:00 + + + 11:45:52 + + + 1 + + */ + string nat = it->getDCI().getString("Nationality"); + if (!nat.empty()) + xml.write("CountryId", "value", nat); + + xml.write("TeamName", it->getName()); + xml.write("BibNumber", it->getStartNo()); + + xml.startTag("StartTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(it->getStartTime(), ZeroTime)); + xml.endTag(); + xml.startTag("FinishTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(it->getFinishTimeAdjusted(), ZeroTime)); + xml.endTag(); + + xml.write("Time", "timeFormat", "HH:MM:SS", formatTimeIOF(it->getRunningTime(), 0)); + xml.write("ResultPosition", it->getPlaceS()); + xml.write("TeamStatus", "value", it->getIOFStatusS()); + + for (size_t k=0;kRunners.size();k++) { + if (!it->Runners[k]) + continue; + pRunner r=it->Runners[k]; + + xml.startTag("PersonResult"); { + + r->exportIOFRunner(xml, true); + + if (r->Club) + r->Club->exportIOFClub(xml, true); + + xml.startTag("Result"); { + xml.write("TeamSequence", k+1); + xml.startTag("StartTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(r->getStartTime(), ZeroTime)); + xml.endTag(); + xml.startTag("FinishTime"); + xml.write("Clock", "clockFormat", "HH:MM:SS", formatTimeIOF(r->getFinishTimeAdjusted(), ZeroTime)); + xml.endTag(); + + xml.write("Time", "timeFormat", "HH:MM:SS", formatTimeIOF(r->getRunningTime(), 0)); + xml.write("ResultPosition", r->getPlaceS()); + + xml.write("CompetitorStatus", "value", r->getIOFStatusS()); + + const vector &sp = r->getSplitTimes(true); + + pCourse pc=r->getCourse(false); + + if (pc) { + xml.startTag("CourseVariation"); + xml.write("CourseVariationId", pc->getId()); + xml.write("CourseLength", "unit", "m", pc->getLengthS()); + xml.endTag(); + } + pCourse pcourse=pc; + if (pcourse && r->getStatus()>0 && r->getStatus()!=StatusDNS + && r->getStatus()!=StatusNotCompetiting) { + int no = 1; + bool hasRogaining = pcourse->hasRogaining(); + int startIx = pcourse->useFirstAsStart() ? 1 : 0; + int endIx = pcourse->useLastAsFinish() ? pcourse->nControls - 1 : pcourse->nControls; + for (int k=startIx;kControls[k]->isRogaining(hasRogaining)) + continue; + xml.startTag("SplitTime", "sequence", itos(no++)); + xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber()); + if (unsigned(k)0) + xml.write("Time", "clockFormat", "HH:MM:SS", getAbsTime((sp[k].time-r->tStartTime)-ZeroTime)); + else + xml.write("Time", "--:--:--"); + + xml.endTag(); + } //Loop over splits + } + } xml.endTag(); + } xml.endTag(); + } //Loop over team members + + } xml.endTag(); // Team result + } + + if (ClassStarted) { + xml.endTag(); + ClassStarted = false; + } + +} + +void oEvent::exportIOFSplits(IOFVersion version, const char *file, + bool oldStylePatrolExport, bool useUTC, + const set &classes, int leg, + bool teamsAsIndividual, bool unrollLoops, + bool includeStageInfo, bool forceSplitFee) { + xmlparser xml(gdibase.getEncoding() == ANSI ? 0 : &gdibase); + + xml.openOutput(file, false); + oClass::initClassId(*this); + reEvaluateAll(set(), true); + if (version != IOF20) + calculateResults(RTClassCourseResult); + calculateResults(RTTotalResult); + calculateResults(RTClassResult); + calculateTeamResults(true); + calculateTeamResults(false); + + if (version == IOF20) + exportIOFResults(xml, true, classes, leg, oldStylePatrolExport); + else { + IOF30Interface writer(this, forceSplitFee); + writer.writeResultList(xml, classes, leg, useUTC, + teamsAsIndividual, unrollLoops, includeStageInfo); + } + + xml.closeOut(); +} + +void oEvent::exportIOFStartlist(IOFVersion version, const char *file, bool useUTC, + const set &classes, bool teamsAsIndividual, + bool includeStageInfo, bool forceSplitFee) { + xmlparser xml(gdibase.getEncoding() == ANSI ? 0 : &gdibase); + + oClass::initClassId(*this); + xml.openOutput(file, false); + + if (version == IOF20) + exportIOFStartlist(xml); + else { + IOF30Interface writer(this, forceSplitFee); + writer.writeStartList(xml, classes, useUTC, teamsAsIndividual, includeStageInfo); + } + xml.closeOut(); +} diff --git a/code/oListInfo.cpp b/code/oListInfo.cpp new file mode 100644 index 0000000..6c7277a --- /dev/null +++ b/code/oListInfo.cpp @@ -0,0 +1,4240 @@ +/********************i**************************************************** + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "oListInfo.h" +#include "oEvent.h" +#include "gdioutput.h" +#include "meos_util.h" +#include +#include +#include "Localizer.h" +#include "metalist.h" +#include +#include "gdifonts.h" +#include "generalresult.h" +#include "meosexception.h" + +struct PrintPostInfo { + PrintPostInfo(gdioutput &gdi, const oListParam &par) : + gdi(gdi), par(par), keepToghether(false) {} + + gdioutput &gdi; + const oListParam ∥ + oCounter counter; + bool keepToghether; + void reset() {keepToghether = false;} +private: + PrintPostInfo &operator=(const PrintPostInfo &a) {} +}; + +oListInfo::oListInfo() { + listType=EBaseTypeRunner; + listSubType=EBaseTypeRunner; + calcResults=false; + calcTotalResults = false; + rogainingResults = false; + calcCourseClassResults = false; + listPostFilter.resize(_EFilterMax+1, 0); + listPostSubFilter.resize(_ESubFilterMax+1, 0); + fixedType = false; + largeSize = false; + supportClasses = true; + supportLegs = false; + supportParameter = false; + supportLarge = false; + supportTo = false; + supportFrom = false; + supportCustomTitle = true; + + resType = Classwise; + + supportSplitAnalysis = true; + supportInterResults = true; + supportPageBreak = true; + supportClassLimit = true; + + needPunches = false; +} + +oListInfo::~oListInfo(void) +{ +} + +oPrintPost::oPrintPost() +{ + dx=0; + dy=0; + format=0; + type=lString; + legIndex= - 1; + linearLegIndex = true; + fixedWidth = 0; + mergeWithTmp = 0; + doMergeNext = false; + color = colorDefault; + resultModuleIndex = -1; +} + +oPrintPost::oPrintPost(EPostType type_, const string &text_, + int format_, int dx_, int dy_, pair index) { + dx=dx_; + dy=dy_; + text=text_; + format=format_; + type=type_; + legIndex=index.first; + linearLegIndex = index.second; + fixedWidth = 0; + mergeWithTmp = 0; + doMergeNext = false; + color = colorDefault; + resultModuleIndex = -1; +} + +bool oListInfo::needRegenerate(const oEvent &oe) const { + for(oClassList::const_iterator it = oe.Classes.begin(); it != oe.Classes.end(); ++it) { + if (it->isRemoved()) + continue; + + if (!lp.selection.empty() && lp.selection.count(it->getId()) == 0 ) + continue; // Not our class + + int legToCheck = -1; + if (needPunches) { + int to = oControl::getIdIndexFromCourseControlId(lp.useControlIdResultTo).first; + int from = oControl::getIdIndexFromCourseControlId(lp.useControlIdResultFrom).first; + + if (it->wasSQLChanged(legToCheck, to) || + it->wasSQLChanged(legToCheck, from) ) + return true; + } + else { + if (it->wasSQLChanged(legToCheck, -1)) + return true; + } + } + + return false; +} + +static void generateNBestHead(const oListParam &par, oListInfo &li, int ypos) { + if (par.filterMaxPer > 0) + li.addHead(oPrintPost(lString, lang.tl("Visar de X bästa#" + itos(par.filterMaxPer)), normalText, 0, ypos)); +} + +static pair getControlName(const oEvent &oe, int courseContolId) { + pair idt = oControl::getIdIndexFromCourseControlId(courseContolId); + pControl to = oe.getControl(idt.first); + string toS; + bool name = false; + if (to) { + if (to->hasName()) { + toS = to->getName(); + name = true; + } + else if (to->getFirstNumber()>0) + toS = itos(to->getFirstNumber()); + else + toS = itos(idt.first); + + if (to->getNumberDuplicates() > 0) + toS += "-" + itos(idt.second + 1); + } + else + toS = itos(idt.first); + + return make_pair(toS, name); +} + +static string getFullControlName(const oEvent &oe, int ctrl) { + pair toS = getControlName(oe, ctrl); + if (toS.second) + return toS.first; + else + return lang.tl("Kontroll X#" + toS.first); +} + +static void getResultTitle(const oEvent &oe, const oListParam &lp, string &title) { + if (lp.useControlIdResultTo <= 0 && lp.useControlIdResultFrom <= 0) + title = lang.tl("Resultat - %s"); + else if (lp.useControlIdResultTo>0 && lp.useControlIdResultFrom<=0){ + pair toS = getControlName(oe, lp.useControlIdResultTo); + if (toS.second) + title = lang.tl("Resultat - %s") + ", " + toS.first; + else + title = lang.tl("Resultat - %s") + ", " + lang.tl("vid kontroll X#" + toS.first); + } + else { + string fromS = lang.tl("Start"), toS = lang.tl("Mål"); + if (lp.useControlIdResultTo>0) { + toS = getControlName(oe, lp.useControlIdResultTo).first; + } + if (lp.useControlIdResultFrom>0) { + fromS = getControlName(oe, lp.useControlIdResultFrom).first; + } + title = lang.tl("Resultat mellan X och Y#" + fromS + "#" + toS); + } +} + +static double adjustmentFactor(double par, double target) { + double k = (1.0 - target)/10; + double val = max(target, 1.0 - (par * k)); + return val; +} + +int oListInfo::getMaxCharWidth(const oEvent *oe, + const set &clsSel, + const vector< pair > &typeFormats, + gdiFonts font, + const char *fontFace, + bool large, int minSize) { + vector pps; + for (size_t k = 0; k < typeFormats.size(); k++) { + pps.push_back(oPrintPost()); + pps.back().text = typeFormats[k].second; + pps.back().type = typeFormats[k].first; + } + + oListParam par; + par.setLegNumberCoded(0); + oCounter c; + vector extras(pps.size(), 0); + + for (size_t k = 0; k < pps.size(); k++) { + string extra; + switch (pps[k].type) { + case lRunnerTotalTimeAfter: + case lRunnerClassCourseTimeAfter: + case lRunnerTimeAfterDiff: + case lRunnerTempTimeAfter: + case lRunnerTimeAfter: + case lRunnerMissedTime: + case lTeamTimeAfter: + case lTeamLegTimeAfter: + case lTeamTotalTimeAfter: + case lTeamTimeAdjustment: + case lRunnerTimeAdjustment: + case lRunnerGeneralTimeAfter: + + extra = "+10:00"; + break; + case lTeamRogainingPointOvertime: + case lRunnerRogainingPointOvertime: + case lResultModuleTime: + case lResultModuleTimeTeam: + case lTeamTime: + case lTeamTotalTime: + case lTeamTotalTimeStatus: + case lTeamLegTimeStatus: + case lTeamTimeStatus: + case lRunnerTempTimeStatus: + case lRunnerTotalTimeStatus: + case lRunnerTotalTime: + case lClassStartTime: + case lRunnerFinish: + case lRunnerTime: + case lRunnerTimeStatus: + case lRunnerTimePlaceFixed: + extra = "50:50"; + break; + case lRunnerGeneralTimeStatus: + case lClassStartTimeRange: + extra = "50:50 (50:50)"; + break; + case lTeamRogainingPointReduction: + case lRunnerRogainingPointReduction: + case lTeamPointAdjustment: + case lRunnerPointAdjustment: + case lRunnerRogainingPointGross: + case lRunnerPlace: + case lRunnerPlaceDiff: + case lTeamPlaceDiff: + case lRunnerTotalPlace: + case lRunnerClassCoursePlace: + case lTeamPlace: + case lTeamTotalPlace: + case lPunchControlPlace: + case lPunchControlPlaceAcc: + case lResultModuleNumber: + case lResultModuleNumberTeam: + extra = "199."; + break; + case lRunnerGeneralPlace: + extra = "199. (99.)"; + break; + } + + int width = 0; + EPostType type = pps[k].type; + + if (type == lClubName || type == lRunnerName || type == lTeamName + || type == lTeamRunner || type == lTeamClub) + width = max(15, width); + + if (type == lRunnerGivenName || type == lRunnerFamilyName || type == lRunnerNationality) + width = max(7, width); + + if (type == lRunnerCompleteName || type == lPatrolNameNames || type == lPatrolClubNameNames) + width = max(20, width); + + width = max(extra.size(), width); + + extras[k] = width; + } + + for (size_t k = 0; k < pps.size(); k++) { + const oPrintPost &pp = pps[k]; + int width = 0; + + for (oClassList::const_iterator it = oe->Classes.begin(); it != oe->Classes.end(); ++it) { + if (it->isRemoved()) + continue; + if (!clsSel.empty() && clsSel.count(it->getId()) == 0) + continue; + + const string &out = oe->formatListString(pp, par, 0, 0, 0, pClass(&*it), c); + width = max(width, int(out.length())); + } + + for (oCourseList::const_iterator it = oe->Courses.begin(); it != oe->Courses.end(); ++it) { + if (it->isRemoved()) + continue; + + const string &out = oe->formatSpecialString(pp, par, 0, 0, pCourse(&*it), 0, c); + width = max(width, int(out.length())); + } + + for (oControlList::const_iterator it = oe->Controls.begin(); it != oe->Controls.end(); ++it) { + if (it->isRemoved()) + continue; + + const string &out = oe->formatSpecialString(pp, par, 0, 0, 0, pControl(&*it), c); + width = max(width, int(out.length())); + } + extras[k] = max(extras[k], width); + } + + int width = minSize; + vector row(pps.size(), 0); + + for (oRunnerList::const_iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { + if (it->isRemoved()) + continue; + + // Case when runner/team has different class + bool teamOK = it->getTeam() && clsSel.count(it->getTeam()->getClassId()); + + if (!clsSel.empty() && (!teamOK && clsSel.count(it->getClassId()) == 0)) + continue; + + copy(extras.begin(), extras.end(), row.begin()); + + for (size_t k = 0; k < pps.size(); k++) { + oPrintPost &pp = pps[k]; + + pp.legIndex = it->tLeg; + pp.linearLegIndex = true; + int numIter = 1; + + if (pp.type == lPunchNamedTime || pp.type == lPunchTime) { + row[k] = max(row[k], 10); + pRunner r = pRunner(&*it); + numIter = (r && r->getCard()) ? r->getCard()->getNumPunches() + 1 : 1; + } + + while (numIter-- > 0) { + const string &out = oe->formatListString(pp, par, it->tInTeam, pRunner(&*it), it->Club, it->Class, c); + row[k] = max(row[k], int(out.length())); + if (numIter>0) + c.level3++; + } + } + + int sum = 0; + for (size_t k = 0; k < row.size(); k++) + sum += row[k]; + width = max(width, sum); + } + + if (width == 0) { + for (size_t k = 0; k < row.size(); k++) + width += extras[k]; + } + + double w = width; + double s = 1.0; + + s = oe->gdibase.getRelativeFontScale(font, fontFace); + + if (w > 15) { + if (large) + w *= adjustmentFactor(w-15, 0.7); + else + w *= adjustmentFactor(w-15, 0.85); + + if (w > 40) + w *= adjustmentFactor(w-40, 0.85); + } + w = max(w, minSize); + + if (width>0 && !large) + return int(s*(w*6.0+20.0)); + else if (width>0 && large) + return int(s*(w*7.0+10.0)); + else + return 0; +} + +const string & oEvent::formatListString(EPostType type, const pRunner r) const +{ + oPrintPost pp; + oCounter ctr; + oListParam par; + par.setLegNumberCoded(r->tLeg); + pp.type = type; + return formatListString(pp, par, r->tInTeam, r, r->Club, r->Class, ctr); +} + +const string & oEvent::formatListString(EPostType type, const pRunner r, + const string &format) const { + oPrintPost pp; + oCounter ctr; + oListParam par; + par.setLegNumberCoded(r->tLeg); + pp.type = type; + pp.text = format; + return formatListString(pp, par, r->tInTeam, r, r->Club, r->Class, ctr); +} + + +const string &oEvent::formatListString(const oPrintPost &pp, const oListParam &par, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, oCounter &counter) const { + const oPrintPost *cpp = &pp; + const string *tmp = 0; + string *out = 0; + while (cpp) { + if (tmp) { + if (!out) { + out = &StringCache::getInstance().get(); + *out = ""; + } + out->append(*tmp); + } + tmp = &formatListStringAux(*cpp, par, t, r, c, pc, counter); + cpp = cpp->mergeWithTmp; + } + + if (out) { + out->append(*tmp); + return *out; + } + else + return *tmp; +} + +const string &oEvent::formatSpecialString(const oPrintPost &pp, const oListParam &par, const pTeam t, int legIndex, + const pCourse crs, const pControl ctrl, oCounter &counter) const { + const oPrintPost *cpp = &pp; + const string *tmp = 0; + string *out = 0; + while (cpp) { + if (tmp) { + if (!out) { + out = &StringCache::getInstance().get(); + *out = ""; + } + out->append(*tmp); + } + tmp = &formatSpecialStringAux(*cpp, par, t, legIndex, crs, ctrl, counter); + cpp = cpp->mergeWithTmp; + } + + if (out) { + out->append(*tmp); + return *out; + } + else + return *tmp; +} + +const string &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListParam &par, + const pTeam t, int legIndex, + const pCourse pc, const pControl ctrl, + oCounter &counter) const { + + char bf[512]; + const string *sptr=0; + bf[0]=0; + static bool reentrantLock = false; + if (reentrantLock == true) { + reentrantLock = false; + throw meosException("Internal list error"); + } + + switch (pp.type) { + case lCourseLength: + if (pc) { + int len = pc->getLength(); + if (len > 0) + sprintf_s(bf, "%d", len); + } + break; + + case lCourseName: + case lRunnerCourse: + if (pc) { + sptr = &pc->getName(); + } + break; + + case lRunnerLegNumberAlpha: + if (t && t->getClassRef() && legIndex >= 0) { + string legStr = t->getClassRef()->getLegNumber(legIndex); + strcpy_s(bf, legStr.c_str()); + } + break; + + case lRunnerLegNumber: + if (t && t->getClassRef() && legIndex >= 0) { + int legNumber, legOrder; + t->getClassRef()->splitLegNumberParallel(legIndex, legNumber, legOrder); + sptr = &itos(legNumber+1); + } + break; + + case lCourseClimb: { + int len = pc ? pc->getDCI().getInt("Climb") : 0; + if (len > 0) + sprintf_s(bf, "%d", len); + } + break; + + case lCourseUsage: + if (pc) { + sptr = &itos(pc->getNumUsedMaps(false)); + } + break; + + case lCourseUsageNoVacant: + if (pc) { + sptr = &itos(pc->getNumUsedMaps(true)); + } + break; + + case lCourseClasses: + if (pc) { + vector cls; + pc->getClasses(cls); + string tmp; + for (size_t k = 0; k < cls.size(); k++) { + if (k > 0) + tmp += ", "; + tmp += cls[k]->getName(); + if (tmp.length() > 100) { + tmp += ", ..."; + break; + } + } + strncpy_s(bf, tmp.c_str(), 256); + } + break; + + + case lControlName: + if (ctrl) + strncpy_s(bf, ctrl->getName().c_str(), 128); + break; + + case lControlCourses: + if (ctrl) { + vector crs; + ctrl->getCourses(crs); + if (crs.size() == Courses.size()) { + sptr = &lang.tl("Alla"); + break; + } + + string tmp; + for (size_t k = 0; k < crs.size(); k++) { + if (k > 0) + tmp += ", "; + tmp += crs[k]->getName(); + if (tmp.length() > 100) { + tmp += ", ..."; + break; + } + } + strncpy_s(bf, tmp.c_str(), 256); + } + break; + + case lControlClasses: + if (ctrl) { + vector cls; + ctrl->getClasses(cls); + if (cls.size() == getNumClasses()) { + sptr = &lang.tl("Alla"); + break; + } + + string tmp; + for (size_t k = 0; k < cls.size(); k++) { + if (k > 0) + tmp += ", "; + tmp += cls[k]->getName(); + if (tmp.length() > 100) { + tmp += ", ..."; + break; + } + } + strncpy_s(bf, tmp.c_str(), 256); + } + break; + + case lControlVisitors: + if (ctrl) + sptr = &itos(ctrl->getNumVisitors(false)); + break; + + case lControlPunches: + if (ctrl) + sptr = &itos(ctrl->getNumVisitors(true)); + break; + + case lControlMedianLostTime: + if (ctrl) + sptr = &formatTime(ctrl->getMissedTimeMedian()); + break; + + case lControlMaxLostTime: + if (ctrl) + sptr = &formatTime(ctrl->getMissedTimeMax()); + break; + + case lControlMistakeQuotient: + if (ctrl) { + string tmp = itos(ctrl->getMistakeQuotient()); + tmp += "%"; + strncpy_s(bf, tmp.c_str(), 20); + } + break; + + case lControlRunnersLeft: + if (ctrl) + sptr = &itos(ctrl->getNumRunnersRemaining()); + break; + + case lControlCodes: + if (ctrl) { + vector numbers; + ctrl->getNumbers(numbers); + string tmp; + for (size_t j = 0; j < numbers.size(); j++) { + if (j > 0) + tmp += ", "; + tmp += itos(numbers[j]); + } + strncpy_s(bf, tmp.c_str(), 256); + } + break; + + default: { + reentrantLock = true; + try { + const string &res = formatListStringAux(pp, par, t, t ? t->getRunner(legIndex) : 0, + t ? t->getClubRef() : 0, + t ? t->getClassRef() : 0, counter); + reentrantLock = false; + return res; + } + catch(...) { + reentrantLock = false; + throw; + } + } + } + + if (pp.type!=lString && (sptr==0 || sptr->empty()) && bf[0]==0) + return _EmptyString; + else if (sptr) { + if (pp.text.empty()) + return *sptr; + else { + sprintf_s(bf, pp.text.c_str(), sptr->c_str()); + string &res = StringCache::getInstance().get(); + res = bf; + return res; + } + } + else { + if (pp.text.empty()) { + string &res = StringCache::getInstance().get(); + res = bf; + return res; + } + else { + char bf2[512]; + sprintf_s(bf2, pp.text.c_str(), bf); + string &res = StringCache::getInstance().get(); + res = bf2; + return res; + } + } +} + +const string &oEvent::formatListStringAux(const oPrintPost &pp, const oListParam &par, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, oCounter &counter) const { + + char bf[512]; + const string *sptr=0; + bf[0]=0; + bool invalidClass = pc && pc->getClassStatus() != oClass::Normal; + int legIndex = pp.legIndex; + if(pc && pp.type != lResultModuleNumber && pp.type != lResultModuleNumberTeam + && pp.type != lResultModuleTime && pp.type != lResultModuleTimeTeam) + legIndex = pc->getLinearIndex(pp.legIndex, pp.linearLegIndex); + + switch ( pp.type ) { + case lClassName: + if (invalidClass) + sprintf_s(bf, "%s (%s)", pc->getName().c_str(), lang.tl("Struken").c_str()); + else + sptr=pc ? &pc->getName() : 0; + break; + case lResultDescription: { + string title; + getResultTitle(*this, par, title); + strcpy_s(bf, title.c_str()); + } + break; + case lTimingFromName: + if (par.useControlIdResultFrom > 0) + strcpy_s(bf, getFullControlName(*this, par.useControlIdResultFrom).c_str()); + else + sptr = &lang.tl("Start"); + break; + case lTimingToName: + if (par.useControlIdResultTo > 0) + strcpy_s(bf, getFullControlName(*this, par.useControlIdResultTo).c_str()); + else + sptr = &lang.tl("Mål"); + break; + case lClassLength: + if (pc) { + strcpy_s(bf, pc->getLength(par.relayLegIndex).c_str()); + } + break; + case lClassStartName: + if (pc) strcpy_s(bf, pc->getDI().getString("StartName").c_str()); + break; + case lClassStartTime: + case lClassStartTimeRange: + if (pc) { + int first, last; + pc->getStartRange(legIndex, first, last); + if (pc->hasFreeStart()) + strcpy_s(bf, lang.tl("Fri starttid").c_str()); + else if (first > 0 && first == last) { + if (oe->useStartSeconds()) + strcpy_s(bf, oe->getAbsTime(first).c_str()); + else + strcpy_s(bf, oe->getAbsTimeHM(first).c_str()); + } + else if (pp.type == lClassStartTimeRange) { + string range = oe->getAbsTimeHM(first) + MakeDash(" - ") + oe->getAbsTimeHM(last); + strcpy_s(bf, range.c_str()); + } + } + break; + case lClassResultFraction: + if (pc && !invalidClass) { + int total, finished, dns; + oe->getNumClassRunners(pc->getId(), par.getLegNumber(pc), total, finished, dns); + sprintf_s(bf, "(%d / %d)", finished, total); + } + break; + case lCourseLength: + if (r) { + pCourse crs = r->getCourse(false); + return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); + } + break; + case lCourseName: + case lRunnerCourse: + if (r) { + pCourse crs = r->getCourse(false); + return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); + } + break; + case lCourseClimb: + if (r) { + pCourse crs = r->getCourse(false); + return formatSpecialStringAux(pp, par, t, 0, crs, 0, counter); + } + break; + case lCourseShortening: + if (r) { + int sh = r->getNumShortening(); + if (sh > 0) + sprintf_s(bf, "%d", sh); + } + break; + case lCmpName: + sptr = &getName(); + break; + case lCmpDate: + strcpy_s(bf, this->getDate().c_str()); + break; + case lCurrentTime: + strcpy_s(bf, getCurrentTimeS().c_str()); + break; + case lRunnerClub: + sptr=(r && r->Club) ? &r->Club->getDisplayName() : 0; + break; + case lRunnerFinish: + if (r && !invalidClass) { + if (pp.resultModuleIndex == -1) + sptr = &r->getFinishTimeS(); + else + sptr = &r->getTempResult(pp.resultModuleIndex).getFinishTimeS(this); + } + break; + case lRunnerStart: + case lRunnerStartCond: + case lRunnerStartZero: + if (r) { + if ((pp.type == lRunnerStartCond || pp.type == lRunnerStartZero) && pc && !pc->hasFreeStart()) { + int fs, ls; + pc->getStartRange(legIndex, fs, ls); + if (fs>0 && fs == ls) { + break; // Common start time, skip + } + } + if (r->startTimeAvailable()) { + if (pp.type != lRunnerStartZero) + sptr = &r->getStartTimeCompact(); + else { + int st = r->getStartTime(); + sptr = &getTimeMS(st-3600); + } + } + else + sptr = &MakeDash("-"); + } + break; + + case lRunnerName: + sptr = r ? &r->getName() : 0; + break; + case lRunnerGivenName: + if (r) strcpy_s(bf, r->getGivenName().c_str()); + break; + case lRunnerFamilyName: + if (r) strcpy_s(bf, r->getFamilyName().c_str()); + break; + case lRunnerCompleteName: + if (r) strcpy_s(bf, r->getCompleteIdentification().c_str()); + break; + case lPatrolNameNames: + if (t) { + pRunner r1 = t->getRunner(0); + pRunner r2 = t->getRunner(1); + if (r1 && r2) { + sprintf_s(bf, "%s / %s", r1->getName().c_str(),r2->getName().c_str()); + } + else if (r1) { + sptr = &r1->getName(); + } + else if (r2) { + sptr = &r2->getName(); + } + } + else { + sptr = r ? &r->getName() : 0; + } + break; + case lPatrolClubNameNames: + if (t) { + pRunner r1 = t->getRunner(0); + pRunner r2 = t->getRunner(1); + pClub c1 = r1 ? r1->Club : 0; + pClub c2 = r2 ? r2->Club : 0; + if (c1 == c2) + c2 = 0; + if (c1 && c2) { + sprintf_s(bf, "%s / %s", c1->getDisplayName().c_str(),c2->getDisplayName().c_str()); + } + else if (c1) { + sptr = &c1->getDisplayName(); + } + else if (c2) { + sptr = &c2->getDisplayName(); + } + } + else { + sptr = r && r->Club ? &r->Club->getDisplayName() : 0; + } + break; + case lRunnerTime: + if (r && !invalidClass) { + if (pp.resultModuleIndex == -1) + sptr = &r->getRunningTimeS(); + else + sptr = &r->getTempResult(pp.resultModuleIndex).getRunningTimeS(0); + + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + + } + case lRunnerTimeStatus: + if (r) { + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (pp.resultModuleIndex == -1) { + bool ok = r->prelStatusOK(); + if (ok && pc && !pc->getNoTiming()) { + sptr = &r->getRunningTimeS(); + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else { + if (ok) + sptr = &formatStatus(StatusOK); + else + sptr = &r->getStatusS(); + } + } + else { + const oAbstractRunner::TempResult &res = r->getTempResult(pp.resultModuleIndex); + if (res.getStatus() == StatusOK && pc && !pc->getNoTiming()) { + sptr = &res.getRunningTimeS(0); + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else + sptr = &res.getStatusS(StatusOK); + } + } + break; + + case lRunnerGeneralTimeStatus: + if (r) { + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (pp.resultModuleIndex == -1) { + if (r->prelStatusOK() && pc && !pc->getNoTiming()) { + string timeStatus = r->getRunningTimeS(); + + if (r->hasInputData() || (r->getLegNumber() > 0 && !r->isPatrolMember())) { + RunnerStatus ts = r->getTotalStatus(); + int rt = r->getTotalRunningTime(); + if (ts == StatusOK || (ts == StatusUnknown && rt > 0)) { + string vts = formatTime(rt) + " (" + timeStatus + ")"; + swap(vts, timeStatus); + } + else { + string vts = formatStatus(ts) + " (" + timeStatus + ")"; + swap(vts, timeStatus); + } + } + + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", timeStatus.c_str()); + } + else { + strcpy_s(bf, timeStatus.c_str()); + } + } + else + sptr = &r->getStatusS(); + } + else { + const oAbstractRunner::TempResult &res = r->getTempResult(pp.resultModuleIndex); + if (res.getStatus() == StatusOK && pc && !pc->getNoTiming()) { + sptr = &res.getRunningTimeS(0); + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else + sptr = &res.getStatusS(StatusOK); + } + } + break; + + break; + + case lRunnerGeneralTimeAfter: + if (r && pc && !invalidClass && !pc->getNoTiming()) { + if (pp.resultModuleIndex == -1) { + + if (r->hasInputData() || (r->getLegNumber() > 0 && !r->isPatrolMember())) { + int tleg = r->tLeg >= 0 ? r->tLeg:0; + if (r->getTotalStatus()==StatusOK) { + if ( (t && t->getNumShortening(tleg) == 0) || (!t && r->getNumShortening() == 0)) { + int after = r->getTotalRunningTime() - pc->getTotalLegLeaderTime(tleg, true); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + else { + sptr = &MakeDash("-"); + } + } + } + else { + int tleg=r->tLeg>=0 ? r->tLeg:0; + if (r->tStatus==StatusOK && pc && !pc->getNoTiming() ) { + if (r->getNumShortening() == 0) { + int after = r->getRunningTime() - pc->getBestLegTime(tleg); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + else { + sptr = &MakeDash("-"); + } + } + } + } + else { + int after = r->getTempResult(pp.resultModuleIndex).getTimeAfter(); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + } + break; + + + case lRunnerTimePerKM: + if (r && !invalidClass && r->prelStatusOK()) { + const pCourse pc = r->getCourse(false); + if (pc) { + int t = r->getRunningTime(); + int len = pc->getLength(); + if (len > 0 && t > 0) { + int sperkm = (1000 * t) / len; + strcpy_s(bf, formatTime(sperkm).c_str()); + } + } + } + break; + case lRunnerTotalTime: + if (r && !invalidClass) { + if (pp.resultModuleIndex == -1) + sptr = &r->getTotalRunningTimeS(); + else + sptr = &r->getTempResult(pp.resultModuleIndex).getRunningTimeS(r->getTotalTimeInput()); + } + break; + case lRunnerTotalTimeStatus: + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (r) { + if (pp.resultModuleIndex == -1) { + if ((r->getTotalStatus()==StatusOK || (r->getTotalStatus()==StatusUnknown + && r->prelStatusOK() && r->getInputStatus() == StatusOK) )&& pc && !pc->getNoTiming()) { + sptr = &r->getTotalRunningTimeS(); + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else + sptr = &r->getTotalStatusS(); + } + else { + const oAbstractRunner::TempResult &res = r->getTempResult(pp.resultModuleIndex); + RunnerStatus input = r->getTotalStatusInput(); + if (input == StatusOK && res.getStatus() == StatusOK && pc && !pc->getNoTiming()) { + sptr = &res.getRunningTimeS(r->getTotalTimeInput()); + if (r->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else + sptr = &res.getStatusS(input); + } + } + break; + case lRunnerTempTimeStatus: + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (r) { + if (r->tempStatus==StatusOK && pc && !pc->getNoTiming()) + strcpy_s(bf, formatTime(r->tempRT).c_str()); + else + strcpy_s(bf, formatStatus(r->tempStatus).c_str() ); + } + break; + case lRunnerPlace: + if (r && !invalidClass && pc && !pc->getNoTiming()) { + if (pp.resultModuleIndex == -1) + strcpy_s(bf, r->getPrintPlaceS(pp.text.empty()).c_str() ); + else + sptr = &r->getTempResult(pp.resultModuleIndex).getPrintPlaceS(pp.text.empty()); + } + break; + case lRunnerTotalPlace: + if (r && !invalidClass && pc && !pc->getNoTiming()) + strcpy_s(bf, r->getPrintTotalPlaceS(pp.text.empty()).c_str() ); + break; + + case lRunnerGeneralPlace: + if (r && !invalidClass && pc && !pc->getNoTiming()) { + if (pp.resultModuleIndex == -1) { + if (r->hasInputData() || (r->getLegNumber() > 0 && !r->isPatrolMember())) { + string iPlace; + if (pc->getClassType() != oClassPatrol) + iPlace = r->getPrintPlaceS(true); + + string tPlace = r->getPrintTotalPlaceS(true); + string v; + if (iPlace.empty()) + v = tPlace; + else { + if (tPlace.empty()) + tPlace = MakeDash("-"); + v = tPlace + " (" + iPlace + ")"; + } + strcpy_s(bf, v.c_str()); + } + else + strcpy_s(bf, r->getPrintPlaceS(pp.text.empty()).c_str() ); + } + else + sptr = &r->getTempResult(pp.resultModuleIndex).getPrintPlaceS(pp.text.empty()); + } + break; + + case lRunnerClassCoursePlace: + if (r && !invalidClass && pc && !pc->getNoTiming()) { + int p = r->getCoursePlace(); + if (p>0 && p<10000) + sprintf_s(bf, "%d.", p); + } + break; + case lRunnerPlaceDiff: + if (r && !invalidClass && pc && !pc->getNoTiming()) { + int p = r->getTotalPlace(); + if (r->getTotalStatus() == StatusOK && p > 0 && r->inputPlace>0) { + int pd = p - r->inputPlace; + if (pd > 0) + sprintf_s(bf, "+%d", pd); + else if (pd < 0) + sprintf_s(bf, "-%d", -pd); + } + } + break; + case lRunnerTimeAfterDiff: + if (r && pc && !invalidClass) { + int tleg = r->tLeg >= 0 ? r->tLeg:0; + if (r->getTotalStatus()==StatusOK && pc && !pc->getNoTiming()) { + int after = r->getTotalRunningTime() - pc->getTotalLegLeaderTime(tleg, true); + int afterOld = r->inputTime - pc->getBestInputTime(tleg); + int ad = after - afterOld; + if (ad > 0) + sprintf_s(bf, "+%d:%02d", ad/60, ad%60); + if (ad < 0) + sprintf_s(bf, "-%d:%02d", (-ad)/60, (-ad)%60); + } + } + break; + case lRunnerRogainingPoint: + if (r && !invalidClass) { + if (pp.resultModuleIndex == -1) + sprintf_s(bf, "%d", r->getRogainingPoints(false)); + else + sprintf_s(bf, "%d", r->getTempResult(pp.resultModuleIndex).getPoints()); + } + break; + + case lRunnerRogainingPointTotal: + if (r && !invalidClass) { + if (pp.resultModuleIndex == -1) + sprintf_s(bf, "%d", r->getRogainingPoints(true)); + else + sprintf_s(bf, "%d", r->getTempResult(pp.resultModuleIndex).getPoints() + r->getInputPoints()); + } + break; + + case lRunnerRogainingPointReduction: + if (r && !invalidClass) { + int red = r->getRogainingReduction(); + if (red > 0) + sprintf_s(bf, "-%d", red); + } + break; + + case lRunnerRogainingPointGross: + if (r && !invalidClass) { + int p = r->getRogainingPointsGross(); + sptr = &itos(p); + } + break; + + case lRunnerPointAdjustment: + if (r && !invalidClass) { + int a = r->getPointAdjustment(); + if (a<0) + sptr = &itos(a); + else if (a>0) + sprintf_s(bf, "+%d", a); + } + break; + case lRunnerTimeAdjustment: + if (r && !invalidClass) { + int a = r->getTimeAdjustment(); + if (a != 0) + sptr = &getTimeMS(a); + } + break; + case lRunnerRogainingPointOvertime: + if (r && !invalidClass) { + int over = r->getRogainingOvertime(); + if (over > 0) + sptr = &formatTime(over); + } + break; + + case lRunnerTimeAfter: + if (r && pc && !invalidClass && !pc->getNoTiming()) { + int after = 0; + if (pp.resultModuleIndex == -1) { + int tleg=r->tLeg>=0 ? r->tLeg:0; + int brt = pc->getBestLegTime(tleg); + if (r->prelStatusOK() && brt > 0) { + after=r->getRunningTime() - brt; + } + } + else { + after = r->getTempResult(pp.resultModuleIndex).getTimeAfter(); + } + + if (r->getNumShortening() == 0) { + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + else { + sptr = &MakeDash("-"); + } + } + break; + case lRunnerTotalTimeAfter: + if (r && pc && !invalidClass) { + int tleg = r->tLeg >= 0 ? r->tLeg:0; + if (r->getTotalStatus()==StatusOK && pc && !pc->getNoTiming()) { + if ( (t && t->getNumShortening(tleg) == 0) || (!t && r->getNumShortening() == 0)) { + int after = r->getTotalRunningTime() - pc->getTotalLegLeaderTime(tleg, true); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + else { + sptr = &MakeDash("-"); + } + } + } + break; + case lRunnerClassCourseTimeAfter: + if (r && pc && !invalidClass) { + pCourse crs = r->getCourse(false); + if (crs && r->tStatus==StatusOK && !pc->getNoTiming()) { + int after = r->getRunningTime() - pc->getBestTimeCourse(crs->getId()); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + } + break; + case lRunnerTimePlaceFixed: + if (r && !invalidClass) { + int t = r->getTimeWhenPlaceFixed(); + if (t == 0 || (t>0 && t < getComputerTime())) { + strcpy_s(bf, lang.tl("klar").c_str()); + } + else if (t == -1) + strcpy_s(bf, "-"); + else + strcpy_s(bf, oe->getAbsTime(t).c_str()); + } + break; + case lRunnerLegNumberAlpha: + case lRunnerLegNumber: + if (r) + return formatSpecialStringAux(pp, par, t, r->getLegNumber(), 0, 0, counter); + else + strcpy_s(bf, par.getLegName().c_str()); + break; + case lRunnerMissedTime: + if (r && r->tStatus == StatusOK && pc && !pc->getNoTiming() && !invalidClass) { + strcpy_s(bf, r->getMissedTimeS().c_str()); + } + break; + case lRunnerTempTimeAfter: + if (r && pc) { + if (r->tempStatus==StatusOK && pc && !pc->getNoTiming() + && r->tempRT>pc->tLegLeaderTime) { + int after=r->tempRT-pc->tLegLeaderTime; + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + } + break; + + case lRunnerCard: + if (r && r->CardNo > 0) + sprintf_s(bf, "%d", r->getCardNo()); + break; + case lRunnerRank: + if (r) { + int rank=r->getDI().getInt("Rank"); + if (rank>0) + strcpy_s(bf, FormatRank(rank).c_str()); + } + break; + case lRunnerBib: + if (r) { + string bib = r->getBib(); + if (!bib.empty()) + sprintf_s(bf, "%s", bib.c_str()); + } + break; + case lRunnerUMMasterPoint: + if (r) { + int total, finished, dns; + oe->getNumClassRunners(pc->getId(), par.getLegNumber(pc), total, finished, dns); + int percent = int(floor(0.5+double((100*(total-dns-r->getPlace()))/double(total-dns)))); + if (r->getStatus()==StatusOK) + sprintf_s(bf, "%d", percent); + else + sprintf_s(bf, "0"); + } + break; + case lRunnerAge: + if (r) { + int y = r->getBirthAge(); + if (y > 0) + sprintf_s(bf, "%d", y); + } + break; + case lRunnerBirthYear: + if (r) { + int y = r->getBirthYear(); + if (y > 0) + sprintf_s(bf, "%d", y); + } + break; + case lRunnerSex: + if (r) { + PersonSex s = r->getSex(); + if (s == sFemale) + sptr = &lang.tl("Kvinna"); + else if (s == sMale) + sptr = &lang.tl("Man"); + } + break; + case lRunnerPhone: + if (r) { + string s = r->getDCI().getString("Phone"); + strcpy_s(bf, s.c_str()); + } + break; + case lRunnerFee: + if (r) { + string s = formatCurrency(r->getDCI().getInt("Fee")); + strcpy_s(bf, s.c_str()); + } + break; + case lTeamFee: + if (t) { + string s = formatCurrency(t->getTeamFee()); + strcpy_s(bf, s.c_str()); + } + break; + case lRunnerNationality: + if (r) { + string nat = r->getNationality(); + strcpy_s(bf, nat.c_str()); + } + break; + case lTeamName: + //sptr = t ? &t->Name : 0; + if (t) { + strcpy_s(bf, t->getDisplayName().c_str()); + } + break; + case lTeamStart: + case lTeamStartCond: + case lTeamStartZero: + if (t) { + if ((pp.type == lTeamStartCond || pp.type == lTeamStartZero) && pc && !pc->hasFreeStart()) { + int fs, ls; + pc->getStartRange(legIndex, fs, ls); + if (fs>0 && fs == ls) { + break; // Common start time, skip + } + } + + if (unsigned(legIndex)Runners.size() && t->Runners[legIndex] && t->Runners[legIndex]->startTimeAvailable()) { + if (pp.type != lTeamStartZero) + sptr = &t->Runners[legIndex]->getStartTimeCompact(); + else { + int st = t->Runners[legIndex]->getStartTime(); + sptr = &getTimeMS(st-3600); + } + } + } + break; + case lTeamStatus: + if (t && !invalidClass) { + if (pp.resultModuleIndex == -1) + sptr = &t->getLegStatusS(legIndex, false); + else + sptr = &t->getTempResult(pp.resultModuleIndex).getStatusS(StatusOK); + } + break; + case lTeamTime: + if (t && !invalidClass) { + if (pp.resultModuleIndex == -1) + strcpy_s(bf, t->getLegRunningTimeS(legIndex, false).c_str() ); + else + sptr = &t->getTempResult(pp.resultModuleIndex).getRunningTimeS(0); + } + break; + case lTeamTimeStatus: + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (t) { + if (pp.resultModuleIndex == -1) { + RunnerStatus st = t->getLegStatus(legIndex, false); + if (st==StatusOK || (st==StatusUnknown && t->getLegRunningTime(legIndex, false)>0)) + strcpy_s(bf, t->getLegRunningTimeS(legIndex, false).c_str()); + else + sptr = &t->getLegStatusS(legIndex, false); + } + else { + RunnerStatus st = t->getTempResult(pp.resultModuleIndex).getStatus(); + if (st == StatusOK || st == StatusUnknown) { + sptr = &t->getTempResult(pp.resultModuleIndex).getRunningTimeS(0); + if (t->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else + sptr = &t->getTempResult(pp.resultModuleIndex).getStatusS(StatusOK); + } + } + break; + case lTeamRogainingPoint: + if (t && !invalidClass) { + if (pp.resultModuleIndex == -1) + sprintf_s(bf, "%d", t->getRogainingPoints(false)); + else + sprintf_s(bf, "%d", t->getTempResult(pp.resultModuleIndex).getPoints()); + } + break; + case lTeamRogainingPointTotal: + if (t && !invalidClass) { + if (pp.resultModuleIndex == -1) + sprintf_s(bf, "%d", t->getRogainingPoints(true)); + else + sprintf_s(bf, "%d", t->getTempResult(pp.resultModuleIndex).getPoints() + t->getInputPoints()); + } + break; + + case lTeamRogainingPointReduction: + if (t && !invalidClass) { + int red = t->getRogainingReduction(); + if (red > 0) + sprintf_s(bf, "-%d", red); + } + break; + + case lTeamRogainingPointOvertime: + if (t && !invalidClass) { + int over = t->getRogainingOvertime(); + if (over > 0) + sptr = &formatTime(over); + } + break; + + case lTeamPointAdjustment: + if (t && !invalidClass) { + int a = t->getPointAdjustment(); + if (a<0) + sptr = &itos(a); + else if (a>0) + sprintf_s(bf, "+%d", a); + } + break; + + case lTeamTimeAdjustment: + if (t && !invalidClass) { + int a = t->getTimeAdjustment(); + if (a != 0) + sptr = &getTimeMS(a); + } + break; + + case lTeamTimeAfter: + if (t && !invalidClass) { + if (pp.resultModuleIndex == -1) { + if (t->getLegStatus(legIndex, false)==StatusOK) { + if (t->getNumShortening(legIndex) == 0) { + int ta=t->getTimeAfter(legIndex); + if (ta>0) + sprintf_s(bf, "+%d:%02d", ta/60, ta%60); + } + else { + sptr = &MakeDash("-"); + } + } + } + else { + if (t->getTempResult().getStatus() == StatusOK) { + int after = t->getTempResult(pp.resultModuleIndex).getTimeAfter(); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + } + } + break; + case lTeamPlace: + if (t && !invalidClass && pc && !pc->getNoTiming()) { + if (pp.resultModuleIndex == -1) { + strcpy_s(bf, t->getLegPrintPlaceS(legIndex, false, pp.text.empty()).c_str()); + } + else + sptr = &t->getTempResult(pp.resultModuleIndex).getPrintPlaceS(pp.text.empty()); + } + break; + + case lTeamLegTimeStatus: + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (t) { + int ix = r ? r->getLegNumber() : counter.level3; + if (t->getLegStatus(ix, false)==StatusOK) + strcpy_s(bf, t->getLegRunningTimeS(ix, false).c_str() ); + else + strcpy_s(bf, t->getLegStatusS(ix, false).c_str() ); + } + break; + case lTeamLegTimeAfter: + if (t) { + int ix = r ? r->getLegNumber() : counter.level3; + if (t->getLegStatus(ix, false)==StatusOK && !invalidClass) { + if (t->getNumShortening(ix) == 0) { + int ta=t->getTimeAfter(ix); + if (ta>0) + sprintf_s(bf, "+%d:%02d", ta/60, ta%60); + } + else { + sptr = &MakeDash("-"); + } + } + } + break; + case lTeamClub: + if (t) { + strcpy_s(bf, t->getDisplayClub().c_str()); + } + break; + case lTeamRunner: + if (t && unsigned(legIndex)Runners.size() && t->Runners[legIndex]) + sptr=&t->Runners[legIndex]->getName(); + break; + case lTeamRunnerCard: + if (t && unsigned(legIndex)Runners.size() && t->Runners[legIndex] + && t->Runners[legIndex]->getCardNo()>0) + sprintf_s(bf, "%d", t->Runners[legIndex]->getCardNo()); + break; + case lTeamBib: + if (t) { + sptr = &t->getBib(); + } + break; + case lTeamTotalTime: + if (t && !invalidClass) strcpy_s(bf, t->getLegRunningTimeS(legIndex, true).c_str() ); + break; + case lTeamTotalTimeStatus: + if (invalidClass) + sptr = &lang.tl("Struken"); + else if (t) { + if (pp.resultModuleIndex == -1) { + if (t->getLegStatus(legIndex, true)==StatusOK) + strcpy_s(bf, t->getLegRunningTimeS(legIndex, true).c_str() ); + else + strcpy_s(bf, t->getLegStatusS(legIndex, true).c_str() ); + } + else { + RunnerStatus st = t->getTempResult(pp.resultModuleIndex).getStatus(); + RunnerStatus inp = t->getInputStatus(); + if (st == StatusOK && inp == StatusOK) { + sptr = &t->getTempResult(pp.resultModuleIndex).getRunningTimeS(0); + if (t->getNumShortening() > 0) { + sprintf_s(bf, "*%s", sptr->c_str()); + sptr = 0; + } + } + else + sptr = &t->getTempResult(pp.resultModuleIndex).getStatusS(StatusOK); + } + } + break; + case lTeamPlaceDiff: + if (t && !invalidClass) { + int p = t->getTotalPlace(); + if (t->getTotalStatus() == StatusOK && p > 0 && t->inputPlace>0) { + int pd = p - t->inputPlace; + if (pd > 0) + sprintf_s(bf, "+%d", pd); + else if (pd < 0) + sprintf_s(bf, "-%d", -pd); + } + } + break; + case lTeamTotalPlace: + if (t && !invalidClass && pc && !pc->getNoTiming()) strcpy_s(bf, t->getPrintTotalPlaceS(pp.text.empty()).c_str() ); + break; + + break; + case lTeamTotalTimeAfter: + if (t && pc && !invalidClass) { + int tleg = t->getNumRunners() - 1; + if (t->getTotalStatus()==StatusOK && pc && !pc->getNoTiming()) { + int after = t->getTotalRunningTime() - pc->getTotalLegLeaderTime(tleg, true); + if (after > 0) + sprintf_s(bf, "+%d:%02d", after/60, after%60); + } + } + break; + case lTeamTotalTimeDiff: + if (t && pc && !invalidClass) { + int tleg = t->getNumRunners() - 1; + if (t->getTotalStatus()==StatusOK && pc && !pc->getNoTiming()) { + int after = t->getTotalRunningTime() - pc->getTotalLegLeaderTime(tleg, true); + int afterOld = t->inputTime - pc->getBestInputTime(tleg); + int ad = after - afterOld; + if (ad > 0) + sprintf_s(bf, "+%d:%02d", ad/60, ad%60); + if (ad < 0) + sprintf_s(bf, "-%d:%02d", (-ad)/60, (-ad)%60); + } + } + break; + case lTeamStartNo: + if (t) + sprintf_s(bf, "%d", t->getStartNo()); + break; + case lRunnerStartNo: + if (r) + sprintf_s(bf, "%d", r->getStartNo()); + break; + case lNationality: + if (r && !(sptr = &r->getDCI().getString("Nationality"))->empty()) + break; + else if (t && !(sptr = &t->getDCI().getString("Nationality"))->empty()) + break; + else if (c && !(sptr = &c->getDCI().getString("Nationality"))->empty()) + break; + + break; + + case lCountry: + if (r && !(sptr = &r->getDCI().getString("Country"))->empty()) + break; + else if (t && !(sptr = &t->getDCI().getString("Country"))->empty()) + break; + else if (c && !(sptr = &c->getDCI().getString("Country"))->empty()) + break; + + break; + case lPunchNamedTime: + if (r && r->Card && r->getCourse(true) && !invalidClass) { + const pCourse crs = r->getCourse(true); + const oControl *ctrl=crs->getControl(counter.level3); + if (!ctrl || ctrl->isRogaining(crs->hasRogaining())) + break; + if (r->getPunchTime(counter.level3, false)>0 && ctrl->hasName()) { + sprintf_s(bf, "%s: %s (%s)", ctrl->getName().c_str(), + r->getNamedSplitS(counter.level3).c_str(), + r->getPunchTimeS(counter.level3, false).c_str()); + } + } + break; + case lPunchTime: + case lPunchControlNumber: + case lPunchControlCode: + case lPunchLostTime: + case lPunchControlPlace: + case lPunchControlPlaceAcc: + + if (r && r->Card && r->getCourse(true) && !invalidClass) { + const pCourse crs=r->getCourse(true); + int nCtrl = crs->getNumControls(); + if (counter.level3 != nCtrl) { // Always allow finish + const oControl *ctrl=crs->getControl(counter.level3); + if (!ctrl || ctrl->isRogaining(crs->hasRogaining())) + break; + } + if (pp.type == lPunchTime) { + if (r->getPunchTime(counter.level3, false)>0) { + sprintf_s(bf, "%s (%s)", + r->getSplitTimeS(counter.level3, false).c_str(), + r->getPunchTimeS(counter.level3, false).c_str()); + } + else { + strcpy_s(bf, MakeDash("- (-)").c_str()); + } + } + else if (pp.type == lPunchControlNumber) { + strcpy_s(bf, crs->getControlOrdinal(counter.level3).c_str()); + } + else if (pp.type == lPunchControlCode) { + const oControl *ctrl=crs->getControl(counter.level3); + if (ctrl) { + if (ctrl->getStatus() == oControl::StatusMultiple) { + string str = ctrl->getStatusS(); + sprintf_s(bf, "%s.", str.substr(0, 1).c_str()); + } + else + sprintf_s(bf, "%d", ctrl->getFirstNumber()); + } + } + else if (pp.type == lPunchControlPlace) { + int p = r->getLegPlace(counter.level3); + if (p>0) + sprintf_s(bf, "%d", p); + } + else if (pp.type == lPunchControlPlaceAcc) { + int p = r->getLegPlaceAcc(counter.level3); + if (p>0) + sprintf_s(bf, "%d", p); + } + else if (pp.type == lPunchLostTime) { + strcpy_s(bf, r->getMissedTimeS(counter.level3).c_str()); + } + } + break; + case lSubSubCounter: + if (pp.text.empty()) + sprintf_s(bf, "%d.", counter.level3+1); + else + sprintf_s(bf, "%d", counter.level3+1); + break; + case lSubCounter: + if (pp.text.empty()) + sprintf_s(bf, "%d.", counter.level2+1); + else + sprintf_s(bf, "%d", counter.level2+1); + break; + case lTotalCounter: + if (pp.text.empty()) + sprintf_s(bf, "%d.", counter.level1+1); + else + sprintf_s(bf, "%d", counter.level1+1); + break; + case lClubName: + sptr = c != 0 ? &c->getDisplayName() : 0; + break; + case lResultModuleTime: + case lResultModuleTimeTeam: + + if (pp.resultModuleIndex != -1) { + if (t && pp.type == lResultModuleTimeTeam) + sptr = &t->getTempResult(pp.resultModuleIndex).getOutputTime(legIndex); + else if (r) + sptr = &r->getTempResult(pp.resultModuleIndex).getOutputTime(legIndex); + } + break; + + case lResultModuleNumber: + case lResultModuleNumberTeam: + + if (pp.resultModuleIndex != -1) { + int nr = 0; + if (t && pp.type == lResultModuleNumberTeam) + nr = t->getTempResult(pp.resultModuleIndex).getOutputNumber(legIndex); + else if (r) + nr = r->getTempResult(pp.resultModuleIndex).getOutputNumber(legIndex); + + if (pp.text.empty() || pp.text[0]!='@') + sptr = &itos(nr); + else { + vector out; + split(pp.text.substr(1), ";", out); + string &res = StringCache::getInstance().get(); + size_t ix = nr; + if (!out.empty() && ix >= out.size() && out.back().find_first_of('%') != out.back().npos) { + ix = out.size() - 1; + } + if (ix < out.size()) { + res.swap(out[ix]); + if (res.find_first_of('%') != res.npos) { + char bf2[256]; + sprintf_s(bf2, res.c_str(), itos(nr).c_str()); + res = bf2; + } + } + else + res = ""; + + return res; + } + } + break; + + case lRogainingPunch: + if (r && r->Card && r->getCourse(false)) { + const pCourse crs = r->getCourse(false); + const pPunch punch = r->Card->getPunchByIndex(counter.level3); + if (punch && punch->tRogainingIndex>=0) { + const pControl ctrl = crs->getControl(punch->tRogainingIndex); + if (ctrl) { + sprintf_s(bf, "%d, %dp, %s (%s)", + punch->Type, ctrl->getRogainingPoints(), + r->Card->getRogainingSplit(counter.level3, r->tStartTime).c_str(), + punch->getRunningTime(r->tStartTime).c_str()); + } + } + } + break; + } + + if (pp.type!=lString && (sptr==0 || sptr->empty()) && bf[0]==0) + return _EmptyString; + else if (sptr) { + if (pp.text.empty()) + return *sptr; + else { + sprintf_s(bf, pp.text.c_str(), sptr->c_str()); + string &res = StringCache::getInstance().get(); + res = bf; + return res; + } + } + else { + if (pp.text.empty()) { + string &res = StringCache::getInstance().get(); + res = bf; + return res; + } + else { + char bf2[512]; + sprintf_s(bf2, pp.text.c_str(), bf); + string &res = StringCache::getInstance().get(); + res = bf2; + return res; + } + } +} + + + +bool oEvent::formatPrintPost(const list &ppli, PrintPostInfo &ppi, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, const pCourse crs, const pControl ctrl, int legIndex) +{ + list::const_iterator ppit; + int y=ppi.gdi.getCY(); + int x=ppi.gdi.getCX(); + bool updated=false; + for (ppit=ppli.begin();ppit!=ppli.end();) { + const oPrintPost &pp=*ppit; + int limit = 0; + + bool keepNext = false; + //Skip merged entities + while (ppit != ppli.end() && ppit->doMergeNext) + ++ppit; + + // Main increment below + if ( ++ppit != ppli.end() && ppit->dy==pp.dy) + limit = ppit->dx - pp.dx; + else + keepNext = true; + + limit=max(pp.fixedWidth, limit); + + assert(limit>=0); + pRunner rr = r; + if (!rr && t) { + if (pp.legIndex >= 0) { + int lg = pc ? pc->getLinearIndex(pp.legIndex, pp.linearLegIndex) : pp.legIndex; + rr=t->getRunner(lg); + } + else if (legIndex >= 0) + rr=t->getRunner(legIndex); + else { + int lg = ppi.par.getLegNumber(pc); + rr = t->getRunner(lg); + } + } + const string &text = (legIndex == -1) ? formatListString(pp, ppi.par, t, rr, c, pc, ppi.counter) : + formatSpecialString(pp, ppi.par, t, legIndex, crs, ctrl, ppi.counter); + updated |= !text.empty(); + TextInfo *ti = 0; + if (!text.empty()) { + if ( (pp.type == lRunnerName || pp.type == lRunnerCompleteName || + pp.type == lRunnerFamilyName || pp.type == lRunnerGivenName || + pp.type == lTeamRunner || (pp.type == lPatrolNameNames && !t)) && rr) { + ti = &ppi.gdi.addStringUT(y+ppi.gdi.scaleLength(pp.dy), x+ppi.gdi.scaleLength(pp.dx), pp.format, text, + ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str()); + ti->setExtra(rr->getId()); + ti->id = "R"; + } + else if ((pp.type == lTeamName || pp.type == lPatrolNameNames) && t) { + ti = &ppi.gdi.addStringUT(y+ppi.gdi.scaleLength(pp.dy), x+ppi.gdi.scaleLength(pp.dx), pp.format, text, + ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str()); + ti->setExtra(t->getId()); + ti->id = "T"; + } + else { + ti = &ppi.gdi.addStringUT(y + ppi.gdi.scaleLength(pp.dy), x + ppi.gdi.scaleLength(pp.dx), + pp.format, text, ppi.gdi.scaleLength(limit), 0, pp.fontFace.c_str()); + } + if (ti && ppi.keepToghether) + ti->lineBreakPrioity = -1; + + if (pp.color != colorDefault) + ti->setColor(pp.color); + } + ppi.keepToghether |= keepNext; + + } + + return updated; +} + +void oEvent::calculatePrintPostKey(const list &ppli, gdioutput &gdi, const oListParam &par, + const pTeam t, const pRunner r, const pClub c, + const pClass pc, oCounter &counter, string &key) +{ + key.clear(); + list::const_iterator ppit; + for (ppit=ppli.begin();ppit!=ppli.end(); ++ppit) { + const oPrintPost &pp=*ppit; + pRunner rr = r; + if (!rr && t) { + int linLeg = pp.legIndex; + if (pc) + linLeg = pc->getLinearIndex(pp.legIndex, pp.linearLegIndex); + rr=t->getRunner(linLeg); + } + const string &text = formatListString(pp, par, t, rr, c, pc, counter); + key += text; + //Skip merged entities + while (ppit != ppli.end() && ppit->doMergeNext) + ++ppit; + } +} + +void oEvent::listGeneratePunches(const list &ppli, gdioutput &gdi, const oListParam &par, + pTeam t, pRunner r, pClub club, pClass cls) +{ + if (!r || ppli.empty()) + return; + + pCourse crs=r->getCourse(true); + + if (!crs) + return; + + if (cls && cls->getNoTiming()) + return; + + bool filterNamed = false; + int h = gdi.getLineHeight(); + int w=0; + + for (list::const_iterator it = ppli.begin(); it != ppli.end(); ++it) { + if (it->type == lPunchNamedTime) + filterNamed = true; + h = max(h, gdi.getLineHeight(it->getFont(), it->fontFace.c_str()) + gdi.scaleLength(it->dy)); + w = max(w, gdi.scaleLength(it->fixedWidth + it->dx)); + } + + int xlimit=gdi.getCX()+ gdi.scaleLength(600); + + if (w>0) { + gdi.pushX(); + gdi.fillNone(); + } + + bool neednewline = false; + bool updated=false; + + int limit = crs->nControls + 1; + + if (r->Card && r->Card->getNumPunches()>limit) + limit = r->Card->getNumPunches(); + + vector skip(limit, false); + if (filterNamed) { + for (int k = 0; k < crs->nControls; k++) { + if (crs->getControl(k) && !crs->getControl(k)->hasName()) + skip[k] = true; + } + for (int k = crs->nControls; k < limit; k++) { + skip[k] = true; + } + } + + PrintPostInfo ppi(gdi, par); + + for (int k=0; k0 && updated) { + updated=false; + if ( gdi.getCX() + w > xlimit) { + neednewline = false; + gdi.popX(); + gdi.setCY(gdi.getCY() + h); + } + else + gdi.setCX(gdi.getCX()+w); + } + + if (!skip[k]) { + updated |= formatPrintPost(ppli, ppi, t, r, club, cls, 0, 0, -1); + neednewline |= updated; + } + + ppi.counter.level3++; + } + + if (w>0) { + gdi.popX(); + gdi.fillDown(); + if (neednewline) + gdi.setCY(gdi.getCY() + h); + } +} + +void oEvent::generateList(gdioutput &gdi, bool reEvaluate, const oListInfo &li, bool updateScrollBars) { + if (reEvaluate) + reEvaluateAll(set(), false); + + oe->calcUseStartSeconds(); + oe->calculateNumRemainingMaps(); + oe->updateComputerTime(); + vector< pair > > tagNameList; + oe->getGeneralResults(false, tagNameList, false); + string src; + for (size_t k = 0; k < tagNameList.size(); k++) + oe->getGeneralResult(tagNameList[k].second.first, src).setContext(&li.lp); + + string listname; + if (!li.Head.empty()) { + oCounter counter; + const string &name = formatListString(li.Head.front(), li.lp, 0, 0, 0, 0, counter); + listname = name; + li.lp.updateDefaultName(name); + } + bool addHead = !li.lp.pageBreak && !li.lp.useLargeSize; + size_t nClassesSelected = li.lp.selection.size(); + if (nClassesSelected!=0 && nClassesSelected < min(Classes.size(), Classes.size()/2+5) ) { + // Non-trivial class selection: + Classes.sort(); + string cls; + for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (li.lp.selection.count(it->getId())) { + cls += MakeDash(" - "); + cls += it->getName(); + } + } + listname += cls; + } + + if (li.lp.getLegNumberCoded() != -1) { + listname += lang.tl(" Sträcka X#" + li.lp.getLegName()); + } + + generateListInternal(gdi, li, addHead); + + for (list::const_iterator it = li.next.begin(); it != li.next.end(); ++it) { + bool interHead = addHead && it->getParam().showInterTitle; + if (li.lp.pageBreak || it->lp.pageBreak) { + gdi.dropLine(1.0); + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + } + else if (interHead) + gdi.dropLine(1.5); + + generateListInternal(gdi, *it, interHead); + } + + for (size_t k = 0; k < tagNameList.size(); k++) + oe->getGeneralResult(tagNameList[k].second.first, src).clearContext(); + + gdi.setListDescription(listname); + if (updateScrollBars) + gdi.updateScrollbars(); +} + +void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool formatHead) { + li.setupLinks(); + pClass sampleClass = 0; + + if (!li.lp.selection.empty()) + sampleClass = getClass(*li.lp.selection.begin()); + if (!sampleClass && !Classes.empty()) + sampleClass = &*Classes.begin(); + + PrintPostInfo printPostInfo(gdi, li.lp); + //oCounter counter; + //Render header + + if (formatHead) + formatPrintPost(li.Head, printPostInfo, 0,0,0,0,0,0, -1); + + if (li.fixedType) { + generateFixedList(gdi, li); + return; + } + + // Apply for all teams (calculate start times etc.) + for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved() || it->tStatus == StatusNotCompetiting) + continue; + + if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId())==0) + continue; + it->apply(false, 0, true); + } + + string oldKey; + if ( li.listType==li.EBaseTypeRunner ) { + + if (li.calcCourseClassResults) + calculateResults(RTClassCourseResult); + + if (li.calcTotalResults) { + if (li.calcResults) { + calculateResults(RTClassResult); + calculateTeamResults(false); + } + + calculateTeamResults(true); + calculateResults(RTTotalResult); + + if (li.sortOrder != ClassTotalResult) + sortRunners(li.sortOrder); + } + else if (li.calcResults) { + if (li.rogainingResults) { + calculateRogainingResults(); + if (li.sortOrder != ClassPoints) + sortRunners(li.sortOrder); + } + else if (li.lp.useControlIdResultTo>0 || li.lp.useControlIdResultFrom>0) + calculateSplitResults(li.lp.useControlIdResultFrom, li.lp.useControlIdResultTo); + else if (li.sortOrder == CourseResult) { + calculateResults(RTCourseResult); + } + else { + calculateTeamResults(false); + calculateResults(RTClassResult); + if (li.sortOrder != ClassResult) + sortRunners(li.sortOrder); + } + } + else + sortRunners(li.sortOrder); + + vector rlist; + rlist.reserve(Runners.size()); + + for (oRunnerList::iterator it=Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved() || it->tStatus == StatusNotCompetiting) + continue; + + if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId())==0) + continue; + + //if (it->legToRun() != li.lp.legNumber && li.lp.legNumber!=-1) + if (!li.lp.matchLegNumber(it->getClassRef(), it->legToRun())) + continue; + + if (li.filter(EFilterExcludeDNS)) + if (it->tStatus==StatusDNS) + continue; + + if (li.filter(EFilterVacant)) { + if (it->isVacant()) + continue; + } + if (li.filter(EFilterOnlyVacant)) { + if (!it->isVacant()) + continue; + } + + if (li.filter(EFilterRentCard) && it->getDI().getInt("CardFee")==0) + continue; + + if (li.filter(EFilterHasCard) && it->getCardNo()==0) + continue; + + if (li.filter(EFilterHasNoCard) && it->getCardNo()>0) + continue; + + rlist.push_back(&*it); + } + + GeneralResult *gResult = 0; + if (!li.resultModule.empty()) { + string src; + gResult = &getGeneralResult(li.resultModule, src); + oListInfo::ResultType resType = li.getResultType(); + gResult->calculateIndividualResults(rlist, resType, li.sortOrder == Custom, li.getParam().getInputNumber()); + + if (li.sortOrder == SortByFinishTime || li.sortOrder == SortByFinishTimeReverse + || li.sortOrder == SortByStartTime) + gResult->sort(rlist, li.sortOrder); + } + + for (size_t k = 0; k < rlist.size(); k++) { + pRunner it = rlist[k]; + + if (gResult && it->getTempResult(0).getStatus() == StatusNotCompetiting) + continue; + + if (li.filter(EFilterHasResult)) { + if (gResult == 0) { + if (li.lp.useControlIdResultTo<=0 && it->tStatus==StatusUnknown) + continue; + else if ( (li.lp.useControlIdResultTo>0 || li.lp.useControlIdResultFrom>0) && it->tempStatus!=StatusOK) + continue; + else if (li.calcTotalResults && it->getTotalStatus() == StatusUnknown) + continue; + } + else { + const oAbstractRunner::TempResult &res = it->getTempResult(0); + RunnerStatus st = res.getStatus(); + if (st==StatusUnknown) + continue; + } + } + else if (li.filter(EFilterHasPrelResult)) { + if (gResult == 0) { + if (li.lp.useControlIdResultTo<=0 && it->tStatus==StatusUnknown && it->getRunningTime()<=0) + continue; + else if ( (li.lp.useControlIdResultTo>0 || li.lp.useControlIdResultFrom>0) && it->tempStatus!=StatusOK) + continue; + else if (li.calcTotalResults && it->getTotalStatus() == StatusUnknown && it->getTotalRunningTime()<=0) + continue; + } + else { + const oAbstractRunner::TempResult &res = it->getTempResult(0); + int rt = res.getRunningTime(); + RunnerStatus st = res.getStatus(); + if (st==StatusUnknown && rt<=0) + continue; + } + } + + string newKey; + printPostInfo.par.relayLegIndex = -1; + calculatePrintPostKey(li.subHead, gdi, li.lp, it->tInTeam, &*it, it->Club, it->Class, printPostInfo.counter, newKey); + + if (newKey != oldKey) { + if (li.lp.pageBreak) { + if (!oldKey.empty()) + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + } + gdi.addStringUT(pagePageInfo, it->getClass()); + + oldKey.swap(newKey); + printPostInfo.counter.level2=0; + printPostInfo.counter.level3=0; + printPostInfo.reset(); + printPostInfo.par.relayLegIndex = -1; + formatPrintPost(li.subHead, printPostInfo, it->tInTeam, &*it, it->Club, it->Class, 0, 0, -1); + } + if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2tLeg; + formatPrintPost(li.listPost, printPostInfo, it->tInTeam, &*it, it->Club, it->Class, 0, 0, -1); + + if (li.listSubType==li.EBaseTypePunches) { + listGeneratePunches(li.subListPost, gdi, li.lp, it->tInTeam, &*it, it->Club, it->Class); + } + } + ++printPostInfo.counter; + } + + } + else if ( li.listType==li.EBaseTypeTeam ) { + if (li.calcResults) + calculateTeamResults(false); + if (li.calcTotalResults) + calculateTeamResults(true); + if (li.rogainingResults && li.resultModule.empty()) + throw std::exception("Not implemented"); + if (li.calcCourseClassResults) + calculateResults(RTClassCourseResult); + + if (li.resultModule.empty()) { + pair legInfo = li.lp.getLegInfo(sampleClass); + sortTeams(li.sortOrder, legInfo.first, legInfo.second); + } + vector tlist; + tlist.reserve(Teams.size()); + for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved() || it->tStatus == StatusNotCompetiting) + continue; + + if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId())==0) + continue; + tlist.push_back(&*it); + } + GeneralResult *gResult = 0; + if (!li.resultModule.empty()) { + string src; + gResult = &getGeneralResult(li.resultModule, src); + oListInfo::ResultType resType = li.getResultType(); + gResult->calculateTeamResults(tlist, resType, li.sortOrder == Custom, li.getParam().getInputNumber()); + } + // Range of runners to include + int parLegRangeMin = 0, parLegRangeMax = 1000; + pClass parLegRangeClass = 0; + const bool needParRange = li.subFilter(ESubFilterSameParallel) + || li.subFilter(ESubFilterSameParallelNotFirst); + + for (size_t k = 0; k < tlist.size(); k++) { + pTeam it = tlist[k]; + int linearLegSpec = li.lp.getLegNumber(it->getClassRef()); + + if (gResult && it->getTempResult(0).getStatus() == StatusNotCompetiting) + continue; + + if (li.filter(EFilterExcludeDNS)) + if (it->tStatus==StatusDNS) + continue; + + if (li.filter(EFilterVacant)) + if (it->isVacant()) + continue; + + if (li.filter(EFilterOnlyVacant)) { + if (!it->isVacant()) + continue; + } + + if ( li.filter(EFilterHasResult) ) { + if (gResult) { + if (it->getTempResult(0).getStatus() == StatusUnknown) + continue; + } + else { + if (it->getLegStatus(linearLegSpec, false)==StatusUnknown) + continue; + else if (li.calcTotalResults && it->getLegStatus(linearLegSpec, true) == StatusUnknown) + continue; + } + } + else if ( li.filter(EFilterHasPrelResult) ) { + if (gResult) { + if (it->getTempResult(0).getStatus() == StatusUnknown && it->getTempResult(0).getRunningTime() <= 0) + continue; + } + else { + if (it->getLegStatus(linearLegSpec, false)==StatusUnknown && it->getLegRunningTime(linearLegSpec, false)<=0) + continue; + else if (li.calcTotalResults && it->getLegStatus(linearLegSpec, true) == StatusUnknown && it->getTotalRunningTime()<=0) + continue; + } + } + + if (needParRange && it->Class != parLegRangeClass && it->Class) { + parLegRangeClass = it->Class; + parLegRangeClass->getParallelRange(linearLegSpec < 0 ? 0 : linearLegSpec, parLegRangeMin, parLegRangeMax); + if (li.subFilter(ESubFilterSameParallelNotFirst)) + parLegRangeMin++; + } + + string newKey; + printPostInfo.par.relayLegIndex = linearLegSpec; + calculatePrintPostKey(li.subHead, gdi, li.lp, &*it, 0, it->Club, it->Class, printPostInfo.counter, newKey); + if (newKey != oldKey) { + if (li.lp.pageBreak) { + if (!oldKey.empty()) + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + } + string legInfo; + if (linearLegSpec >= 0 && it->getClassRef()) { + // Specified leg + legInfo = lang.tl(", Str. X#" + li.lp.getLegName()); + } + + gdi.addStringUT(pagePageInfo, it->getClass() + legInfo); // Teamlist + + oldKey.swap(newKey); + printPostInfo.counter.level2=0; + printPostInfo.counter.level3=0; + printPostInfo.reset(); + printPostInfo.par.relayLegIndex = linearLegSpec; + formatPrintPost(li.subHead, printPostInfo, &*it, 0, it->Club, it->Class, 0,0,-1); + } + ++printPostInfo.counter; + if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2<=li.lp.filterMaxPer) { + printPostInfo.counter.level3=0; + printPostInfo.reset(); + printPostInfo.par.relayLegIndex = linearLegSpec; + formatPrintPost(li.listPost, printPostInfo, &*it, 0, it->Club, it->Class, 0, 0, -1); + + if (li.subListPost.empty()) + continue; + + if (li.listSubType==li.EBaseTypeRunner) { + int nr = int(it->Runners.size()); + vector tr; + tr.reserve(nr); + vector usedIx(nr, -1); + + for (int k=0;kRunners[k]) { + + if (li.filter(EFilterHasResult) || li.subFilter(ESubFilterHasResult) || + li.filter(EFilterHasPrelResult) || li.subFilter(ESubFilterHasPrelResult) || + li.filter(EFilterExcludeDNS) || li.subFilter(ESubFilterExcludeDNS) || + li.subFilter(ESubFilterVacant)) { + usedIx[k] = -2; // Skip totally + } + continue; + } + else + usedIx[k] = -2; // Skip unless allowed after filters + bool noResult = false; + bool noPrelResult = false; + bool noStart = false; + if (gResult == 0) { + noResult = it->Runners[k]->tStatus == StatusUnknown; + noPrelResult = it->Runners[k]->tStatus == StatusUnknown && it->Runners[k]->getRunningTime() <= 0; + noStart = it->Runners[k]->tStatus == StatusDNS; + //XXX TODO Multiday + } + else { + noResult = it->Runners[k]->tmpResult.status == StatusUnknown; + noPrelResult = it->Runners[k]->tmpResult.status == StatusUnknown && it->Runners[k]->tmpResult.runningTime <= 0; + noStart = it->Runners[k]->tmpResult.status == StatusDNS; + } + + if (noResult && (li.filter(EFilterHasResult) || li.subFilter(ESubFilterHasResult))) + continue; + + if (noPrelResult && (li.filter(EFilterHasPrelResult) || li.subFilter(ESubFilterHasPrelResult))) + continue; + + if (noStart && (li.filter(EFilterExcludeDNS) || li.subFilter(ESubFilterExcludeDNS))) + continue; + + if (it->Runners[k]->isVacant() && li.subFilter(ESubFilterVacant)) + continue; + + if ( (it->Runners[k]->tLeg < parLegRangeMin || it->Runners[k]->tLeg > parLegRangeMax) + && needParRange) + continue; + + usedIx[k] = tr.size(); + tr.push_back(it->Runners[k]); + } + + if (gResult) { + gResult->sortTeamMembers(tr); + + for (size_t k = 0; k < tr.size(); k++) { + bool suitableBreak = k<2 || (k+2)>=tr.size(); + printPostInfo.keepToghether = suitableBreak; + printPostInfo.par.relayLegIndex = tr[k] ? tr[k]->tLeg : -1; + formatPrintPost(li.subListPost, printPostInfo, &*it, tr[k], + it->Club, tr[k]->Class, 0, 0, -1); + printPostInfo.counter.level3++; + } + } + else { + for (size_t k = 0; k < usedIx.size(); k++) { + if (usedIx[k] == -2) + continue; // Skip + bool suitableBreak = k<2 || (k+2)>=usedIx.size(); + printPostInfo.keepToghether = suitableBreak; + printPostInfo.par.relayLegIndex = k; + if (usedIx[k] == -1) { + pCourse crs = it->Class ? it->Class->getCourse(k, it->StartNo) : 0; + formatPrintPost(li.subListPost, printPostInfo, &*it, 0, + it->Club, it->Class, crs, 0, k); + } + else { + formatPrintPost(li.subListPost, printPostInfo, &*it, tr[usedIx[k]], + it->Club, tr[usedIx[k]]->Class, 0, 0, -1); + } + printPostInfo.counter.level3++; + } + } + } + else if (li.listSubType==li.EBaseTypePunches) { + pRunner r=it->Runners.empty() ? 0:it->Runners[0]; + if (!r) continue; + + listGeneratePunches(li.subListPost, gdi, li.lp, &*it, r, it->Club, it->Class); + } + } + } + } + else if ( li.listType==li.EBaseTypeClub ) { + if (li.calcResults) { + calculateTeamResults(true); + calculateTeamResults(false); + } + if (li.calcCourseClassResults) + calculateResults(RTClassCourseResult); + + pair info = li.lp.getLegInfo(sampleClass); + sortTeams(li.sortOrder, info.first, info.second); + if ( li.calcResults ) { + if (li.lp.useControlIdResultTo>0 || li.lp.useControlIdResultFrom>0) + calculateSplitResults(li.lp.useControlIdResultFrom, li.lp.useControlIdResultTo); + else + calculateResults(RTClassResult); + } + else sortRunners(li.sortOrder); + + Clubs.sort(); + oClubList::iterator it; + + oRunnerList::iterator rit; + bool first = true; + for (it = Clubs.begin(); it != Clubs.end(); ++it) { + if (it->isRemoved()) + continue; + + if (li.filter(EFilterVacant)) { + if (it->getId() == getVacantClub()) + continue; + } + + if (li.filter(EFilterOnlyVacant)) { + if (it->getId() != getVacantClub()) + continue; + } + + bool startClub = false; + pRunner pLeader = 0; + + for (rit = Runners.begin(); rit != Runners.end(); ++rit) { + if (rit->isRemoved() || rit->tStatus == StatusNotCompetiting) + continue; + + if (!li.lp.selection.empty() && li.lp.selection.count(rit->getClassId())==0) + continue; + + if (!li.lp.matchLegNumber(rit->getClassRef(), rit->legToRun())) + continue; + + if (li.filter(EFilterExcludeDNS)) + if (rit->tStatus==StatusDNS) + continue; + + if (li.filter(EFilterHasResult)) { + if (li.lp.useControlIdResultTo<=0 && rit->tStatus==StatusUnknown) + continue; + else if ((li.lp.useControlIdResultTo>0 || li.lp.useControlIdResultFrom>0) && rit->tempStatus!=StatusOK) + continue; + else if (li.calcTotalResults && rit->getTotalStatus() == StatusUnknown) + continue; + } + + if (!pLeader || pLeader->Class != rit->Class) + pLeader = &*rit; + if (rit->Club == &*it) { + if (!startClub) { + if (li.lp.pageBreak) { + if (!first) + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + else + first = false; + } + gdi.addStringUT(pagePageInfo, it->getName()); + printPostInfo.counter.level2=0; + printPostInfo.counter.level3=0; + printPostInfo.reset(); + printPostInfo.par.relayLegIndex = -1; + formatPrintPost(li.subHead, printPostInfo, 0, 0, &*it, 0, 0, 0, -1); + startClub = true; + } + ++printPostInfo.counter; + if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2<=li.lp.filterMaxPer) { + printPostInfo.counter.level3=0; + printPostInfo.reset(); + printPostInfo.par.relayLegIndex = rit->tLeg; + formatPrintPost(li.listPost, printPostInfo, 0, &*rit, &*it, rit->Class, 0, 0, -1); + if (li.subListPost.empty()) + continue; + } + } + }//Runners + }//Clubs + } + else if (li.listType == oListInfo::EBaseTypeCourse) { + Courses.sort(); + oCourseList::iterator it; + for (it = Courses.begin(); it != Courses.end(); ++it) { + if (it->isRemoved()) + continue; + + if (!li.lp.selection.empty()) { + vector usageClass; + it->getClasses(usageClass); + + bool used = false; + while (!used && !usageClass.empty()) { + used = li.lp.selection.count(usageClass.back()->getId()) > 0; + usageClass.pop_back(); + } + if (!used) + continue; + } + + string newKey; + calculatePrintPostKey(li.subHead, gdi, li.lp, 0, 0, 0, 0, printPostInfo.counter, newKey); + + if (newKey != oldKey) { + if (li.lp.pageBreak) { + if (!oldKey.empty()) + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + } + + oldKey.swap(newKey); + printPostInfo.counter.level2=0; + printPostInfo.counter.level3=0; + printPostInfo.reset(); + formatPrintPost(li.subHead, printPostInfo, 0, 0, 0, 0, &*it, 0, 0); + } + if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2tInTeam, &*it, it->Club, it->Class); + } + } + ++printPostInfo.counter; + + } + } + else if (li.listType == oListInfo::EBaseTypeControl) { + Controls.sort(); + oControlList::iterator it; + for (it = Controls.begin(); it != Controls.end(); ++it) { + if (it->isRemoved()) + continue; + + string newKey; + calculatePrintPostKey(li.subHead, gdi, li.lp, 0, 0, 0, 0, printPostInfo.counter, newKey); + + if (newKey != oldKey) { + if (li.lp.pageBreak) { + if (!oldKey.empty()) + gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); + } + + oldKey.swap(newKey); + printPostInfo.counter.level2=0; + printPostInfo.counter.level3=0; + printPostInfo.reset(); + formatPrintPost(li.subHead, printPostInfo, 0, 0, 0, 0, 0, &*it, 0); + } + if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2 listMap; + getListTypes(listMap, filter); + + //gdi.clearList(name); + map::iterator it; + + vector< pair > v; + for (it=listMap.begin(); it!=listMap.end(); ++it) { + v.push_back(make_pair(it->second.Name, it->first)); + //gdi.addItem(name, it->second.Name, it->first); + } + sort(v.begin(), v.end()); + gdi.addItem(name, v); +} + +void oEvent::getListType(EStdListType type, oListInfo &li) +{ + map listMap; + getListTypes(listMap, false); + li = listMap[type]; +} + + +void oEvent::getListTypes(map &listMap, int filterResults) +{ + listMap.clear(); + + if (!filterResults) { + oListInfo li; + li.Name=lang.tl("Startlista, individuell"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = true; + listMap[EStdStartList]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Resultat, individuell"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = true; + li.supportFrom = true; + li.supportTo = true; + listMap[EStdResultList]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Resultat, generell"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = true; + li.supportLarge = true; + li.supportFrom = true; + li.supportTo = true; + li.calcTotalResults = true; + listMap[EGeneralResultList]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Rogaining, individuell"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = true; + listMap[ERogainingInd]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Avgjorda klasser (prisutdelningslista)"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = true; + listMap[EIndPriceList]=li; + } + if (!filterResults) { + oListInfo li; + li.Name=lang.tl("Startlista, patrull"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + + listMap[EStdPatrolStartList]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Resultat, patrull"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + + listMap[EStdPatrolResultList]=li; + } + + { + oListInfo li; + li.Name="Patrullresultat (STOR)"; + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + li.largeSize = true; + listMap[EStdPatrolResultListLARGE]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Resultat (STOR)"); + li.supportClasses = true; + li.supportLegs = true; + li.supportFrom = true; + li.supportTo = true; + li.largeSize = true; + li.listType=li.EBaseTypeRunner; + listMap[EStdResultListLARGE]=li; + } + + /*{ + oListInfo li; + li.Name=lang.tl("Stafettresultat, sträcka (STOR)"); + li.supportClasses = true; + li.supportLegs = true; + li.largeSize = true; + li.listType=li.EBaseTypeTeam; + listMap[EStdTeamResultListLegLARGE]=li; + }*/ + + if (!filterResults) { + oListInfo li; + li.Name=lang.tl("Hyrbricksrapport"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = false; + li.supportLegs = false; + listMap[EStdRentedCard]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Stafettresultat, delsträckor"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + listMap[EStdTeamResultListAll]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Stafettresultat, lag"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + listMap[EStdTeamResultList]=li; + } + /* + { + oListInfo li; + li.Name=lang.tl("Stafettresultat, sträcka"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = true; + listMap[EStdTeamResultListLeg]=li; + }*/ + + if (!filterResults) { + { + oListInfo li; + li.Name=lang.tl("Startlista, stafett (lag)"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + listMap[EStdTeamStartList]=li; + } + { + oListInfo li; + li.Name=lang.tl("Startlista, stafett (sträcka)"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = true; + listMap[EStdTeamStartListLeg]=li; + } + { + oListInfo li; + li.Name=lang.tl("Bantilldelning, stafett"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + listMap[ETeamCourseList]=li; + } + { + oListInfo li; + li.Name=lang.tl("Bantilldelning, individuell"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = false; + listMap[EIndCourseList]=li; + } + { + oListInfo li; + li.Name=lang.tl("Individuell startlista, visst lopp"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = true; + listMap[EStdIndMultiStartListLeg]=li; + } + } + + { + oListInfo li; + li.Name=lang.tl("Individuell resultatlista, visst lopp"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = true; + listMap[EStdIndMultiResultListLeg]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Individuell resultatlista, visst lopp (STOR)"); + li.listType=li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = true; + li.largeSize = true; + listMap[EStdIndMultiResultListLegLARGE]=li; + } + + { + oListInfo li; + li.Name = lang.tl("Individuell resultatlista, alla lopp"); + li.listType = li.EBaseTypeTeam; + li.supportClasses = true; + li.supportLegs = false; + listMap[EStdIndMultiResultListAll]=li; + } + + if (!filterResults) { + oListInfo li; + li.Name = lang.tl("Klubbstartlista"); + li.listType = li.EBaseTypeClub; + li.supportClasses = true; + li.supportLegs = false; + listMap[EStdClubStartList]=li; + } + + { + oListInfo li; + li.Name = lang.tl("Klubbresultatlista"); + li.listType = li.EBaseTypeClub; + li.supportClasses = true; + li.supportLegs = false; + listMap[EStdClubResultList]=li; + } + + if (!filterResults) { + { + oListInfo li; + li.Name=lang.tl("Tävlingsrapport"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedReport]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Kontroll inför tävlingen"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedPreReport]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Kvar-i-skogen"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedInForest]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Fakturor"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedInvoices]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Ekonomisk sammanställning"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedEconomy]=li; + } + } + /* + { + oListInfo li; + li.Name=lang.tl("Först-i-mål, klassvis"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedResultFinishPerClass]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Först-i-mål, gemensam"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedResultFinish]=li; + }*/ + + if (!filterResults) { + oListInfo li; + li.Name=lang.tl("Minutstartlista"); + li.supportClasses = false; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedMinuteStartlist]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Händelser - tidslinje"); + li.supportClasses = true; + li.supportLegs = false; + li.listType=li.EBaseTypeNone; + listMap[EFixedTimeLine]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Liveresultat, deltagare"); + li.listType=li.EBaseTypeRunner; + li.supportClasses = true; + li.supportLegs = false; + li.supportFrom = true; + li.supportTo = true; + li.supportSplitAnalysis = false; + li.supportInterResults = false; + li.supportPageBreak = false; + li.supportClassLimit = false; + li.supportCustomTitle = false; + + listMap[EFixedLiveResult]=li; + } + + { + oListInfo li; + li.Name=lang.tl("Stafettresultat, sträcka (STOR)"); + li.supportClasses = true; + li.supportLegs = false; + li.largeSize = true; + li.listType=li.EBaseTypeTeam; + listMap[EStdTeamAllLegLARGE]=li; + } + + getListContainer().setupListInfo(EFirstLoadedList, listMap, filterResults != 0); +} + + +void oEvent::generateListInfo(EStdListType lt, const gdioutput &gdi, int classId, oListInfo &li) +{ + oListParam par; + + if (classId!=0) + par.selection.insert(classId); + + par.listCode=lt; + + generateListInfo(par, gdi.getLineHeight(), li); +} + +int openRunnerTeamCB(gdioutput *gdi, int type, void *data); + +void oEvent::generateFixedList(gdioutput &gdi, const oListInfo &li) +{ + string dmy; + switch (li.lp.listCode) { + case EFixedPreReport: + generatePreReport(gdi); + break; + + case EFixedReport: + generateCompetitionReport(gdi); + break; + + case EFixedInForest: + generateInForestList(gdi, openRunnerTeamCB, 0); + break; + + case EFixedEconomy: + printInvoices(gdi, IPTAllPrint, dmy, true); + break; + + case EFixedInvoices: + printInvoices(gdi, IPTAllPrint, dmy, false); + break; + + case EFixedMinuteStartlist: + generateMinuteStartlist(gdi); + break; + + case EFixedLiveResult: + + + break; + + case EFixedTimeLine: + gdi.clearPage(false); + gdi.addString("", boldLarge, MakeDash("Tidslinje - X#" + getName())); + + gdi.dropLine(); + set<__int64> stored; + vector events; + + map cName; + for (oClassList::const_iterator it = Classes.begin(); it != Classes.end(); ++it) { + if (!it->isRemoved()) + cName[it->getId()] = it->getName(); + } + + oe->getTimeLineEvents(li.lp.selection, events, stored, 3600*24*7); + gdi.fillDown(); + int yp = gdi.getCY(); + int xp = gdi.getCX(); + + int w1 = gdi.scaleLength(60); + int w = gdi.scaleLength(110); + int w2 = w1+w; + + for (size_t k = 0; k(ev.getSource(*this)); + if (!r) + continue; + + if (ev.getType() == oTimeLine::TLTFinish && r->getStatus() != StatusOK) + continue; + + string name = ""; + if (r) + name = r->getCompleteIdentification() + " "; + + gdi.addStringUT(yp, xp, 0, oe->getAbsTime(ev.getTime())); + gdi.addStringUT(yp, xp + w1, 0, cName[ev.getClassId()], w-10); + gdi.addStringUT(yp, xp + w2, 0, name + lang.tl(ev.getMessage())); + + yp += gdi.getLineHeight(); + + + /*string detail = ev.getDetail(); + + if (detail.size() > 0) { + gdi.addStringUT(yp, xp + w, 0, detail); + yp += gdi.getLineHeight(); + }*/ + + } + gdi.refresh(); + + break; + } +} + +void oListInfo::setCallback(GUICALLBACK cb) { + lp.cb=cb; + for (list::iterator it = next.begin(); it != next.end(); ++it) { + it->setCallback(cb); + } +} + +void oEvent::generateListInfo(oListParam &par, int lineHeight, oListInfo &li) { + vector parV(1, par); + generateListInfo(parV, lineHeight, li); +} + +void oEvent::generateListInfo(vector &par, int lineHeight, oListInfo &li) { + loadGeneralResults(false); + lineHeight = 14; + for (size_t k = 0; k < par.size(); k++) { + par[k].cb = 0; + } + + map listMap; + getListTypes(listMap, false); + + if (par.size() == 1) { + generateListInfoAux(par[0], lineHeight, li, listMap[par[0].listCode].Name); + set used; + // Add linked lists + oListParam *cPar = &par[0]; + while (cPar->nextList>0) { + if (used.count(cPar->nextList)) + break; // Circular definition + used.insert(cPar->nextList); + used.insert(cPar->previousList); + oListParam &nextPar = oe->getListContainer().getParam(cPar->nextList-1); + li.next.push_back(oListInfo()); + nextPar.cb = 0; + generateListInfoAux(nextPar, lineHeight, li.next.back(), ""); + cPar = &nextPar; + } + } + else { + for (size_t k = 0; k < par.size(); k++) { + if (k > 0) { + li.next.push_back(oListInfo()); + } + generateListInfoAux(par[k], lineHeight, k == 0 ? li : li.next.back(), + li.Name = listMap[par[0].listCode].Name); + } + } +} + +void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li, const string &name) { + const int lh=lineHeight; + const int vspace=lh/2; + int bib; + pair ln; + const double scale = 1.8; + + string ttl; + Position pos; + + pClass sampleClass = 0; + if (!par.selection.empty()) + sampleClass = getClass(*par.selection.begin()); + if (!sampleClass && !Classes.empty()) + sampleClass = &*Classes.begin(); + + EStdListType lt=par.listCode; + li=oListInfo(); + li.lp = par; + li.Name = name; + li.lp.defaultName = li.Name; + if (par.defaultName.empty()) + par.defaultName = li.Name; + if (par.name.empty()) + par.name = li.Name; + if (li.lp.name.empty()) + li.lp.name = li.Name; + + switch (lt) { + case EStdStartList: { + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Startlista - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + + int bib = 0; + int rank = 0; + if (hasBib(true, false)) { + li.addListPost(oPrintPost(lRunnerBib, "", normalText, 0, 0)); + bib=40; + } + li.addListPost(oPrintPost(lRunnerStart, "", normalText, 0+bib, 0)); + li.addListPost(oPrintPost(lPatrolNameNames, "", normalText, 70+bib, 0)); + li.addListPost(oPrintPost(lPatrolClubNameNames, "", normalText, 300+bib, 0)); + if (hasRank()) { + li.addListPost(oPrintPost(lRunnerRank, "", normalText, 470+bib, 0)); + rank = 50; + } + li.addListPost(oPrintPost(lRunnerCard, "", normalText, 470+bib+rank, 0)); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 12)); + li.addSubHead(oPrintPost(lClassLength, lang.tl("%s meter"), boldText, 300+bib, 12)); + li.addSubHead(oPrintPost(lClassStartName, "", boldText, 470+bib+rank, 12)); + li.addSubHead(oPrintPost(lString, "", boldText, 470+bib, 16)); + + li.listType=li.EBaseTypeRunner; + li.sortOrder=ClassStartTime; + li.setFilter(EFilterExcludeDNS); + break; + } + + case EStdClubStartList: { + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Klubbstartlista - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + + if (hasBib(true, true)) { + pos.add("bib", 40); + li.addListPost(oPrintPost(lRunnerBib, "", normalText, 0, 0)); + } + + pos.add("start", li.getMaxCharWidth(this, par.selection, lRunnerStart, "", normalText)); + li.addListPost(oPrintPost(lRunnerStart, "", normalText, pos.get("start"), 0)); + + if (hasRank()) { + pos.add("rank", 50); + li.addListPost(oPrintPost(lRunnerRank, "", normalText, pos.get("rank"), 0)); + } + pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerName, "", normalText)); + li.addListPost(oPrintPost(lPatrolNameNames, "", normalText, pos.get("name"), 0)); + pos.add("class", li.getMaxCharWidth(this, par.selection, lClassName, "", normalText)); + li.addListPost(oPrintPost(lClassName, "", normalText, pos.get("class"), 0)); + pos.add("length", li.getMaxCharWidth(this, par.selection, lClassLength, "%s m", normalText)); + li.addListPost(oPrintPost(lClassLength, lang.tl("%s m"), normalText, pos.get("length"), 0)); + pos.add("sname", li.getMaxCharWidth(this, par.selection, lClassStartName, "", normalText)); + li.addListPost(oPrintPost(lClassStartName, "", normalText, pos.get("sname"), 0)); + + pos.add("card", 70); + li.addListPost(oPrintPost(lRunnerCard, "", normalText, pos.get("card"), 0)); + + li.addSubHead(oPrintPost(lClubName, "", boldText, 0, 12)); + li.addSubHead(oPrintPost(lString, "", boldText, 100, 16)); + + li.listType=li.EBaseTypeClub; + li.sortOrder=ClassTeamLeg; + li.setFilter(EFilterExcludeDNS); + li.setFilter(EFilterVacant); + break; + } + + case EStdClubResultList: { + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Klubbresultatlista - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + + pos.add("class", li.getMaxCharWidth(this, par.selection, lClassName, "", normalText)); + li.addListPost(oPrintPost(lClassName, "", normalText, pos.get("class"), 0)); + + pos.add("place", 40); + li.addListPost(oPrintPost(lRunnerPlace, "", normalText, pos.get("place"), 0)); + + pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, "", normalText)); + li.addListPost(oPrintPost(lRunnerName, "", normalText, pos.get("name"), 0)); + + pos.add("time", li.getMaxCharWidth(this, par.selection, lRunnerTimeStatus, "", normalText)); + li.addListPost(oPrintPost(lRunnerTimeStatus, "", normalText, pos.get("time"), 0)); + + pos.add("after", li.getMaxCharWidth(this, par.selection, lRunnerTimeAfter, "", normalText)); + li.addListPost(oPrintPost(lRunnerTimeAfter, "", normalText, pos.get("after"), 0)); + + li.addSubHead(oPrintPost(lClubName, "", boldText, 0, 12)); + li.addSubHead(oPrintPost(lString, "", boldText, 100, 16)); + + li.listType=li.EBaseTypeClub; + li.sortOrder=ClassResult; + li.calcResults = true; + li.setFilter(EFilterVacant); + break; + } + + case EStdRentedCard: + { + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Hyrbricksrapport - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + + li.addListPost(oPrintPost(lTotalCounter, "%s", normalText, 0, 0)); + li.addListPost(oPrintPost(lRunnerCard, "", normalText, 30, 0)); + li.addListPost(oPrintPost(lRunnerName, "", normalText, 130, 0)); + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + + li.setFilter(EFilterHasCard); + li.setFilter(EFilterRentCard); + li.setFilter(EFilterExcludeDNS); + li.listType=li.EBaseTypeRunner; + li.sortOrder=ClassStartTime; + break; + } + + case EStdResultList: { + string stitle; + getResultTitle(*this, li.lp, stitle); + stitle = par.getCustomTitle(stitle); + + li.addHead(oPrintPost(lCmpName, MakeDash(stitle), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + pos.add("place", 25); + pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, "", normalText, 0, false, 25)); + pos.add("club", li.getMaxCharWidth(this, par.selection, lPatrolClubNameNames, "", normalText, 0, false, 25)); + pos.add("status", 50); + pos.add("after", 50); + pos.add("missed", 50); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + + li.addListPost(oPrintPost(lRunnerPlace, "", normalText, pos.get("place"), 0)); + li.addListPost(oPrintPost(lPatrolNameNames, "", normalText, pos.get("name"), 0)); + li.addListPost(oPrintPost(lPatrolClubNameNames, "", normalText, pos.get("club"), 0)); + + if (li.lp.useControlIdResultTo<=0 && li.lp.useControlIdResultFrom<=0) { + li.addSubHead(oPrintPost(lClassResultFraction, "", boldText, pos.get("club"), 10)); + + li.addListPost(oPrintPost(lRunnerTimeStatus, "", normalText, pos.get("status"), 0)); + li.addListPost(oPrintPost(lRunnerTimeAfter, "", normalText, pos.get("after"), 0)); + if (li.lp.showInterTimes) { + li.addSubListPost(oPrintPost(lPunchNamedTime, "", italicSmall, pos.get("name"), 0, make_pair(1, true))); + li.subListPost.back().fixedWidth = 160; + li.listSubType = li.EBaseTypePunches; + } + else if (li.lp.showSplitTimes) { + li.addSubListPost(oPrintPost(lPunchTime, "", italicSmall, pos.get("name"), 0, make_pair(1, true))); + li.subListPost.back().fixedWidth = 95; + li.listSubType = li.EBaseTypePunches; + } + } + else { + li.needPunches = true; + li.addListPost(oPrintPost(lRunnerTempTimeStatus, "", normalText, pos.get("status"), 0)); + li.addListPost(oPrintPost(lRunnerTempTimeAfter, "", normalText, pos.get("after"), 0)); + } + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, pos.get("status"), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldText, pos.get("after"), 10)); + + if (li.lp.splitAnalysis) { + li.addListPost(oPrintPost(lRunnerMissedTime, "", normalText, pos.get("missed"), 0)); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldText, pos.get("missed"), 10)); + } + + li.calcResults = true; + li.listType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.supportFrom = true; + li.supportTo = true; + li.setFilter(EFilterHasPrelResult); + break; + } + case EGeneralResultList: { + string stitle; + getResultTitle(*this, li.lp, stitle); + stitle = par.getCustomTitle(stitle); + + gdiFonts normal, header, small; + double s; + + if (par.useLargeSize) { + s = scale; + normal = fontLarge; + header = boldLarge; + small = normalText; + } + else { + s = 1.0; + normal = normalText; + header = boldText; + small = italicSmall; + } + + li.addHead(oPrintPost(lCmpName, MakeDash(stitle), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + pos.add("place", li.getMaxCharWidth(this, par.selection, lRunnerGeneralPlace, "", normalText)); + pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerCompleteName, "", normalText)); + pos.add("status", li.getMaxCharWidth(this, par.selection, lRunnerGeneralTimeStatus, "", normalText)); + pos.add("after", li.getMaxCharWidth(this, par.selection, lRunnerGeneralTimeAfter, "", normalText)); + pos.add("missed", 50); + + li.addSubHead(oPrintPost(lClassName, "", header, 0, 10)); + + li.addListPost(oPrintPost(lRunnerGeneralPlace, "", normal, pos.get("place", s), 0)); + li.addListPost(oPrintPost(lRunnerCompleteName, "", normal, pos.get("name", s), 0)); + + if (li.lp.useControlIdResultTo<=0 && li.lp.useControlIdResultFrom<=0) { + li.addListPost(oPrintPost(lRunnerGeneralTimeStatus, "", normal, pos.get("status", s), 0)); + li.addListPost(oPrintPost(lRunnerGeneralTimeAfter, "", normal, pos.get("after", s), 0)); + if (li.lp.showInterTimes) { + li.addSubListPost(oPrintPost(lPunchNamedTime, "", small, pos.get("name", s), 0, make_pair(1, true))); + li.subListPost.back().fixedWidth = 160; + li.listSubType = li.EBaseTypePunches; + } + else if (li.lp.showSplitTimes) { + li.addSubListPost(oPrintPost(lPunchTime, "", small, pos.get("name", s), 0, make_pair(1, true))); + li.subListPost.back().fixedWidth = 95; + li.listSubType = li.EBaseTypePunches; + } + } + else { + li.needPunches = true; + li.addListPost(oPrintPost(lRunnerTempTimeStatus, "", normal, pos.get("status", s), 0)); + li.addListPost(oPrintPost(lRunnerTempTimeAfter, "", normal, pos.get("after", s), 0)); + } + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), header, pos.get("status", s), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), header, pos.get("after", s), 10)); + + li.calcResults = true; + li.listType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasPrelResult); + li.supportFrom = true; + li.supportTo = true; + li.calcTotalResults = true; + break; + } + case EIndPriceList: + + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Avgjorda placeringar - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCurrentTime, lang.tl("Genererad: ") + "%s", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + pos.add("place", 25); + pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, "", normalText)); + pos.add("club", li.getMaxCharWidth(this, par.selection, lPatrolClubNameNames, "", normalText)); + pos.add("status", 80); + pos.add("info", 80); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldText, pos.get("club"), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, pos.get("status"), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Avgörs kl"), boldText, pos.get("info"), 10)); + + li.addListPost(oPrintPost(lRunnerPlace, "", normalText, pos.get("place"), 0)); + li.addListPost(oPrintPost(lPatrolNameNames, "", normalText, pos.get("name"), 0)); + li.addListPost(oPrintPost(lPatrolClubNameNames, "", normalText, pos.get("club"), 0)); + li.addListPost(oPrintPost(lRunnerTimeStatus, "", normalText, pos.get("status"), 0)); + li.addListPost(oPrintPost(lRunnerTimePlaceFixed, "", normalText, pos.get("info"), 0)); + + li.calcResults = true; + li.listType = li.EBaseTypeRunner; + li.sortOrder = ClassResult; + li.setFilter(EFilterHasResult); + break; + + case EStdTeamResultList: + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Resultatsammanställning - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", normalText, 280, 14)); + + //Use last leg for every team (index=-1) + li.addListPost(oPrintPost(lTeamPlace, "", normalText, 0, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamName, "", normalText, 25, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamTimeStatus, "", normalText, 280, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamTimeAfter, "", normalText, 340, 5, make_pair(-1, true))); + + li.lp.setLegNumberCoded(-1); + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.listSubType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + + case EStdTeamResultListAll: + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Resultat - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldText, 280, 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, 400, 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldText, 460, 14)); + + //Use last leg for every team (index=-1) + li.addListPost(oPrintPost(lTeamPlace, "", normalText, 0, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamName, "", normalText, 25, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamTimeStatus, "", normalText, 400, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamTimeAfter, "", normalText, 460, 5, make_pair(-1, true))); + + li.addSubListPost(oPrintPost(lRunnerLegNumberAlpha, "%s.", normalText, 25, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lRunnerName, "", normalText, 45, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lRunnerTimeStatus, "", normalText, 280, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lTeamLegTimeStatus, "", normalText, 400, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lTeamLegTimeAfter, "", normalText, 460, 0, make_pair(0, true))); + + if (li.lp.splitAnalysis) { + li.addSubListPost(oPrintPost(lRunnerMissedTime, "", normalText, 510, 0)); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldText, 510, 14)); + } + + li.lp.setLegNumberCoded(-1); + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.listSubType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + + case unused_EStdTeamResultListLeg: { + char title[256]; + if (li.lp.getLegNumberCoded() != 1000) + sprintf_s(title, (lang.tl("Resultat efter sträcka X#" + li.lp.getLegName())+" - %%s").c_str()); + else + sprintf_s(title, (lang.tl("Resultat efter sträckan")+" - %%s").c_str()); + + pos.add("place", 25); + pos.add("team", li.getMaxCharWidth(this, par.selection, lTeamName, "", normalText)); + pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerName, "", normalText)); + pos.add("status", 50); + pos.add("teamstatus", 50); + pos.add("after", 50); + pos.add("missed", 50); + + li.addHead(oPrintPost(lCmpName, MakeDash(title), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addSubHead(oPrintPost(lClassName, "", boldText, pos.get("place"), 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldText, pos.get("name"), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, pos.get("status"), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Totalt"), boldText, pos.get("teamstatus"), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldText, pos.get("after"), 14)); + + ln = li.lp.getLegInfo(sampleClass); + li.addListPost(oPrintPost(lTeamPlace, "", normalText, pos.get("place"), 2, ln)); + li.addListPost(oPrintPost(lTeamName, "", normalText, pos.get("team"), 2, ln)); + li.addListPost(oPrintPost(lRunnerName, "", normalText, pos.get("name"), 2, ln)); + li.addListPost(oPrintPost(lRunnerTimeStatus, "", normalText, pos.get("status"), 2, ln)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", normalText, pos.get("teamstatus"), 2, ln)); + li.addListPost(oPrintPost(lTeamTimeAfter, "", normalText, pos.get("after"), 2, ln)); + + if (li.lp.splitAnalysis) { + li.addListPost(oPrintPost(lRunnerMissedTime, "", normalText, pos.get("missed"), 2, ln)); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldText, pos.get("missed"), 14)); + } + + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + } + case unused_EStdTeamResultListLegLARGE: { + char title[256]; + if (li.lp.getLegNumberCoded() != 1000) + sprintf_s(title, ("%%s - "+lang.tl("sträcka X#" + li.lp.getLegName())).c_str()); + else + sprintf_s(title, ("%%s - "+lang.tl("slutsträckan")).c_str()); + + pos.add("place", 25); + pos.add("team", min(120, li.getMaxCharWidth(this, par.selection, lTeamName, "", normalText))); + pos.add("name", min(120, li.getMaxCharWidth(this, par.selection, lRunnerName, "", normalText))); + pos.add("status", 50); + pos.add("teamstatus", 50); + pos.add("after", 50); + pos.add("missed", 50); + + li.addSubHead(oPrintPost(lClassName, MakeDash(title), boldLarge, pos.get("place", scale), 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldLarge, pos.get("name", scale), 14)); + + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldLarge, pos.get("status", scale), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Totalt"), boldLarge, pos.get("teamstatus", scale), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldLarge, pos.get("after", scale), 14)); + + ln = li.lp.getLegInfo(sampleClass); + li.addListPost(oPrintPost(lTeamPlace, "", fontLarge, pos.get("place", scale), 5, ln)); + li.addListPost(oPrintPost(lTeamName, "", fontLarge, pos.get("team", scale), 5, ln)); + li.addListPost(oPrintPost(lRunnerName, "", fontLarge, pos.get("name", scale), 5, ln)); + li.addListPost(oPrintPost(lRunnerTimeStatus, "", fontLarge, pos.get("status", scale), 5, ln)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", fontLarge, pos.get("teamstatus", scale), 5, ln)); + li.addListPost(oPrintPost(lTeamTimeAfter, "", fontLarge, pos.get("after", scale), 5, ln)); + + if (li.lp.splitAnalysis) { + li.addListPost(oPrintPost(lRunnerMissedTime, "", fontLarge, pos.get("missed", scale), 5, ln)); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldLarge, pos.get("missed", scale), 14)); + } + + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + } + case EStdTeamStartList: + { + MetaList mList; + mList.setListName("Startlista, stafett"); + mList.addToHead(lCmpName).setText("Startlista - X");; + mList.newHead(); + mList.addToHead(lCmpDate); + + mList.addToSubHead(lClassName); + mList.addToSubHead(MetaListPost(lClassStartTime, lNone)); + mList.addToSubHead(MetaListPost(lClassLength, lNone)).setText("X meter"); + mList.addToSubHead(MetaListPost(lClassStartName, lNone)); + + mList.addToList(lTeamBib); + mList.addToList(lTeamStartCond); + mList.addToList(lTeamName); + + mList.addToSubList(lRunnerLegNumberAlpha).align(lTeamName, false).setText("X."); + mList.addToSubList(lRunnerName); + mList.addToSubList(lRunnerCard).align(lClassStartName); + + mList.interpret(this, gdibase, par, lh, li); + } + li.listType=li.EBaseTypeTeam; + li.listSubType=li.EBaseTypeRunner; + //li.setFilter(EFilterExcludeDNS); + li.setSubFilter(ESubFilterVacant); + li.sortOrder = ClassStartTime; + break; + + case ETeamCourseList: + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Bantilldelningslista - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + li.listType=li.EBaseTypeTeam; + + bib=0; + li.addListPost(oPrintPost(lTeamBib, "", normalText, 0+bib, 4)); + li.addListPost(oPrintPost(lTeamName, "", normalText, 50+bib, 4)); + li.addListPost(oPrintPost(lTeamClub, "", normalText, 300+bib, 4)); + + li.listSubType=li.EBaseTypeRunner; + li.addSubListPost(oPrintPost(lRunnerLegNumberAlpha, "%s.", normalText, 25+bib, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lRunnerName, "", normalText, 50+bib, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lRunnerCard, "", normalText, 300+bib, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lRunnerCourse, "", normalText, 400+bib, 0, make_pair(0, true))); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Bricka"), boldText, 300+bib, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Bana"), boldText, 400+bib, 10)); + + li.sortOrder = ClassStartTime; + break; + + case EIndCourseList: { + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Bantilldelningslista - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + li.listType=li.EBaseTypeRunner; + + bib=0; + li.addListPost(oPrintPost(lRunnerBib, "", normalText, 0+bib, 0)); + oPrintPost &rn = li.addListPost(oPrintPost(lRunnerName, "", normalText, 50+bib, 0)); + rn.doMergeNext = true; + li.addListPost(oPrintPost(lRunnerClub, " (%s)", normalText, 50+bib, 0)); + li.addListPost(oPrintPost(lRunnerCard, "", normalText, 300+bib, 0)); + li.addListPost(oPrintPost(lRunnerCourse, "", normalText, 400+bib, 0)); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Bricka"), boldText, 300+bib, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Bana"), boldText, 400+bib, 10)); + + li.sortOrder = ClassStartTime; + break; + } + case EStdTeamStartListLeg: { + char title[256]; + if (li.lp.getLegNumberCoded() == 1000) + throw std::exception("Ogiltigt val av sträcka"); + + sprintf_s(title, lang.tl("Startlista %%s - sträcka X#" + li.lp.getLegName()).c_str()); + + li.addHead(oPrintPost(lCmpName, MakeDash(title), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + + ln=li.lp.getLegInfo(sampleClass); + li.listType=li.EBaseTypeTeam; + bib=0; + if (hasBib(false, true)) { + li.addListPost(oPrintPost(lTeamBib, "", normalText, 0, 0)); + bib=40; + } + li.addListPost(oPrintPost(lTeamStart, "", normalText, 0+bib, 0, ln)); + li.addListPost(oPrintPost(lTeamName, "", normalText, 70+bib, 0, ln)); + li.addListPost(oPrintPost(lTeamRunner, "", normalText, 300+bib, 0, ln)); + li.addListPost(oPrintPost(lTeamRunnerCard, "", normalText, 520+bib, 0, ln)); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + li.addSubHead(oPrintPost(lClassStartName, "", normalText, 300+bib, 10)); + + li.sortOrder=ClassStartTime; + //li.setFilter(EFilterExcludeDNS); + break; + } + case EStdIndMultiStartListLeg: + if (li.lp.getLegNumberCoded() == 1000) + throw std::exception("Ogiltigt val av sträcka"); + + //sprintf_s(title, lang.tl("Startlista lopp %d - %%s").c_str(), li.lp.legNumber+1); + ln=li.lp.getLegInfo(sampleClass); + + ttl = MakeDash(lang.tl("Startlista lopp X - Y#" + li.lp.getLegName() + "#%s")); + li.addHead(oPrintPost(lCmpName, ttl, boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + + li.listType=li.EBaseTypeTeam; + bib=0; + if (hasBib(false, true)) { + li.addListPost(oPrintPost(lTeamBib, "", normalText, 0, 0)); + bib=40; + } + li.addListPost(oPrintPost(lTeamStart, "", normalText, 0+bib, 0, ln)); + li.addListPost(oPrintPost(lTeamRunner, "", normalText, 70+bib, 0, ln)); + li.addListPost(oPrintPost(lTeamClub, "", normalText, 300+bib, 0, ln)); + li.addListPost(oPrintPost(lTeamRunnerCard, "", normalText, 500+bib, 0, ln)); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + li.addSubHead(oPrintPost(lClassLength, lang.tl("%s meter"), boldText, 300+bib, 10, ln)); + li.addSubHead(oPrintPost(lClassStartName, "", boldText, 500+bib, 10, ln)); + + li.sortOrder=ClassStartTime; + li.setFilter(EFilterExcludeDNS); + break; + + case EStdIndMultiResultListLeg: + ln=li.lp.getLegInfo(sampleClass); + + if (li.lp.getLegNumberCoded() != 1000) + ttl = lang.tl("Resultat lopp X - Y#" + li.lp.getLegName() + "#%s"); + else + ttl = lang.tl("Resultat - X#%s"); + + li.addHead(oPrintPost(lCmpName, MakeDash(ttl), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldText, 260, 14)); + + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, 460, 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Totalt"), boldText, 510, 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldText, 560, 14)); + + li.addListPost(oPrintPost(lTeamPlace, "", normalText, 0, 0, ln)); + li.addListPost(oPrintPost(lRunnerName, "", normalText, 40, 0, ln)); + li.addListPost(oPrintPost(lRunnerClub, "", normalText, 260, 0, ln)); + + li.addListPost(oPrintPost(lRunnerTimeStatus, "", normalText, 460, 0, ln)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", normalText, 510, 0, ln)); + li.addListPost(oPrintPost(lTeamTimeAfter, "", normalText, 560, 0, ln)); + + if (li.lp.splitAnalysis) { + li.addListPost(oPrintPost(lRunnerMissedTime, "", normalText, 620, 0, ln)); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldText, 620, 14)); + } + + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + + case EStdIndMultiResultListLegLARGE: + if (li.lp.getLegNumberCoded() == 1000) + throw std::exception("Ogiltigt val av sträcka"); + + ln=li.lp.getLegInfo(sampleClass); + + pos.add("place", 25); + pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerName, "", normalText)); + pos.add("club", li.getMaxCharWidth(this, par.selection, lRunnerClub, "", normalText)); + + pos.add("status", 50); + pos.add("teamstatus", 50); + pos.add("after", 50); + + ttl = "%s - " + lang.tl("Lopp ") + li.lp.getLegName(); + li.addSubHead(oPrintPost(lClassName, MakeDash(ttl), boldLarge, pos.get("place", scale), 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldLarge, pos.get("club", scale), 14)); + + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldLarge, pos.get("status", scale), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Totalt"), boldLarge, pos.get("teamstatus", scale), 14)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldLarge, pos.get("after", scale), 14)); + + li.addListPost(oPrintPost(lTeamPlace, "", fontLarge, pos.get("place", scale), 0, ln)); + li.addListPost(oPrintPost(lRunnerName, "", fontLarge, pos.get("name", scale), 0, ln)); + li.addListPost(oPrintPost(lRunnerClub, "", fontLarge, pos.get("club", scale), 0, ln)); + + li.addListPost(oPrintPost(lRunnerTimeStatus, "", fontLarge, pos.get("status", scale), 0, ln)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", fontLarge, pos.get("teamstatus", scale), 0, ln)); + li.addListPost(oPrintPost(lTeamTimeAfter, "", fontLarge, pos.get("after", scale), 0, ln)); + + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + + case EStdIndMultiResultListAll: + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Resultat - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 14)); + li.addSubHead(oPrintPost(lClassResultFraction, "", boldText, 280, 14)); + li.addSubHead(oPrintPost(lClassResultFraction, lang.tl("Tid"), boldText, 480, 14)); + li.addSubHead(oPrintPost(lClassResultFraction, lang.tl("Efter"), boldText, 540, 14)); + + //Use last leg for every team (index=-1) + li.addListPost(oPrintPost(lTeamPlace, "", normalText, 0, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lRunnerName, "", normalText, 25, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lRunnerClub, "", normalText, 280, 5, make_pair(-1, true))); + + li.addListPost(oPrintPost(lTeamTimeStatus, "", normalText, 480, 5, make_pair(-1, true))); + li.addListPost(oPrintPost(lTeamTimeAfter, "", normalText, 540, 5, make_pair(-1, true))); + + li.addSubListPost(oPrintPost(lSubSubCounter, lang.tl("Lopp %s"), normalText, 25, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lRunnerTimeStatus, "", normalText, 90, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lTeamLegTimeStatus, "", normalText, 150, 0, make_pair(0, true))); + li.addSubListPost(oPrintPost(lTeamLegTimeAfter, "", normalText, 210, 0, make_pair(0, true))); + + li.lp.setLegNumberCoded(-1); + li.calcResults=true; + li.listType=li.EBaseTypeTeam; + li.listSubType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.setFilter(EFilterHasResult); + break; + case EStdPatrolStartList: + { + MetaList mList; + mList.setListName("Startlista, patrull"); + + mList.addToHead(lCmpName).setText("Startlista - X").align(false); + mList.newHead(); + mList.addToHead(lCmpDate).align(false); + + mList.addToSubHead(lClassName); + mList.addToSubHead(lClassStartTime); + mList.addToSubHead(lClassLength).setText("X meter"); + mList.addToSubHead(lClassStartName); + + mList.addToList(lTeamBib); + mList.addToList(lTeamStartCond).setLeg(0); + mList.addToList(lTeamName); + + mList.newListRow(); + + mList.addToList(MetaListPost(lTeamRunner, lTeamName, 0)); + mList.addToList(MetaListPost(lTeamRunnerCard, lAlignNext, 0)); + mList.addToList(MetaListPost(lTeamRunner, lAlignNext, 1)); + mList.addToList(MetaListPost(lTeamRunnerCard, lAlignNext, 1)); + + mList.setListType(li.EBaseTypeTeam); + mList.setSortOrder(ClassStartTime); + mList.addFilter(EFilterExcludeDNS); + +/* xmlparser xfoo, xbar; + xfoo.openMemoryOutput(true); + + mList.save(xfoo); + + string res; + xfoo.getMemoryOutput(res); + xbar.readMemory(res, 0); + + MetaList mList2; + mList2.load(xbar.getObject("MeOSListDefinition")); +*/ + mList.interpret(this, gdibase, par, lh, li); + break; + } + case EStdPatrolResultList: + li.addHead(oPrintPost(lCmpName, MakeDash(lang.tl("Resultatlista - %s")), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addListPost(oPrintPost(lTeamPlace, "", normalText, 0, vspace, make_pair(1, true))); + li.addListPost(oPrintPost(lTeamName, "", normalText, 70, vspace)); + //li.addListPost(oPrintPost(lTeamClub, "", normalText, 250, vspace)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", normalText, 400, vspace, make_pair(1, true))); + li.addListPost(oPrintPost(lTeamTimeAfter, "", normalText, 460, vspace, make_pair(1, true))); + + li.addListPost(oPrintPost(lTeamRunner, "", normalText, 70, lh+vspace, make_pair(0, true))); + li.addListPost(oPrintPost(lTeamRunner, "", normalText, 250, lh+vspace, make_pair(1, true))); + li.setFilter(EFilterHasResult); + + li.addSubHead(oPrintPost(lClassName, "", boldText, 0, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, 400, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldText, 460, 10)); + + if (li.lp.showInterTimes) { + li.addSubListPost(oPrintPost(lPunchNamedTime, "", normalText, 10, 0, make_pair(1, true))); + li.subListPost.back().fixedWidth=160; + li.listSubType=li.EBaseTypePunches; + } + + if (li.lp.splitAnalysis) { + li.addListPost(oPrintPost(lRunnerMissedTime, "", normalText, 520, vspace, make_pair(1, true))); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldText, 520, 10)); + } + + li.listType=li.EBaseTypeTeam; + li.sortOrder=ClassResult; + li.lp.setLegNumberCoded(-1); + li.calcResults=true; + break; + + case EStdPatrolResultListLARGE: + pos.add("place", 25); + pos.add("team", int(0.7*max(li.getMaxCharWidth(this, par.selection, lTeamName, "", normalText), + li.getMaxCharWidth(this, par.selection, lPatrolNameNames, "", normalText)))); + + pos.add("status", 50); + pos.add("after", 50); + pos.add("missed", 50); + + li.addListPost(oPrintPost(lTeamPlace, "", fontLarge, pos.get("place", scale), vspace, make_pair(1, true))); + li.addListPost(oPrintPost(lTeamName, "", fontLarge, pos.get("team", scale), vspace)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", fontLarge, pos.get("status", scale), vspace, make_pair(1, true))); + li.addListPost(oPrintPost(lTeamTimeAfter, "", fontLarge, pos.get("after", scale), vspace, make_pair(1, true))); + + li.addListPost(oPrintPost(lPatrolNameNames, "", fontLarge, pos.get("team", scale), 25+vspace, make_pair(0, true))); + //li.addListPost(oPrintPost(lTeamRunner, "", fontLarge, pos.get("status", scale), 25+vspace, 1)); + + li.addSubHead(oPrintPost(lClassName, "", boldLarge, 0, 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldLarge, pos.get("status", scale), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Efter"), boldLarge, pos.get("after", scale), 10)); + + if (li.lp.showInterTimes) { + li.addSubListPost(oPrintPost(lPunchNamedTime, "", normalText, 10, 0, make_pair(1, true))); + li.subListPost.back().fixedWidth=200; + li.listSubType=li.EBaseTypePunches; + } + + if (li.lp.splitAnalysis) { + li.addListPost(oPrintPost(lRunnerMissedTime, "", fontLarge, pos.get("missed", scale), vspace, make_pair(0, true))); + li.addSubHead(oPrintPost(lString, lang.tl("Bomtid"), boldLarge, pos.get("missed", scale), 10)); + } + + li.setFilter(EFilterHasResult); + li.listType=li.EBaseTypeTeam; + li.sortOrder=ClassResult; + li.lp.setLegNumberCoded(-1); + li.calcResults=true; + break; + + case unused_EStdRaidResultListLARGE: + li.addListPost(oPrintPost(lTeamPlace, "", fontLarge, 0, vspace)); + li.addListPost(oPrintPost(lTeamName, "", fontLarge, 40, vspace)); + li.addListPost(oPrintPost(lTeamTimeStatus, "", fontLarge, 490, vspace)); + + li.addListPost(oPrintPost(lTeamRunner, "", fontLarge, 40, 25+vspace, make_pair(0, true))); + li.addListPost(oPrintPost(lTeamRunner, "", fontLarge, 300, 25+vspace, make_pair(1, true))); + + li.addSubListPost(oPrintPost(lPunchNamedTime, "", fontMedium, 0, 2, make_pair(1, true))); + li.subListPost.back().fixedWidth=200; + li.setFilter(EFilterHasResult); + + li.addSubHead(oPrintPost(lClassName, "", boldLarge, 0, 10)); + + li.listType=li.EBaseTypeTeam; + li.listSubType=li.EBaseTypePunches; + li.sortOrder=ClassResult; + li.calcResults=true; + break; + + case EStdResultListLARGE: + pos.add("place", 25); + pos.add("name", li.getMaxCharWidth(this, par.selection, lPatrolNameNames, "", normalText, 0, true)); + pos.add("club", li.getMaxCharWidth(this, par.selection, lPatrolClubNameNames, "", normalText, 0, true)); + pos.add("status", 50); + pos.add("missed", 50); + + li.addListPost(oPrintPost(lRunnerPlace, "", fontLarge, pos.get("place", scale), vspace)); + li.addListPost(oPrintPost(lPatrolNameNames, "", fontLarge, pos.get("name", scale), vspace)); + li.addListPost(oPrintPost(lPatrolClubNameNames, "", fontLarge, pos.get("club", scale), vspace)); + + li.addSubHead(oPrintPost(lClassName, "", boldLarge, pos.get("place", scale), 10)); + + if (li.lp.useControlIdResultTo<=0 && li.lp.useControlIdResultFrom<=0) { + li.addSubHead(oPrintPost(lClassResultFraction, "", boldLarge, pos.get("club", scale), 10)); + li.addListPost(oPrintPost(lRunnerTimeStatus, "", fontLarge, pos.get("status", scale), vspace)); + } + else { + li.needPunches = true; + li.addListPost(oPrintPost(lRunnerTempTimeStatus, "", normalText, pos.get("status", scale), vspace)); + } + if (li.lp.splitAnalysis) { + li.addSubHead(oPrintPost(lString, "Bomtid", boldLarge, pos.get("missed", scale), 10)); + li.addListPost(oPrintPost(lRunnerMissedTime, "", fontLarge, pos.get("missed", scale), vspace)); + } + + if (li.lp.showInterTimes) { + li.addSubListPost(oPrintPost(lPunchNamedTime, "", normalText, 0, 0, make_pair(1, true))); + li.subListPost.back().fixedWidth = 160; + li.listSubType = li.EBaseTypePunches; + } + else if (li.lp.showSplitTimes) { + li.addSubListPost(oPrintPost(lPunchTime, "", normalText, 0, 0, make_pair(1, true))); + li.subListPost.back().fixedWidth = 95; + li.listSubType = li.EBaseTypePunches; + } + + li.setFilter(EFilterHasResult); + li.lp.setLegNumberCoded(0); + li.listType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.calcResults=true; + + li.supportFrom = true; + li.supportTo = true; + break; + + case EStdUM_Master: + li.addListPost(oPrintPost(lRunnerPlace, "", fontMedium, 0, 0)); + li.addListPost(oPrintPost(lRunnerName, "", fontMedium, 40, 0)); + li.addListPost(oPrintPost(lRunnerClub, "", fontMedium, 250, 0)); + li.addListPost(oPrintPost(lClassName, "", fontMedium, 490, 0)); + li.addListPost(oPrintPost(lRunnerUMMasterPoint, "", fontMedium, 580, 0)); + + li.setFilter(EFilterHasResult); + + li.lp.setLegNumberCoded(0); + li.listType=li.EBaseTypeRunner; + li.sortOrder=ClassResult; + li.calcResults=true; + break; + + case ERogainingInd: + pos.add("place", 25); + pos.add("name", li.getMaxCharWidth(this, par.selection, lRunnerCompleteName, "", normalText, 0, true)); + pos.add("points", 50); + pos.add("status", 50); + li.addHead(oPrintPost(lCmpName, MakeDash(par.getCustomTitle(lang.tl("Rogainingresultat - %s"))), boldLarge, 0,0)); + li.addHead(oPrintPost(lCmpDate, "", normalText, 0, 25)); + generateNBestHead(par, li, 25+lh); + + li.addListPost(oPrintPost(lRunnerPlace, "", normalText, pos.get("place"), vspace)); + li.addListPost(oPrintPost(lRunnerCompleteName, "", normalText, pos.get("name"), vspace)); + li.addListPost(oPrintPost(lRunnerRogainingPoint, "%sp", normalText, pos.get("points"), vspace)); + li.addListPost(oPrintPost(lRunnerTimeStatus, "", normalText, pos.get("status"), vspace)); + + li.setFilter(EFilterHasResult); + + if (li.lp.splitAnalysis || li.lp.showInterTimes) { + li.addSubListPost(oPrintPost(lRogainingPunch, "", normalText, 10, 0, make_pair(1, true))); + li.subListPost.back().fixedWidth=130; + li.listSubType=li.EBaseTypePunches; + } + + li.addSubHead(oPrintPost(lClassName, "", boldText, pos.get("place"), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Poäng"), boldText, pos.get("points"), 10)); + li.addSubHead(oPrintPost(lString, lang.tl("Tid"), boldText, pos.get("status"), 10)); + + li.listType=li.EBaseTypeRunner; + li.sortOrder = ClassPoints; + li.lp.setLegNumberCoded(-1); + li.calcResults = true; + li.rogainingResults = true; + break; + + case EStdTeamAllLegLARGE: { + vector< pair > out; + fillLegNumbers(par.selection, false, false, out); + par.listCode = oe->getListContainer().getType("legresult"); + par.useLargeSize = true; + for (size_t k = 0; k < out.size(); k++) { + if (out[k].second >= 1000) + continue; + par.setLegNumberCoded(out[k].second); + if (k == 0) + generateListInfo(par, lineHeight, li); + else { + li.next.push_back(oListInfo()); + generateListInfo(par, lineHeight, li.next.back()); + } + } + } + break; + + case EFixedPreReport: + case EFixedReport: + case EFixedInForest: + case EFixedEconomy: + case EFixedInvoices: + case EFixedMinuteStartlist: + case EFixedTimeLine: + case EFixedLiveResult: + li.fixedType = true; + break; + + default: + if (!getListContainer().interpret(this, gdibase, par, lineHeight, li)) + throw std::exception("Not implemented"); + } +} + +string oPrintPost::encodeFont(const string &face, int factor) { + string out(face); + if (factor > 0 && factor != 100) { + out += ";" + itos(factor/100) + "." + itos(factor%100); + } + return out; +} +void oListInfo::setupLinks(const list &lst) const { + for (list::const_iterator it = lst.begin(); it != lst.end(); ++it) { + list::const_iterator itNext = it; + ++itNext; + if (itNext != lst.end() && it->doMergeNext) + it->mergeWithTmp = &*itNext; + else + it->mergeWithTmp = 0; + } +} + +void oListInfo::setupLinks() const { + setupLinks(Head); + setupLinks(subHead); + setupLinks(listPost); + setupLinks(subListPost); +} + +oListInfo::ResultType oListInfo::getResultType() const { + return resType; +} + +bool oListParam::matchLegNumber(const pClass cls, int leg) const { + if (cls == 0 || legNumber == -1 || leg < 0) + return true; + int number, order; + cls->splitLegNumberParallel(leg, number, order); + if (number == legNumber) + return true; + int sub = legNumber % 10000; + int maj = legNumber / 10000; + return maj == number + 1 && sub == order; +} + +int oListParam::getLegNumber(const pClass cls) const { + if (legNumber < 0) + return legNumber; + + int sub = legNumber % 10000; + int maj = legNumber / 10000; + + if (cls) { + if (legNumber < 10000) + return cls->getLegNumberLinear(legNumber, 0); + else + return cls->getLegNumberLinear(maj-1, sub); + } + return sub; +} + +pair oListParam::getLegInfo(const pClass cls) const { + if (legNumber == -1) + return make_pair(-1, true); + else if (legNumber < 10000) + return make_pair(legNumber, false); + + int sub = legNumber % 10000; + int maj = legNumber / 10000; + + int lin = cls ? cls->getLegNumberLinear(maj-1, sub) : sub+maj; + + return make_pair(lin, true); +} + +string oListParam::getLegName() const { + if (legNumber == -1) + return ""; + + if (legNumber < 1000) + return itos(legNumber + 1); + + int sub = legNumber % 10000; + int maj = legNumber / 10000; + + char bf[64]; + char symb = 'a' + sub; + sprintf_s(bf, "%d%c", maj, symb); + return bf; +} diff --git a/code/oListInfo.h b/code/oListInfo.h new file mode 100644 index 0000000..3c31697 --- /dev/null +++ b/code/oListInfo.h @@ -0,0 +1,500 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include +#include "oBase.h" +#include "gdifonts.h" + +class oClass; + +typedef oEvent *pEvent; +typedef oClass *pClass; + +enum EPostType +{ + lAlignNext, + lNone, + lString, + lResultDescription, + lTimingFromName, + lTimingToName, + lCmpName, + lCmpDate, + lCurrentTime, + lClubName, + lClassName, + lClassStartName, + lClassStartTime, + lClassStartTimeRange, + lClassLength, + lClassResultFraction, + lCourseLength, + lCourseName, + lCourseClimb, + lCourseShortening, + lCourseUsage, + lCourseUsageNoVacant, + lCourseClasses, + lRunnerName, + lRunnerGivenName, + lRunnerFamilyName, + lRunnerCompleteName, + lPatrolNameNames, // Single runner's name or both names in a patrol + lPatrolClubNameNames, // Single runner's club or combination of patrol clubs + lRunnerFinish, + lRunnerTime, + lRunnerTimeStatus, + lRunnerTotalTime, + lRunnerTimePerKM, + lRunnerTotalTimeStatus, + lRunnerTotalPlace, + lRunnerPlaceDiff, + lRunnerClassCoursePlace, + lRunnerTotalTimeAfter, + lRunnerClassCourseTimeAfter, + lRunnerTimeAfterDiff, + lRunnerTempTimeStatus, + lRunnerTempTimeAfter, + lRunnerGeneralTimeStatus, + lRunnerGeneralPlace, + lRunnerGeneralTimeAfter, + lRunnerTimeAfter, + lRunnerMissedTime, + lRunnerPlace, + lRunnerStart, + lRunnerStartCond, + lRunnerStartZero, + lRunnerClub, + lRunnerCard, + lRunnerBib, + lRunnerStartNo, + lRunnerRank, + lRunnerCourse, + lRunnerRogainingPoint, + lRunnerRogainingPointTotal, + lRunnerRogainingPointReduction, + lRunnerRogainingPointOvertime, + lRunnerRogainingPointGross, + lRunnerTimeAdjustment, + lRunnerPointAdjustment, + + lRunnerUMMasterPoint, + lRunnerTimePlaceFixed, + lRunnerLegNumberAlpha, + lRunnerLegNumber, + + lRunnerBirthYear, + lRunnerAge, + lRunnerSex, + lRunnerNationality, + lRunnerPhone, + lRunnerFee, + + lTeamName, + lTeamStart, + lTeamStartCond, + lTeamStartZero, + lTeamTimeStatus, + lTeamTimeAfter, + lTeamPlace, + lTeamLegTimeStatus, + lTeamLegTimeAfter, + lTeamRogainingPoint, + lTeamRogainingPointTotal, + lTeamRogainingPointReduction, + lTeamRogainingPointOvertime, + lTeamTimeAdjustment, + lTeamPointAdjustment, + + lTeamTime, + lTeamStatus, + lTeamClub, + lTeamRunner, + lTeamRunnerCard, + lTeamBib, + lTeamStartNo, + lTeamFee, + + lTeamTotalTime, + lTeamTotalTimeStatus, + lTeamTotalPlace, + lTeamTotalTimeAfter, + lTeamTotalTimeDiff, + lTeamPlaceDiff, + + lPunchNamedTime, + lPunchTime, + lPunchControlNumber, + lPunchControlCode, + lPunchLostTime, + lPunchControlPlace, + lPunchControlPlaceAcc, + + lResultModuleTime, + lResultModuleNumber, + lResultModuleTimeTeam, + lResultModuleNumberTeam, + + lCountry, + lNationality, + + lControlName, + lControlCourses, + lControlClasses, + lControlVisitors, + lControlPunches, + lControlMedianLostTime, + lControlMaxLostTime, + lControlMistakeQuotient, + lControlRunnersLeft, + lControlCodes, + + lRogainingPunch, + lTotalCounter, + lSubCounter, + lSubSubCounter, + lLastItem +}; + +enum EStdListType +{ + EStdNone=-1, + EStdStartList=1, + EStdResultList, + EGeneralResultList, + ERogainingInd, + EStdTeamResultListAll, + unused_EStdTeamResultListLeg,//EStdTeamResultListLeg, + EStdTeamResultList, + EStdTeamStartList, + EStdTeamStartListLeg, + EStdIndMultiStartListLeg, + EStdIndMultiResultListLeg, + EStdIndMultiResultListAll, + EStdPatrolStartList, + EStdPatrolResultList, + EStdRentedCard, + EStdResultListLARGE, + unused_EStdTeamResultListLegLARGE,//EStdTeamResultListLegLARGE, + EStdPatrolResultListLARGE, + EStdIndMultiResultListLegLARGE, + unused_EStdRaidResultListLARGE,//EStdRaidResultListLARGE, //Obsolete + ETeamCourseList, + EIndCourseList, + EStdClubStartList, + EStdClubResultList, + + EIndPriceList, + EStdUM_Master, + + EFixedPreReport, + EFixedReport, + EFixedInForest, + EFixedInvoices, + EFixedEconomy, + unused_EFixedResultFinishPerClass, + unused_EFixedResultFinish, + EFixedMinuteStartlist, + EFixedTimeLine, + EFixedLiveResult, + + EStdTeamAllLegLARGE, + + EFirstLoadedList = 1000 +}; + +enum EFilterList +{ + EFilterHasResult, + EFilterHasPrelResult, + EFilterRentCard, + EFilterHasCard, + EFilterHasNoCard, + EFilterExcludeDNS, + EFilterVacant, + EFilterOnlyVacant, + _EFilterMax +}; + +enum ESubFilterList +{ + ESubFilterHasResult, + ESubFilterHasPrelResult, + ESubFilterExcludeDNS, + ESubFilterVacant, + ESubFilterSameParallel, + ESubFilterSameParallelNotFirst, + _ESubFilterMax +}; + +enum gdiFonts; + +struct oPrintPost { + oPrintPost(); + oPrintPost(EPostType type_, const string &format_, + int style_, int dx_, int dy_, + pair legIndex_=make_pair(0, true)); + + static string encodeFont(const string &face, int factor); + + EPostType type; + string text; + string fontFace; + int resultModuleIndex; + int format; + GDICOLOR color; + int dx; + int dy; + int legIndex; + bool linearLegIndex; + gdiFonts getFont() const {return gdiFonts(format & 0xFF);} + oPrintPost &setFontFace(const string &font, int factor) { + fontFace = encodeFont(font, factor); + return *this; + } + int fixedWidth; + bool doMergeNext; + mutable const oPrintPost *mergeWithTmp; // Merge text with this output +}; + +class gdioutput; +enum gdiFonts; +typedef int (*GUICALLBACK)(gdioutput *gdi, int type, void *data); +class xmlparser; +class xmlobject; +class MetaListContainer; + +struct oListParam { + oListParam(); + EStdListType listCode; + GUICALLBACK cb; + set selection; + + int useControlIdResultTo; + int useControlIdResultFrom; + int filterMaxPer; + bool pageBreak; + bool showInterTimes; + bool showSplitTimes; + bool splitAnalysis; + bool showInterTitle; + string title; + string name; + int inputNumber; + int nextList; // 1-based index of next list (in the container, MetaListParam::listParam) for linked lists + int previousList; // 1-based index of previous list (in the container, MetaListParam::listParam) for linked lists. Not serialized + + mutable int relayLegIndex; // Current index of leg (or -1 for entire team) + mutable string defaultName; // Initialized when generating list + // Generate a large-size list (supported as input when supportLarge is true) + bool useLargeSize; + bool saved; + + void updateDefaultName(const string &name) const {defaultName = name;} + void setCustomTitle(const string &t) {title = t;} + void getCustomTitle(char *t) const; // 256 size buffer required. Get title if set + const string &getCustomTitle(const string &t) const; + const string &getDefaultName() const {return defaultName;} + void setName(const string &n) {name = n;} + const string &getName() const {return name;} + + int getInputNumber() const {return inputNumber;} + void setInputNumber(int n) {inputNumber = n;} + + void serialize(xmlparser &xml, + const MetaListContainer &container, + const map &idToIndex) const; + void deserialize(const xmlobject &xml, const MetaListContainer &container); + + void setLegNumberCoded(int code) { + if (code == 1000) + legNumber = -1; + else + legNumber = code; + } + + bool matchLegNumber(const pClass cls, int leg) const; + int getLegNumber(const pClass cls) const; + pair getLegInfo(const pClass cls) const; + + string getLegName() const; + + const int getLegNumberCoded() const { + return legNumber >= 0 ? legNumber : 1000; + } + + + +private: + int legNumber; +}; + +class oListInfo { +public: + enum EBaseType {EBaseTypeRunner, + EBaseTypeTeam, + EBaseTypeClub, + EBaseTypePunches, + EBaseTypeNone, + EBaseTypeRunnerGlobal, // Used only in metalist (meaning global, not classwise) + EBaseTypeRunnerLeg, // Used only in metalist, meaning legwise + EBaseTypeTeamGlobal, // Used only in metalist (meaning global, not classwise) + EBaseTypeCourse, + EBaseTypeControl, + EBasedTypeLast_}; + + bool isTeamList() const {return listType == EBaseTypeTeam;} + + enum ResultType { + Global, + Classwise, + Legwise, + }; + + static bool addRunners(EBaseType t) {return t == EBaseTypeRunner || t == EBaseTypeClub;} + static bool addTeams(EBaseType t) {return t == EBaseTypeTeam || t == EBaseTypeClub;} + static bool addPatrols(EBaseType t) {return t == EBaseTypeTeam || t == EBaseTypeClub;} + + const string &getName() const {return Name;} +protected: + string Name; + EBaseType listType; + EBaseType listSubType; + SortOrder sortOrder; + + bool calcResults; + bool calcCourseClassResults; + bool calcTotalResults; + bool rogainingResults; + + oListParam lp; + + list Head; + list subHead; + list listPost; + vector listPostFilter; + vector listPostSubFilter; + list subListPost; + bool fixedType; + bool needPunches; + string resultModule; + set additionalModules; + + void setupLinks(const list &lst) const; + void setupLinks() const; + + list next; +public: + ResultType getResultType() const; + + bool supportClasses; + bool supportLegs; + bool supportParameter; + // True if large (and non-large) is supported + bool supportLarge; + // True if a large-size list only + bool largeSize; + + bool supportSplitAnalysis; + bool supportInterResults; + bool supportPageBreak; + bool supportClassLimit; + bool supportCustomTitle; + + // True if supports timing from control + bool supportTo; + // True if supports timing to control + bool supportFrom; + // Result type + ResultType resType; + + + bool needPunchCheck() const {return needPunches;} + void setCallback(GUICALLBACK cb); + int getLegNumberCoded() const {return lp.getLegNumberCoded();} + + + EStdListType getListCode() const {return lp.listCode;} + oPrintPost &addHead(const oPrintPost &pp) { + Head.push_back(pp); + return Head.back(); + } + oPrintPost &addSubHead(const oPrintPost &pp) { + subHead.push_back(pp); + return subHead.back(); + } + oPrintPost &addListPost(const oPrintPost &pp) { + listPost.push_back(pp); + return listPost.back(); + } + oPrintPost &addSubListPost(const oPrintPost &pp) { + subListPost.push_back(pp); + return subListPost.back(); + } + inline bool filter(EFilterList i) const {return listPostFilter[i]!=0;} + inline bool subFilter(ESubFilterList i) const {return listPostSubFilter[i]!=0;} + + void setFilter(EFilterList i) {listPostFilter[i]=1;} + void setSubFilter(ESubFilterList i) {listPostSubFilter[i]=1;} + + void setResultModule(const string &rm) {resultModule = rm;} + void additionalResultModule(const string &rm) {additionalModules.insert(rm);} + const string &getResultModule() const {return resultModule;} + oListInfo(void); + ~oListInfo(void); + + friend class oEvent; + friend class MetaList; + friend class MetaListContainer; + + int getMaxCharWidth(const oEvent *oe, + const set &clsSel, + const vector< pair > &typeFormats, + gdiFonts font, + const char *fontFace = 0, + bool large = false, + int minSize = 0); + + + int getMaxCharWidth(const oEvent *oe, + const set &clsSel, + EPostType type, + string formats, + gdiFonts font, + const char *fontFace = 0, + bool large = false, + int minSize = 0) { + vector< pair > typeFormats(1, make_pair(type, formats)); + return getMaxCharWidth(oe, clsSel, typeFormats, font, fontFace, largeSize, minSize); + } + + + const oListParam &getParam() const {return lp;} + oListParam &getParam() {return lp;} + + // Returns true if the list needs to be regenerated due to competition changes + bool needRegenerate(const oEvent &oe) const; + +}; diff --git a/code/oPunch.cpp b/code/oPunch.cpp new file mode 100644 index 0000000..22fc6b8 --- /dev/null +++ b/code/oPunch.cpp @@ -0,0 +1,184 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oPunch.cpp: implementation of the oPunch class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "oPunch.h" +#include "oEvent.h" +#include "meos_util.h" +#include "localizer.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +oPunch::oPunch(oEvent *poe): oBase(poe) +{ + Type=0; + Time=0; + tTimeAdjust=0; + isUsed=false; + hasBeenPlayed=false; + tMatchControlId = -1; + tRogainingIndex = 0; + tIndex = -1; +} + +oPunch::~oPunch() +{ +} + +string oPunch::getInfo() const +{ + return "Stämpling "+codeString(); +} + +string oPunch::codeString() const +{ + char bf[32]; + sprintf_s(bf, 32, "%d-%d;", Type, Time); + return bf; +} + +void oPunch::decodeString(const string &s) +{ + Type=atoi(s.c_str()); + Time=atoi(s.substr(s.find_first_of('-')+1).c_str()); +} + +string oPunch::getString() const +{ + char bf[32]; + + const char *ct; + string time(getTime()); + ct=time.c_str(); + + string typeS = getType(); + const char *tp = typeS.c_str(); + + if (Type==oPunch::PunchStart) + sprintf_s(bf, "%s\t%s", tp, ct); + else if (Type==oPunch::PunchFinish) + sprintf_s(bf, "%s\t%s", tp, ct); + else if (Type==oPunch::PunchCheck) + sprintf_s(bf, "%s\t%s", tp, ct); + else + { + if (isUsed) + sprintf_s(bf, "%d\t%s", Type, ct); + else + sprintf_s(bf, " %d*\t%s", Type, ct); + } + + return bf; +} + +string oPunch::getSimpleString() const +{ + string time(getTime()); + + if (Type==oPunch::PunchStart) + return lang.tl("starten (X)#" + time); + else if (Type==oPunch::PunchFinish) + return lang.tl("målet (X)#" + time); + else if (Type==oPunch::PunchCheck) + return lang.tl("check (X)#" + time); + else + return lang.tl("kontroll X (Y)#" + itos(Type) + "#" + time); +} + +string oPunch::getTime() const +{ + if (Time>=0) + return oe->getAbsTime(Time+tTimeAdjust); + else return "-"; +} + +int oPunch::getAdjustedTime() const +{ + if (Time>=0) + return Time+tTimeAdjust; + else return -1; +} +void oPunch::setTime(const string &t) +{ + int tt = oe->getRelativeTime(t)-tTimeAdjust; + if (tt < 0) + tt = 0; + setTimeInt(tt, false); +} + +void oPunch::setTimeInt(int tt, bool databaseUpdate) { + if (tt != Time) { + Time = tt; + if (!databaseUpdate) + updateChanged(); + } +} + +oDataContainer &oPunch::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + throw std::exception("Unsupported"); +} + +string oPunch::getRunningTime(int startTime) const +{ + int t = getAdjustedTime(); + if (startTime>0 && t>0 && t>startTime) + return formatTime(t-startTime); + else + return "-"; +} + +void oPunch::remove() +{ + // Not implemented +} + +bool oPunch::canRemove() const +{ + return true; +} + +const string &oPunch::getType() const { + return getType(Type); +} + +const string &oPunch::getType(int t) { + if (t==oPunch::PunchStart) + return lang.tl("Start"); + else if (t==oPunch::PunchFinish) + return lang.tl("Mål"); + else if (t==oPunch::PunchCheck) + return lang.tl("Check"); + else if (t>10 && t<10000) { + return itos(t); + } + return _EmptyString; +} + +void oPunch::changedObject() { + // Does nothing +} diff --git a/code/oPunch.h b/code/oPunch.h new file mode 100644 index 0000000..6c2c065 --- /dev/null +++ b/code/oPunch.h @@ -0,0 +1,109 @@ +// oPunch.h: interface for the oPunch class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_OPUNCH_H__67B23AF5_5783_4A6A_BB2E_E522B9283A42__INCLUDED_) +#define AFX_OPUNCH_H__67B23AF5_5783_4A6A_BB2E_E522B9283A42__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +#include "oBase.h" + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class oEvent; + +class oPunch : public oBase +{ +protected: + + int Type; + int Time; + bool isUsed; //Is used in the course... + + // Index into course (-1 if unused) + int tRogainingIndex; + // Number of rogaining points given + int tRogainingPoints; + + //Adjustment of this punch, loaded from control + int tTimeAdjust; + + volatile int tCardIndex; // Index into card + int tIndex; // Control match index in course + int tMatchControlId; + bool hasBeenPlayed; + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + int getDISize() const {return -1;} + + void changedObject(); +public: + + virtual int getControlId() {return tMatchControlId;} + + bool isUsedInCourse() const {return isUsed;} + void remove(); + bool canRemove() const; + + string getInfo() const; + + bool isStart() const {return Type==PunchStart;} + bool isStart(int startType) const {return Type==PunchStart || Type == startType;} + bool isFinish() const {return Type==PunchFinish;} + bool isFinish(int finishType) const {return Type==PunchFinish || Type == finishType;} + bool isCheck() const {return Type==PunchCheck;} + int getControlNumber() const {return Type>=30 ? Type : 0;} + const string &getType() const; + static const string &getType(int t); + int getTypeCode() const {return Type;} + string getString() const ; + string getSimpleString() const; + + string getTime() const; + int getAdjustedTime() const; + void setTime(const string &t); + virtual void setTimeInt(int newTime, bool databaseUpdate); + + void setTimeAdjust(int t) {tTimeAdjust=t;} + void adjustTimeAdjust(int t) {tTimeAdjust+=t;} + + string getRunningTime(int startTime) const; + + enum SpecialPunch {PunchStart=1, PunchFinish=2, PunchCheck=3}; + void decodeString(const string &s); + string codeString() const; + oPunch(oEvent *poe); + virtual ~oPunch(); + + friend class oCard; + friend class oRunner; + friend class oTeam; + friend class oEvent; +}; + +typedef oPunch * pPunch; + +#endif // !defined(AFX_OPUNCH_H__67B23AF5_5783_4A6A_BB2E_E522B9283A42__INCLUDED_) diff --git a/code/oReport.cpp b/code/oReport.cpp new file mode 100644 index 0000000..455763f --- /dev/null +++ b/code/oReport.cpp @@ -0,0 +1,685 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" +#include "gdifonts.h" + +#include "oDataContainer.h" + +#include "random.h" +#include "SportIdent.h" + +#include "oFreeImport.h" + +#include "meos.h" +#include "meos_util.h" +#include "RunnerDB.h" +#include "MeOSFeatures.h" + +#include +#include +#include + +#include "Localizer.h" + + +void oEvent::generateCompetitionReport(gdioutput &gdi) +{ + gdi.fillDown(); + gdi.addString("", boldLarge, "Tävlingsstatistik"); + + + int lh = gdi.getLineHeight(); + + oClassList::iterator it; + + reinitializeClasses(); + Classes.sort(); + + gdi.dropLine(); + // int xp = gdi.getCX(); +// int yp = gdi.getCY(); + int entries=0; + int started=0; + int fee=0; +// int dx[]={0, 150, 200, 250, 350, 450}; + + int entries_sum=0; + int started_sum=0; + int fee_sum=0; + + int entries_sum_y=0; + int started_sum_y=0; + int fee_sum_y=0; + + int cfee; + gdi.addString("", boldText, "Elitklasser"); + vector types; + types.push_back(ctElite); + cfee = getDCI().getInt("EliteFee"); + generateStatisticsPart(gdi, types, set(), cfee, false, 90, entries, started, fee); + entries_sum += entries; + started_sum += started; + fee_sum += fee; + + gdi.addString("", boldText, "Vuxenklasser"); + types.clear(); + types.push_back(ctNormal); + types.push_back(ctExercise); + cfee = getDCI().getInt("EntryFee"); + generateStatisticsPart(gdi, types, set(), cfee, false, 90, entries, started, fee); + entries_sum += entries; + started_sum += started; + fee_sum += fee; + + gdi.addString("", boldText, "Ungdomsklasser"); + types.clear(); + types.push_back(ctYouth); + cfee = getDCI().getInt("YouthFee"); + generateStatisticsPart(gdi, types, set(), cfee, true, 50, entries, started, fee); + entries_sum_y += entries; + started_sum_y += started; + fee_sum_y += fee; + + types.clear(); + types.push_back(ctOpen); + + gdi.addString("", boldText, "Öppna klasser, vuxna"); + set adultFee; + set youthFee; + + cfee = getDCI().getInt("EntryFee"); + if (cfee > 0) + adultFee.insert(cfee); + + for(it=Classes.begin(); it!=Classes.end(); ++it) { + if (!it->isRemoved() && it->interpretClassType() == ctOpen) { + int af = it->getDCI().getInt("ClassFee"); + if (af > 0) + adultFee.insert(af); + int yf = it->getDCI().getInt("ClassFeeRed"); + if (yf > 0) + youthFee.insert(yf); + } + } + + generateStatisticsPart(gdi, types, adultFee, cfee, false, 90, entries, started, fee); + entries_sum += entries; + started_sum += started; + fee_sum += fee; + + gdi.addString("", boldText, "Öppna klasser, ungdom"); + + cfee = getDCI().getInt("YouthFee"); + if (cfee > 0) + youthFee.insert(cfee); + + generateStatisticsPart(gdi, types, youthFee, cfee, true, 50, entries, started, fee); + entries_sum_y += entries; + started_sum_y += started; + fee_sum_y += fee; + + gdi.addString("", boldText, "Sammanställning"); + gdi.dropLine(); + int xp = gdi.getCX(); + int yp = gdi.getCY(); + + gdi.addString("", yp, xp+200, textRight|fontMedium, "Vuxna"); + gdi.addString("", yp, xp+300, textRight|fontMedium, "Ungdom"); + gdi.addString("", yp, xp+400, textRight|fontMedium, "Totalt"); + + yp+=lh; + gdi.addString("", yp, xp+0, fontMedium, "Anmälda"); + gdi.addStringUT(yp, xp+200, textRight|fontMedium, itos(entries_sum)); + gdi.addStringUT(yp, xp+300, textRight|fontMedium, itos(entries_sum_y)); + gdi.addStringUT(yp, xp+400, textRight|boldText, itos(entries_sum+entries_sum_y)); + + yp+=lh; + gdi.addString("", yp, xp+0, fontMedium, "Startande"); + gdi.addStringUT(yp, xp+200, textRight|fontMedium, itos(started_sum)); + gdi.addStringUT(yp, xp+300, textRight|fontMedium, itos(started_sum_y)); + gdi.addStringUT( yp, xp+400, textRight|boldText, itos(started_sum+started_sum_y)); + + yp+=lh; + gdi.addString("", yp, xp+0, fontMedium, "Grundavgift"); + gdi.addStringUT(yp, xp+200, textRight|fontMedium, itos(fee_sum)); + gdi.addStringUT(yp, xp+300, textRight|fontMedium, itos(fee_sum_y)); + gdi.addStringUT(yp, xp+400, textRight|boldText, itos(fee_sum+fee_sum_y)); + + yp+=lh; + gdi.addString("", yp, xp+0, fontMedium, "SOFT-avgift"); + gdi.addStringUT(yp, xp+200, textRight|fontMedium, itos(entries_sum*15)); + gdi.addStringUT(yp, xp+300, textRight|fontMedium, itos(entries_sum_y*5)); + gdi.addStringUT(yp, xp+400, textRight|boldText, itos(entries_sum*15+entries_sum_y*5)); + + yp+=lh*2; + gdi.addString("", yp, xp+0,fontMedium, "Underlag för tävlingsavgift:"); + int baseFee = (fee_sum+fee_sum_y) - (entries_sum*15+5*entries_sum_y); + gdi.addStringUT(yp, xp+200,fontMedium, itos(baseFee)); + + yp+=lh; + gdi.addString("", yp, xp+0,fontMedium, "Total tävlingsavgift:"); + int cmpFee = int((baseFee * .34 * (baseFee - 5800)) / (200000)); + gdi.addStringUT(yp, xp+200, fontMedium, itos(cmpFee)); + + yp+=lh; + gdi.addString("", yp, xp, fontMedium, "Avrundad tävlingsavgift:"); + gdi.addStringUT(yp, xp+200, boldText, itos(((cmpFee+50))/100)+"00"); + + gdi.dropLine(); + gdi.addString("", boldText, "Geografisk fördelning"); + gdi.addString("", fontSmall, "Anmälda per distrikt"); + gdi.dropLine(0.2); + yp = gdi.getCY(); + vector runners; + vector districts; + getRunnersPerDistrict(runners); + getDistricts(districts); + int nd = min(runners.size(), districts.size()); + + int ybase = yp; + for (int k=1;k<=nd;k++) { + gdi.addStringUT(yp, xp, fontMedium, itos(k) + " " + districts[k%nd]); + gdi.addStringUT(yp, xp+200, textRight|fontMedium, itos(runners[k%nd])); + yp+=lh; + if (k%8==0){ + yp = ybase; + xp += 250; + } + } +} + +void oEvent::generateStatisticsPart(gdioutput &gdi, const vector &type, + const set &feeLock, int actualFee, bool useReducedFee, + int baseFee, int &entries_sum, int &started_sum, int &fee_sum) const +{ + entries_sum=0; + started_sum=0; + fee_sum=0; + int xp = gdi.getCX(); + int yp = gdi.getCY(); + int entries; + int started; + int dx[]={0, 150, 210, 270, 350, 450}; + int lh = gdi.getLineHeight(); + oClassList::const_iterator it; + + gdi.addString("", yp, xp+dx[0], fontSmall, "Klass"); + gdi.addString("", yp, xp+dx[1], textRight|fontSmall, "Anm. avg."); + gdi.addString("", yp, xp+dx[2], textRight|fontSmall, "Grund avg."); + gdi.addString("", yp, xp+dx[3], textRight|fontSmall, "Anmälda"); + gdi.addString("", yp, xp+dx[4], textRight|fontSmall, "Avgift"); + gdi.addString("", yp, xp+dx[5], textRight|fontSmall, "Startande"); + yp+=lh; + for(it=Classes.begin(); it!=Classes.end(); ++it) { + if (it->isRemoved()) + continue; + //int lowAge = it->getDCI().getInt("LowAge"); +/* int highAge = it->getDCI().getInt("HighAge"); + + if (ageSpan.second > 0 && (highAge == 0 || highAge > ageSpan.second)) + continue; + + if (ageSpan.first > 0 && (highAge != 0 && highAge < ageSpan.first)) + continue; +*/ + if (count(type.begin(), type.end(), it->interpretClassType())==1) { + it->getStatistics(feeLock, entries, started); + gdi.addStringUT(yp, xp+dx[0], fontMedium, it->getName()); + + int afee = it->getDCI().getInt("ClassFee"); + int redfee = it->getDCI().getInt("ClassFeeRed"); + + int f = actualFee; + + if (afee > 0) + f = afee; + + if (useReducedFee && redfee > 0) + f = redfee; + + gdi.addStringUT(yp, xp+dx[1], textRight|fontMedium, itos(f)); + gdi.addStringUT(yp, xp+dx[2], textRight|fontMedium, itos(baseFee)); + gdi.addStringUT(yp, xp+dx[3], textRight|fontMedium, itos(entries)); + gdi.addStringUT(yp, xp+dx[4], textRight|fontMedium, itos(baseFee*entries)); + gdi.addStringUT(yp, xp+dx[5], textRight|fontMedium, itos(started)); + entries_sum += entries; + started_sum += started; + fee_sum += entries*baseFee; + yp+=lh; + } + } + yp+=lh/2; + gdi.addStringUT(yp, xp+dx[3], textRight|boldText, itos(entries_sum)); + gdi.addStringUT(yp, xp+dx[4], textRight|boldText, itos(fee_sum)); + gdi.addStringUT(yp, xp+dx[5], textRight|boldText, itos(started_sum)); + gdi.dropLine(); +} + +void oEvent::getRunnersPerDistrict(vector &runners) const +{ + runners.clear(); + runners.resize(24); + + oRunnerList::const_iterator it; + + for (it = Runners.begin(); it != Runners.end(); ++it) { + if (!it->skip()) { + int code = 0; + if (it->Club) + code = it->Club->getDCI().getInt("District"); + + if (code>0 && code<24) + ++runners[code]; + else + ++runners[0]; + } + } +} + +void oEvent::getDistricts(vector &districts) +{ + districts.resize(24); + int i=0; + districts[i++]="Övriga"; + districts[i++]="Blekinge"; + districts[i++]="Bohuslän-Dal"; + districts[i++]="Dalarna"; + districts[i++]="Gotland"; + districts[i++]="Gästrikland"; + districts[i++]="Göteborg"; + districts[i++]="Halland"; + districts[i++]="Hälsingland"; + districts[i++]="Jämtland-Härjedalan"; + districts[i++]="Medelpad"; + districts[i++]="Norrbotten"; + districts[i++]="Örebro län"; + districts[i++]="Skåne"; + districts[i++]="Småland"; + districts[i++]="Stockholm"; + districts[i++]="Södermanland"; + districts[i++]="Uppland"; + districts[i++]="Värmland"; + districts[i++]="Västerbotten"; + districts[i++]="Västergötland"; + districts[i++]="Västmanland"; + districts[i++]="Ångermanland"; + districts[i++]="Östergötland"; +} + + +void oEvent::generatePreReport(gdioutput &gdi) { + CurrentSortOrder=SortByName; + Runners.sort(); + + int lVacId = getVacantClub(); + + oRunnerList::iterator r_it; + oTeamList::iterator t_it; + + //BIB, START, NAME, CLUB, RANK, SI + int dx[6]={0, 0, 70, 300, 470, 470}; + + bool withrank = hasRank(); + bool withbib = hasBib(true, true); + int i; + + if (withrank) dx[5]+=50; + if (withbib) for(i=1;i<6;i++) dx[i]+=40; + + int y=gdi.getCY(); + int x=gdi.getCX(); + int lh=gdi.getLineHeight(); + + gdi.addStringUT(2, lang.tl("Rapport inför: ") + getName()); + + gdi.addStringUT(1, getDate()); + gdi.dropLine(); + char bf[256]; + + list no_card; + list no_start; + list no_class; + list no_course; + list no_club; + + for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){ + if (r_it->isRemoved()) + continue; + + bool needStartTime = true; + bool needCourse = true; + + pClass pc = r_it->Class; + if (pc) { + LegTypes lt = pc->getLegType(r_it->tLeg); + if (lt == LTIgnore) { + needStartTime = false; + needCourse = false; + } + if (pc->hasDirectResult()) + needCourse = false; + + StartTypes st = pc->getStartType(r_it->tLeg); + + if (st != STTime && st != STDrawn) + needStartTime = false; + + if (pc->hasFreeStart()) + needStartTime = false; + } + if ( r_it->getClubId() != lVacId) { + if (needCourse && r_it->getCardNo()==0) + no_card.push_back(&*r_it); + if (needStartTime && r_it->getStartTime()==0) + no_start.push_back(&*r_it); + if (r_it->getClubId()==0) + no_club.push_back(&*r_it); + } + + if (r_it->getClassId()==0) + no_class.push_back(&*r_it); + else if (needCourse && r_it->getCourse(false)==0) + no_course.push_back(&*r_it); + } + + deque si_duplicate; + + if (Runners.size()>1){ + Runners.sort(oRunner::CompareSINumber); + map > initDup; + + r_it=Runners.begin(); + while (++r_it != Runners.end()){ + oRunnerList::iterator r_it2=r_it; + r_it2--; + int cno = r_it->getCardNo(); + if (cno && r_it2->getCardNo() == cno){ + vector &sid = initDup[cno]; + if (sid.empty() || sid.back()->getId()!=r_it2->getId()) + sid.push_back(&*r_it2); + + sid.push_back(&*r_it); + } + } + + for(map >::const_iterator it = initDup.begin(); it != initDup.end(); ++it) { + const vector &eq = it->second; + vector added(eq.size()); + for (size_t k = 0; k < eq.size(); k++) { + if (added[k]) + continue; + + for (size_t j = 0; j < eq.size(); j++) { + if (j == k) + continue; + if (!eq[k]->canShareCard(eq[j], eq[k]->getCardNo())) { + if (!added[k]) { + si_duplicate.push_back(eq[k]); + added[k] = 1; + } + if (!added[j]) { + si_duplicate.push_back(eq[j]); + added[j] = 1; + } + } + } + } + } + + } + + const string Ellipsis="[ ... ]"; + + sprintf_s(bf, lang.tl("Löpare utan klass: %d.").c_str(), no_class.size()); + gdi.addStringUT(1, bf); + i=0; + + while(!no_class.empty() && ++i<20){ + pRunner r=no_class.front(); + no_class.pop_front(); + string name = r->getName(); + if (!r->getClub().empty()) + name += " ("+r->getClub()+")"; + gdi.addStringUT(0, name); + } + if (!no_class.empty()) gdi.addStringUT(1, Ellipsis); + + gdi.dropLine(); + sprintf_s(bf, lang.tl("Löpare utan bana: %d.").c_str(), no_course.size()); + gdi.addStringUT(1, bf); + i=0; + + while(!no_course.empty() && ++i<20){ + pRunner r=no_course.front(); + no_course.pop_front(); + string name = r->getClass() + ": " + r->getName(); + if (!r->getClub().empty()) + name += " ("+r->getClub()+")"; + gdi.addStringUT(0, name); + } + if (!no_course.empty()) gdi.addStringUT(1, Ellipsis); + + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { + gdi.dropLine(); + sprintf_s(bf, lang.tl("Löpare utan klubb: %d.").c_str(), no_club.size()); + gdi.addStringUT(1, bf); + i=0; + + while(!no_club.empty() && ++i<20){ + pRunner r=no_club.front(); + no_club.pop_front(); + sprintf_s(bf, "%s: %s", r->getClass().c_str(), r->getName().c_str()); + gdi.addStringUT(0, bf); + } + if (!no_club.empty()) gdi.addStringUT(1, Ellipsis); + } + + gdi.dropLine(); + sprintf_s(bf, lang.tl("Löpare utan starttid: %d.").c_str(), no_start.size()); + gdi.addStringUT(1, bf); + i=0; + + while(!no_start.empty() && ++i<20){ + pRunner r=no_start.front(); + no_start.pop_front(); + string name = r->getClass() + ": " + r->getName(); + if (!r->getClub().empty()) + name += " ("+r->getClub()+")"; + + gdi.addStringUT(0, name); + } + if (!no_start.empty()) gdi.addStringUT(1, Ellipsis); + + gdi.dropLine(); + sprintf_s(bf, lang.tl("Löpare utan SI-bricka: %d.").c_str(), no_card.size()); + gdi.addStringUT(1, bf); + i=0; + + while(!no_card.empty() && ++i<20){ + pRunner r=no_card.front(); + no_card.pop_front(); + string name = r->getClass() + ": " + r->getName(); + if (!r->getClub().empty()) + name += " ("+r->getClub()+")"; + + gdi.addStringUT(0, name); + } + if (!no_card.empty()) gdi.addStringUT(1, Ellipsis); + + + gdi.dropLine(); + sprintf_s(bf, lang.tl("SI-dubbletter: %d.").c_str(), si_duplicate.size()); + gdi.addStringUT(1, bf); + i=0; + + while(!si_duplicate.empty() && ++i<50){ + pRunner r=si_duplicate.front(); + si_duplicate.pop_front(); + string name = r->getClass() + " / " + r->getName(); + if (!r->getClub().empty()) + name += " ("+r->getClub()+")"; + name += ": " + itos(r->getCardNo()); + gdi.addStringUT(0, name); + } + if (!si_duplicate.empty()) gdi.addStringUT(1, Ellipsis); + + if (useLongTimes()) { // Warn SICard5 + long times + bool header = false; + + i = 0; + for (r_it = Runners.begin(); r_it != Runners.end(); ++r_it) { + pRunner r = &(*r_it); + if (r_it->isRemoved()) + continue; + if (r_it->getCardNo() > 0 && r_it->getCardNo() < 300000) { + if (!header) { + gdi.dropLine(); + sprintf_s(bf, lang.tl("Gamla brickor utan stöd för långa tider").c_str(), si_duplicate.size()); + gdi.addStringUT(1, bf); + header = true; + } + + string name = r->getClass() + " / " + r->getName(); + if (!r->getClub().empty()) + name += " ("+r->getClub()+")"; + name += ": " + itos(r->getCardNo()); + gdi.addStringUT(0, name); + + if (++i > 5) { + gdi.addStringUT(1, Ellipsis); + break; + } + } + } + } + + // Clear markers + for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it) + r_it->_objectmarker=0; + + //List all competitors not in a team. + if (oe->hasTeam()) { + for (t_it=Teams.begin(); t_it != Teams.end(); ++t_it) { + if (t_it->isRemoved()) + continue; + pClass pc=getClass(t_it->getClassId()); + + if (pc){ + for(unsigned i=0;igetNumStages();i++){ + pRunner r=t_it->getRunner(i); + if (r) r->_objectmarker++; + } + } + } + + gdi.dropLine(); + gdi.addString("", 1, "Löpare som förekommer i mer än ett lag:"); + bool any = false; + for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){ + if (r_it->_objectmarker>1){ + string name = r_it->getClass() + ": " + r_it->getName(); + if (!r_it->getClub().empty()) + name += " ("+r_it->getClub()+")"; + + gdi.addStringUT(0, name); + any = true; + } + } + if (!any) + gdi.addStringUT(1, "0"); + } + sortRunners(ClassStartTime); + + gdi.dropLine(); + gdi.addString("", 1, "Individuella deltagare"); + + y=gdi.getCY(); + int tab[5]={0, 100, 350, 420, 550}; + for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it) { + if (r_it->isRemoved()) + continue; + if (r_it->_objectmarker==0){ //Only consider runners not in a team. + gdi.addStringUT(y, x+tab[0], 0, r_it->getClass(), tab[1]-tab[0]); + string name = r_it->getName(); + if (!r_it->getClub().empty()) + name += " ("+r_it->getClub()+")"; + gdi.addStringUT(y, x+tab[1], 0, name, tab[2]-tab[1]); + gdi.addStringUT(y, x+tab[2], 0, itos(r_it->getCardNo()), tab[3]-tab[2]); + gdi.addStringUT(y, x+tab[3], 0, r_it->getCourseName(), tab[4]-tab[3]); + y+=lh; + pCourse pc=r_it->getCourse(true); + + if (pc){ + vector res = pc->getCourseReadable(101); + for (size_t k = 0; kgetClassId()); + + gdi.addStringUT(0, t_it->getClass() + ": " + t_it->getName() + " " +t_it->getStartTimeS()); + + if (pc){ + for(unsigned i=0;igetNumStages();i++){ + pRunner r=t_it->getRunner(i); + if (r){ + gdi.addStringUT(0, r->getName()+ " SI: " +itos(r->getCardNo())); + + pCourse pcourse=r->getCourse(true); + + if (pcourse){ + y = gdi.getCY(); + vector res = pcourse->getCourseReadable(101); + for (size_t k = 0; k. + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oRunner.cpp: implementation of the oRunner class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "oRunner.h" + +#include "oEvent.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "table.h" +#include "meos_util.h" +#include "oFreeImport.h" +#include +#include "localizer.h" +#include "SportIdent.h" +#include +#include "intkeymapimpl.hpp" +#include "runnerdb.h" +#include "meosexception.h" +#include +#include "socket.h" +#include "MeOSFeatures.h" +#include "oListInfo.h" + +oRunner::RaceIdFormatter oRunner::raceIdFormatter; + +const string &oRunner::RaceIdFormatter::formatData(oBase *ob) const { + return itos(dynamic_cast(ob)->getRaceIdentifier()); +} + +string oRunner::RaceIdFormatter::setData(oBase *ob, const string &input) const { + int rid = atoi(input.c_str()); + if (input == "0") + ob->getDI().setInt("RaceId", 0); + else if (rid>0 && rid != dynamic_cast(ob)->getRaceIdentifier()) + ob->getDI().setInt("RaceId", rid); + return formatData(ob); +} + +int oRunner::RaceIdFormatter::addTableColumn(Table *table, const string &description, int minWidth) const { + return table->addColumn(description, max(minWidth, 90), true, true); +} + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +oAbstractRunner::oAbstractRunner(oEvent *poe, bool loading):oBase(poe) +{ + Class=0; + Club=0; + startTime = 0; + tStartTime = 0; + + FinishTime = 0; + tStatus = status = StatusUnknown; + + inputPoints = 0; + if (loading || !oe->hasPrevStage()) + inputStatus = StatusOK; + else + inputStatus = StatusNotCompetiting; + + inputTime = 0; + inputPlace = 0; + + tTimeAdjustment = 0; + tPointAdjustment = 0; + tAdjustDataRevision = -1; +} + +string oAbstractRunner::getInfo() const +{ + return getName(); +} + +void oAbstractRunner::setFinishTimeS(const string &t) +{ + setFinishTime(oe->getRelativeTime(t)); +} + +void oAbstractRunner::setStartTimeS(const string &t) +{ + setStartTime(oe->getRelativeTime(t), true, false); +} + +oRunner::oRunner(oEvent *poe):oAbstractRunner(poe, false) +{ + isTemporaryObject = false; + Id=oe->getFreeRunnerId(); + Course=0; + StartNo=0; + CardNo=0; + + tInTeam=0; + tLeg=0; + tLegEquClass = 0; + tNeedNoCard=false; + tUseStartPunch=true; + getDI().initData(); + correctionNeeded = false; + + tDuplicateLeg=0; + tParentRunner=0; + + Card=0; + cPriority=0; + + tCachedRunningTime = 0; + tSplitRevision = -1; + + tRogainingPoints = 0; + tRogainingOvertime = 0; + tReduction = 0; + tRogainingPointsGross = 0; + tAdaptedCourse = 0; + tAdaptedCourseRevision = -1; + + tShortenDataRevision = -1; + tNumShortening = 0; +} + +oRunner::oRunner(oEvent *poe, int id):oAbstractRunner(poe, true) +{ + isTemporaryObject = false; + Id=id; + oe->qFreeRunnerId = max(id, oe->qFreeRunnerId); + Course=0; + StartNo=0; + CardNo=0; + + tInTeam=0; + tLeg=0; + tLegEquClass = 0; + tNeedNoCard=false; + tUseStartPunch=true; + getDI().initData(); + correctionNeeded = false; + + tDuplicateLeg=0; + tParentRunner=0; + + Card=0; + cPriority=0; + tCachedRunningTime = 0; + tSplitRevision = -1; + + tRogainingPoints = 0; + tRogainingOvertime = 0; + tReduction = 0; + tRogainingPointsGross = 0; + tAdaptedCourse = 0; + tAdaptedCourseRevision = -1; +} + +oRunner::~oRunner() +{ + if (tInTeam){ + for(unsigned i=0;iRunners.size(); i++) + if (tInTeam->Runners[i] && tInTeam->Runners[i]==this) + tInTeam->Runners[i]=0; + + tInTeam=0; + } + + for (size_t k=0;ktParentRunner=0; + } + + if (tParentRunner) { + for (size_t k=0;kmultiRunner.size(); k++) + if (tParentRunner->multiRunner[k] == this) + tParentRunner->multiRunner[k]=0; + } + + delete tAdaptedCourse; + tAdaptedCourse = 0; +} + +bool oRunner::Write(xmlparser &xml) +{ + if (Removed) return true; + + xml.startTag("Runner"); + xml.write("Id", Id); + xml.write("Updated", Modified.getStamp()); + xml.write("Name", sName); + xml.write("Start", startTime); + xml.write("Finish", FinishTime); + xml.write("Status", status); + xml.write("CardNo", CardNo); + xml.write("StartNo", StartNo); + + xml.write("InputPoint", inputPoints); + if (inputStatus != StatusOK) + xml.write("InputStatus", itos(inputStatus)); //Force write of 0 + xml.write("InputTime", inputTime); + xml.write("InputPlace", inputPlace); + + if (Club) xml.write("Club", Club->Id); + if (Class) xml.write("Class", Class->Id); + if (Course) xml.write("Course", Course->Id); + + if (multiRunner.size()>0) + xml.write("MultiR", codeMultiR()); + + if (Card) { + assert(Card->tOwner==this); + Card->Write(xml); + } + getDI().write(xml); + + xml.endTag(); + + for (size_t k=0;kWrite(xml); + + return true; +} + +void oRunner::Set(const xmlobject &xo) +{ + xmlList xl; + xo.getObjects(xl); + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Id")){ + Id = it->getInt(); + } + else if (it->is("Name")){ + sName = it->get(); + getRealName(sName, tRealName); + } + else if (it->is("Start")){ + tStartTime = startTime = it->getInt(); + } + else if (it->is("Finish")){ + FinishTime = it->getInt(); + } + else if (it->is("Status")){ + unsigned rawStat = it->getInt(); + tStatus = status = RunnerStatus(rawStat<100u ? rawStat : 0); + } + else if (it->is("CardNo")){ + CardNo=it->getInt(); + } + else if (it->is("StartNo") || it->is("OrderId")) + StartNo=it->getInt(); + else if (it->is("Club")) + Club=oe->getClub(it->getInt()); + else if (it->is("Class")) + Class=oe->getClass(it->getInt()); + else if (it->is("Course")) + Course=oe->getCourse(it->getInt()); + else if (it->is("Card")){ + Card=oe->allocateCard(this); + Card->Set(*it); + assert(Card->getId()!=0); + } + else if (it->is("oData")) + getDI().set(*it); + else if (it->is("Updated")) + Modified.setStamp(it->get()); + else if (it->is("MultiR")) + decodeMultiR(it->get()); + else if (it->is("InputTime")) { + inputTime = it->getInt(); + } + else if (it->is("InputStatus")) { + unsigned rawStat = it->getInt(); + inputStatus = RunnerStatus(rawStat<100u ? rawStat : 0); + } + else if (it->is("InputPoint")) { + inputPoints = it->getInt(); + } + else if (it->is("InputPlace")) { + inputPlace = it->getInt(); + } + } +} + +int oAbstractRunner::getBirthAge() const { + return 0; +} + +int oRunner::getBirthAge() const { + int y = getBirthYear(); + if (y > 0) + return getThisYear() - y; + return 0; +} + +void oAbstractRunner::addClassDefaultFee(bool resetFees) { + if (Class) { + oDataInterface di = getDI(); + + if (isVacant()) { + di.setInt("Fee", 0); + di.setInt("EntryDate", 0); + di.setInt("Paid", 0); + if (typeid(*this)==typeid(oRunner)) + di.setInt("CardFee", 0); + return; + } + string date = getEntryDate(); + int currentFee = di.getInt("Fee"); + + pTeam t = getTeam(); + if (t && t != this) { + // Thus us a runner in a team + // Check if the team has a fee. + // Don't assign personal fee if so. + if (t->getDCI().getInt("Fee") > 0) + return; + } + + if ((currentFee == 0 && !hasFlag(FlagFeeSpecified)) || resetFees) { + int age = getBirthAge(); + int fee = Class->getEntryFee(date, age); + di.setInt("Fee", fee); + } + } +} + +// Get entry date of runner (or its team) +string oRunner::getEntryDate(bool useTeamEntryDate) const { + if (useTeamEntryDate && tInTeam) { + string date = tInTeam->getEntryDate(false); + if (!date.empty()) + return date; + } + oDataConstInterface dci = getDCI(); + int date = dci.getInt("EntryDate"); + if (date == 0) { + (const_cast(this)->getDI()).setDate("EntryDate", getLocalDate()); + } + return dci.getDate("EntryDate"); +} + +string oRunner::codeMultiR() const +{ + char bf[32]; + string r; + + for (size_t k=0;kgetId()); + r+=bf; + } + return r; +} + +void oRunner::decodeMultiR(const string &r) +{ + vector sv; + split(r, ":", sv); + multiRunnerId.clear(); + + for (size_t k=0;k0) + multiRunnerId.push_back(d); + } + multiRunnerId.push_back(0); // Mark as containing something +} + +void oAbstractRunner::setClassId(int id, bool isManualUpdate) { + pClass pc=Class; + Class=id ? oe->getClass(id):0; + + if (Class!=pc) { + apply(false, 0, false); + if (Class) { + Class->clearCache(true); + } + if (pc) { + pc->clearCache(true); + if (isManualUpdate) { + setFlag(FlagUpdateClass, true); + // Update heat data + int heat = pc->getDCI().getInt("Heat"); + if (heat != 0) + getDI().setInt("Heat", heat); + } + } + updateChanged(); + } +} + +// Update all classes (for multirunner) +void oRunner::setClassId(int id, bool isManualUpdate) +{ + if (tParentRunner) + tParentRunner->setClassId(id, isManualUpdate); + else { + pClass pc = Class; + pClass nPc = id>0 ? oe->getClass(id):0; + + if (pc && pc->isSingleRunnerMultiStage() && nPc!=pc && tInTeam) { + if (!isTemporaryObject) { + oe->autoRemoveTeam(this); + + if (nPc) { + int newNR = max(nPc->getNumMultiRunners(0), 1); + for (size_t k = newNR - 1; ktParentRunner == this); + multiRunner[k]->tParentRunner = 0; + vector toRemove; + toRemove.push_back(multiRunner[k]->Id); + oe->removeRunner(toRemove); + } + } + multiRunner.resize(newNR-1); + } + } + } + + Class = nPc; + + if (Class != 0 && Class != pc && tInTeam==0 && + Class->isSingleRunnerMultiStage()) { + if (!isTemporaryObject) { + pTeam t = oe->addTeam(getName(), getClubId(), getClassId()); + t->setStartNo(StartNo, false); + t->setRunner(0, this, true); + } + } + + apply(false, 0, false); //We may get old class back from team. + + for (size_t k=0;kClass) { + multiRunner[k]->Class=Class; + multiRunner[k]->updateChanged(); + } + } + + if (Class!=pc && !isTemporaryObject) { + if (Class) { + Class->clearCache(true); + } + if (pc) { + pc->clearCache(true); + } + tSplitRevision = 0; + updateChanged(); + if (isManualUpdate && pc) { + setFlag(FlagUpdateClass, true); + // Update heat data + int heat = pc->getDCI().getInt("Heat"); + if (heat != 0) + getDI().setInt("Heat", heat); + + } + } + } +} + +void oRunner::setCourseId(int id) +{ + pCourse pc=Course; + + if (id>0) + Course=oe->getCourse(id); + else + Course=0; + + if (Course!=pc) { + updateChanged(); + if (Class) + Class->clearSplitAnalysis(); + tSplitRevision = 0; + } +} + +bool oAbstractRunner::setStartTime(int t, bool updateSource, bool tmpOnly, bool recalculate) { + assert(!(updateSource && tmpOnly)); + if (tmpOnly) { + tmpStore.startTime = t; + return false; + } + + int tOST=tStartTime; + if (t>0) + tStartTime=t; + else tStartTime=0; + + if (updateSource) { + int OST=startTime; + startTime = tStartTime; + + if (OST!=startTime) { + updateChanged(); + } + } + + if (tOST != tStartTime) { + changedObject(); + if (Class) { + Class->clearCache(false); + } + } + + if (tOSTreCalculateLeaderTimes(Class->getId()); + + return tOST != tStartTime; +} + +void oAbstractRunner::setFinishTime(int t) +{ + int OFT=FinishTime; + + if (t>tStartTime) + FinishTime=t; + else //Beeb + FinishTime=0; + + if (OFT != FinishTime) { + updateChanged(); + if (Class) { + Class->clearCache(false); + } + } + + if (OFT>FinishTime && Class) + oe->reCalculateLeaderTimes(Class->getId()); +} + +void oRunner::setFinishTime(int t) +{ + bool update=false; + if (Class && (getTimeAfter(tDuplicateLeg)==0 || getTimeAfter()==0)) + update=true; + + oAbstractRunner::setFinishTime(t); + + tSplitRevision = 0; + + if (update && t!=FinishTime) + oe->reCalculateLeaderTimes(Class->getId()); +} + +const string &oAbstractRunner::getStartTimeS() const { + if (tStartTime>0) + return oe->getAbsTime(tStartTime); + else if (Class && Class->hasFreeStart()) + return _EmptyString; + else + return MakeDash("-"); +} + +const string &oAbstractRunner::getStartTimeCompact() const { + if (tStartTime>0) { + if (oe->useStartSeconds()) + return oe->getAbsTime(tStartTime); + else + return oe->getAbsTimeHM(tStartTime); + } + else if (Class && Class->hasFreeStart()) + return _EmptyString; + else + return MakeDash("-"); +} + +const string &oAbstractRunner::getFinishTimeS() const +{ + if (FinishTime>0) + return oe->getAbsTime(FinishTime); + else return MakeDash("-"); +} + +int oAbstractRunner::getRunningTime() const { + int rt = max(FinishTime-tStartTime, 0); + if (rt > 0) + return getTimeAdjustment() + rt; + else + return 0; +} + +const string &oAbstractRunner::getRunningTimeS() const +{ + return formatTime(getRunningTime()); +} + +const string &oAbstractRunner::getTotalRunningTimeS() const +{ + return formatTime(getTotalRunningTime()); +} + +int oAbstractRunner::getTotalRunningTime() const { + int t = getRunningTime(); + if (t > 0 && inputTime>=0) + return t + inputTime; + else + return 0; +} + +int oRunner::getTotalRunningTime() const { + return getTotalRunningTime(getFinishTime()); +} + + +const string &oAbstractRunner::getStatusS() const +{ + return oEvent::formatStatus(tStatus); +} + +const string &oAbstractRunner::getTotalStatusS() const +{ + return oEvent::formatStatus(getTotalStatus()); +} + +/* + - Inactive : Has not yet started + - DidNotStart : Did Not Start (in this race) + - Active : Currently on course + - Finished : Finished but not validated + - OK : Finished and validated + - MisPunch : Missing Punch + - DidNotFinish : Did Not Finish + - Disqualified : Disqualified + - NotCompeting : Not Competing (running outside the competition) + - SportWithdr : Sporting Withdrawal (e.g. helping injured) + - OverTime : Overtime, i.e. did not finish within max time + - Moved : Moved to another class + - MovedUp : Moved to a "better" class, in case of entry + restrictions + - Cancelled +*/ +const char *formatIOFStatus(RunnerStatus s) { + switch(s) { + case StatusOK: + return "OK"; + case StatusDNS: + return "DidNotStart"; + case StatusMP: + return "MisPunch"; + case StatusDNF: + return "DidNotFinish"; + case StatusDQ: + return "Disqualified"; + case StatusMAX: + return "OverTime"; + } + return "Inactive"; + +} + +string oAbstractRunner::getIOFStatusS() const +{ + return formatIOFStatus(tStatus); +} + +string oAbstractRunner::getIOFTotalStatusS() const +{ + return formatIOFStatus(getTotalStatus()); +} + +void oRunner::addPunches(pCard card, vector &missingPunches) { + RunnerStatus oldStatus = getStatus(); + int oldFinishTime = getFinishTime(); + pCard oldCard = Card; + + if (Card && card != Card) { + Card->tOwner = 0; + } + + Card = card; + card->adaptTimes(getStartTime()); + updateChanged(); + + if (card) { + if (CardNo==0) + CardNo=card->cardNo; + //315422 + assert(card->tOwner==0 || card->tOwner==this); + } + // Auto-select shortening + pCourse mainCourse = getCourse(false); + if (mainCourse && Card) { + pCourse shortVersion = mainCourse->getShorterVersion(); + if (shortVersion) { + //int s = mainCourse->getStartPunchType(); + //int f = mainCourse->getFinishPunchType(); + const int numCtrl = Card->getNumControlPunches(-1,-1); + int numCtrlLong = mainCourse->getNumControls(); + int numCtrlShort = shortVersion->getNumControls(); + + SICard sic; + Card->getSICard(sic); + int level = 0; + while (mainCourse->distance(sic) < 0 && abs(numCtrl-numCtrlShort) < abs(numCtrl-numCtrlLong)) { + level++; + if (shortVersion->distance(sic) >= 0) { + setNumShortening(level); // We passed at some level + break; + } + mainCourse = shortVersion; + shortVersion = mainCourse->getShorterVersion(); + numCtrlLong = numCtrlShort; + if (!shortVersion) { + break; + } + numCtrlShort = shortVersion->getNumControls(); + } + } + } + + if (Card) + Card->tOwner=this; + + evaluateCard(true, missingPunches, 0, true); + + if (oe->isClient() && oe->getPropertyInt("UseDirectSocket", true)!=0) { + if (oldStatus != getStatus() || oldFinishTime != getFinishTime()) { + SocketPunchInfo pi; + pi.runnerId = getId(); + pi.time = getFinishTime(); + pi.status = getStatus(); + pi.iHashType = oPunch::PunchFinish; + oe->getDirectSocket().sendPunch(pi); + } + } + + oe->pushDirectChange(); + if (oldCard && Card && oldCard != Card && oldCard->isConstructedFromPunches()) + oldCard->remove(); // Remove card constructed from punches +} + +pCourse oRunner::getCourse(bool useAdaptedCourse) const { + pCourse tCrs = 0; + if (Course) + tCrs = Course; + else if (Class) { + if (Class->hasMultiCourse()) { + if (tInTeam) { + if (size_t(tLeg) >= tInTeam->Runners.size() || tInTeam->Runners[tLeg] != this) { + tInTeam->quickApply(); + } + } + + if (tInTeam && Class->hasUnorderedLegs()) { + vector< pair > group; + Class->getParallelCourseGroup(tLeg, StartNo, group); + + if (group.size() == 1) { + tCrs = group[0].second; + } + else { + // Remove used courses + int myStart = 0; + + for (size_t k = 0; k < group.size(); k++) { + if (group[k].first == tLeg) + myStart = k; + + pRunner tr = tInTeam->getRunner(group[k].first); + if (tr && tr->Course) { + // The course is assigned. Remove from group + for (size_t j = 0; j < group.size(); j++) { + if (group[j].second == tr->Course) { + group[j].second = 0; + break; + } + } + } + } + + // Clear out already preliminary assigned courses + for (int k = 0; k < myStart; k++) { + pRunner r = tInTeam->getRunner(group[k].first); + if (r && !r->Course) { + size_t j = k; + while (j < group.size()) { + if (group[j].second) { + group[j].second = 0; + break; + } + else j++; + } + } + } + + for (size_t j = 0; j < group.size(); j++) { + int ix = (j + myStart) % group.size(); + pCourse gcrs = group[ix].second; + if (gcrs) { + tCrs = gcrs; + break; + } + } + } + } + else if (tInTeam) { + unsigned leg=legToRun(); + tCrs = Class->getCourse(leg, StartNo); + /*if (legMultiCourse.size()) { + vector &courses=Class->MultiCourse[leg]; + if (courses.size()>0) { + int index=StartNo; + if (index>0) + index = (index-1) % courses.size(); + + tCrs = courses[index]; + } + }*/ + } + else { + if (unsigned(tDuplicateLeg)MultiCourse.size()) { + vector &courses=Class->MultiCourse[tDuplicateLeg]; + if (courses.size()>0) { + int index=StartNo % courses.size(); + tCrs = courses[index]; + } + } + } + } + else + tCrs = Class->Course; + } + + if (tCrs && useAdaptedCourse) { + // Find shortened version of course + int ns = getNumShortening(); + pCourse shortCrs = tCrs; + while (ns > 0 && shortCrs) { + shortCrs = shortCrs->getShorterVersion(); + if (shortCrs) + tCrs = shortCrs; + ns--; + } + } + + if (tCrs && useAdaptedCourse && Card && tCrs->getCommonControl() != 0) { + if (tAdaptedCourse && tAdaptedCourseRevision == oe->dataRevision) { + return tAdaptedCourse; + } + if (!tAdaptedCourse) + tAdaptedCourse = new oCourse(oe, -1); + + tCrs = tCrs->getAdapetedCourse(*Card, *tAdaptedCourse); + tAdaptedCourseRevision = oe->dataRevision; + return tCrs; + } + + return tCrs; +} + +const string &oRunner::getCourseName() const +{ + pCourse oc=getCourse(false); + if (oc) return oc->getName(); + return MakeDash("-"); +} + +#define NOTATIME 0xF0000000 +void oAbstractRunner::resetTmpStore() { + tmpStore.startTime = startTime; + tmpStore.status = status; + tmpStore.startNo = StartNo; + tmpStore.bib = getBib(); +} + +bool oAbstractRunner::setTmpStore() { + bool res = false; + setStartNo(tmpStore.startNo, false); + res |= setStartTime(tmpStore.startTime, false, false, false); + res |= setStatus(tmpStore.status, false, false, false); + setBib(tmpStore.bib, 0, false, false); + return res; +} + +bool oRunner::evaluateCard(bool doApply, vector & MissingPunches, + int addpunch, bool sync) { + if (unsigned(status) >= 100u) + status = StatusUnknown; //Reset bad input + + MissingPunches.clear(); + int oldFT = FinishTime; + int oldStartTime; + RunnerStatus oldStatus; + int *refStartTime; + RunnerStatus *refStatus; + + if (doApply) { + oldStartTime = tStartTime; + tStartTime = startTime; + oldStatus = tStatus; + tStatus = status; + refStartTime = &tStartTime; + refStatus = &tStatus; + + resetTmpStore(); + apply(sync, 0, true); + } + else { + // tmp initialized from outside. Do not change tStatus, tStartTime. Work with tmpStore instead! + oldStartTime = tStartTime; + oldStatus = tStatus; + refStartTime = &tmpStore.startTime; + refStatus = &tmpStore.status; + + createMultiRunner(false, sync); + } + + // Reset card data + oPunchList::iterator p_it; + if (Card) { + for (p_it=Card->punches.begin(); p_it!=Card->punches.end(); ++p_it) { + p_it->tRogainingIndex = -1; + p_it->tRogainingPoints = 0; + p_it->isUsed = false; + p_it->tIndex = -1; + p_it->tMatchControlId = -1; + p_it->tTimeAdjust = 0; + } + } + + bool inTeam = tInTeam != 0; + tProblemDescription.clear(); + tReduction = 0; + tRogainingPointsGross = 0; + tRogainingOvertime = 0; + + vector oldTimes; + swap(splitTimes, oldTimes); + + if (!Card) { + if ((inTeam || !tUseStartPunch) && doApply) + apply(sync, 0, false); //Post apply. Update start times. + + if (storeTimes() && Class && sync) { + set cls; + cls.insert(Class->getId()); + oe->reEvaluateAll(cls, sync); + } + normalizedSplitTimes.clear(); + if (oldTimes.size() > 0 && Class) + Class->clearSplitAnalysis(); + return false; + } + //Try to match class?! + if (!Class) + return false; + + if (Class->ignoreStartPunch()) + tUseStartPunch = false; + + const pCourse course = getCourse(true); + + if (!course) { + // Reset rogaining. Store start/finish + for (p_it=Card->punches.begin(); p_it!=Card->punches.end(); ++p_it) { + if (p_it->isStart() && tUseStartPunch) + *refStartTime = p_it->Time; + else if (p_it->isFinish()) + setFinishTime(p_it->Time); + } + if ((inTeam || !tUseStartPunch) && doApply) + apply(sync, 0, false); //Post apply. Update start times. + + storeTimes(); + return false; + } + + int startPunchCode = course->getStartPunchType(); + int finishPunchCode = course->getFinishPunchType(); + + bool hasRogaining = course->hasRogaining(); + + // Pairs: + intkeymap< pair > rogaining(course->getNumControls()); + for (int k = 0; k< course->nControls; k++) { + if (course->Controls[k] && course->Controls[k]->isRogaining(hasRogaining)) { + int pt = course->Controls[k]->getRogainingPoints(); + for (int j = 0; jControls[k]->nNumbers; j++) { + rogaining.insert(course->Controls[k]->Numbers[j], make_pair(k, pt)); + } + } + } + + if (addpunch && Card->punches.empty()) { + Card->addPunch(addpunch, -1, course->Controls[0] ? course->Controls[0]->getId():0); + } + + if (Card->punches.empty()) { + for(int k=0;knControls;k++) { + if (course->Controls[k]) { + course->Controls[k]->startCheckControl(); + course->Controls[k]->addUncheckedPunches(MissingPunches, hasRogaining); + } + } + if ((inTeam || !tUseStartPunch) && doApply) + apply(sync, 0, false); //Post apply. Update start times. + + if (storeTimes() && Class && sync) { + set cls; + cls.insert(Class->getId()); + oe->reEvaluateAll(cls, sync); + } + + normalizedSplitTimes.clear(); + if (oldTimes.size() > 0 && Class) + Class->clearSplitAnalysis(); + tRogainingPoints = max(0, getPointAdjustment()); + return false; + } + + // Reset rogaining + for (p_it=Card->punches.begin(); p_it!=Card->punches.end(); ++p_it) { + p_it->tRogainingIndex = -1; + p_it->tRogainingPoints = 0; + } + + bool clearSplitAnalysis = false; + + + //Search for start and update start time. + p_it=Card->punches.begin(); + while ( p_it!=Card->punches.end()) { + if (p_it->Type == startPunchCode) { + if (tUseStartPunch && p_it->getAdjustedTime() != *refStartTime) { + p_it->setTimeAdjust(0); + *refStartTime = p_it->getAdjustedTime(); + if (*refStartTime != oldStartTime) + clearSplitAnalysis = true; + //updateChanged(); + } + break; + } + ++p_it; + } + + inthashmap expectedPunchCount(course->nControls); + inthashmap punchCount(Card->punches.size()); + for (int k=0; knControls; k++) { + pControl ctrl=course->Controls[k]; + if (ctrl && !ctrl->isRogaining(hasRogaining)) { + for (int j = 0; jnNumbers; j++) + ++expectedPunchCount[ctrl->Numbers[j]]; + } + } + + for (p_it = Card->punches.begin(); p_it != Card->punches.end(); ++p_it) { + if (p_it->Type>=10 && p_it->Type<=1024) + ++punchCount[p_it->Type]; + } + + p_it = Card->punches.begin(); + splitTimes.resize(course->nControls, SplitData(NOTATIME, SplitData::Missing)); + int k=0; + + + for (k=0;knControls;k++) { + //Skip start finish check + while(p_it!=Card->punches.end() && + (p_it->isCheck() || p_it->isFinish() || p_it->isStart())) { + p_it->setTimeAdjust(0); + ++p_it; + } + + if (p_it==Card->punches.end()) + break; + + oPunchList::iterator tp_it=p_it; + pControl ctrl=course->Controls[k]; + int skippedPunches = 0; + + if (ctrl) { + int timeAdjust=ctrl->getTimeAdjust(); + ctrl->startCheckControl(); + + // Add rogaining punches + if (addpunch && ctrl->isRogaining(hasRogaining) && ctrl->getFirstNumber() == addpunch) { + if ( Card->getPunchByType(addpunch) == 0) { + oPunch op(oe); + op.Type=addpunch; + op.Time=-1; + op.isUsed=true; + op.tIndex = k; + op.tMatchControlId=ctrl->getId(); + Card->punches.insert(tp_it, op); + Card->updateChanged(); + } + } + + if (ctrl->getStatus() == oControl::StatusBad || ctrl->getStatus() == oControl::StatusOptional) { + // The control is marked "bad" but we found it anyway in the card. Mark it as used. + if (tp_it!=Card->punches.end() && ctrl->hasNumberUnchecked(tp_it->Type)) { + tp_it->isUsed=true; //Show that this is used when splittimes are calculated. + // Adjust if the time of this control was incorrectly set. + tp_it->setTimeAdjust(timeAdjust); + tp_it->tMatchControlId=ctrl->getId(); + tp_it->tIndex = k; + splitTimes[k].setPunchTime(tp_it->getAdjustedTime()); + ++tp_it; + p_it=tp_it; + } + } + else { + while(!ctrl->controlCompleted(hasRogaining) && tp_it!=Card->punches.end()) { + if (ctrl->hasNumberUnchecked(tp_it->Type)) { + + if (skippedPunches>0) { + if (ctrl->Status == oControl::StatusOK) { + int code = tp_it->Type; + if (expectedPunchCount[code]>1 && punchCount[code] < expectedPunchCount[code]) { + tp_it==Card->punches.end(); + ctrl->uncheckNumber(code); + break; + } + } + } + tp_it->isUsed=true; //Show that this is used when splittimes are calculated. + // Adjust if the time of this control was incorrectly set. + tp_it->setTimeAdjust(timeAdjust); + tp_it->tMatchControlId=ctrl->getId(); + tp_it->tIndex = k; + if (ctrl->controlCompleted(hasRogaining)) + splitTimes[k].setPunchTime(tp_it->getAdjustedTime()); + ++tp_it; + p_it=tp_it; + } + else { + if (ctrl->hasNumberUnchecked(addpunch)){ + //Add this punch. + oPunch op(oe); + op.Type=addpunch; + op.Time=-1; + op.isUsed=true; + + op.tMatchControlId=ctrl->getId(); + op.tIndex = k; + Card->punches.insert(tp_it, op); + Card->updateChanged(); + if (ctrl->controlCompleted(hasRogaining)) + splitTimes[k].setPunched(); + } + else { + skippedPunches++; + tp_it->isUsed=false; + ++tp_it; + } + } + } + } + + if (tp_it==Card->punches.end() && !ctrl->controlCompleted(hasRogaining) + && ctrl->hasNumberUnchecked(addpunch) ) { + Card->addPunch(addpunch, -1, ctrl->getId()); + if (ctrl->controlCompleted(hasRogaining)) + splitTimes[k].setPunched(); + Card->punches.back().isUsed=true; + Card->punches.back().tMatchControlId=ctrl->getId(); + Card->punches.back().tIndex = k; + } + + if (ctrl->controlCompleted(hasRogaining) && splitTimes[k].time == NOTATIME) + splitTimes[k].setPunched(); + } + else //if (ctrl && ctrl->Status==oControl::StatusBad){ + splitTimes[k].setNotPunched(); + + //Add missing punches + if (ctrl && !ctrl->controlCompleted(hasRogaining)) + ctrl->addUncheckedPunches(MissingPunches, hasRogaining); + } + + //Add missing punches for remaining controls + while (knControls) { + if (course->Controls[k]) { + pControl ctrl = course->Controls[k]; + ctrl->startCheckControl(); + + if (ctrl->hasNumberUnchecked(addpunch)) { + Card->addPunch(addpunch, -1, ctrl->getId()); + Card->updateChanged(); + if (ctrl->controlCompleted(hasRogaining)) + splitTimes[k].setNotPunched(); + } + ctrl->addUncheckedPunches(MissingPunches, hasRogaining); + } + k++; + } + + //Set the rest (if exist -- probably not) to "not used" + while(p_it!=Card->punches.end()){ + p_it->isUsed=false; + p_it->tIndex = -1; + p_it->setTimeAdjust(0); + ++p_it; + } + + int OK = MissingPunches.empty(); + + tRogaining.clear(); + tRogainingPoints = 0; + int time_limit = 0; + + // Rogaining logic + if (rogaining.size() > 0) { + set visitedControls; + for (p_it=Card->punches.begin(); p_it != Card->punches.end(); ++p_it) { + pair pt; + if (rogaining.lookup(p_it->Type, pt)) { + if (visitedControls.count(pt.first) == 0) { + visitedControls.insert(pt.first); // May noy be revisited + p_it->isUsed = true; + p_it->tRogainingIndex = pt.first; + p_it->tMatchControlId = course->Controls[pt.first]->getId(); + p_it->tRogainingPoints = pt.second; + tRogaining.push_back(make_pair(course->Controls[pt.first], p_it->getAdjustedTime())); + splitTimes[pt.first].setPunchTime(p_it->getAdjustedTime()); + tRogainingPoints += pt.second; + } + } + } + + // Manual point adjustment + tRogainingPoints = max(0, tRogainingPoints + getPointAdjustment()); + + int point_limit = course->getMinimumRogainingPoints(); + if (point_limit>0 && tRogainingPointsgetMaximumRogainingTime(); + + for (int k = 0; knControls; k++) { + if (course->Controls[k] && course->Controls[k]->isRogaining(hasRogaining)) { + if (!visitedControls.count(k)) + splitTimes[k].setNotPunched();// = splitTimes[k-1]; + } + } + } + + int maxTimeStatus = 0; + if (Class && FinishTime>0) { + int mt = Class->getMaximumRunnerTime(); + if (mt>0) { + if (getRunningTime() > mt) + maxTimeStatus = 1; + else + maxTimeStatus = 2; + } + else + maxTimeStatus = 2; + } + + if (*refStatus == StatusMAX && maxTimeStatus == 2) + *refStatus = StatusUnknown; + + if (OK && (*refStatus==0 || *refStatus==StatusDNS || *refStatus==StatusMP || *refStatus==StatusOK || *refStatus==StatusDNF)) + *refStatus = StatusOK; + else *refStatus = RunnerStatus(max(int(StatusMP), int(*refStatus))); + + oPunchList::reverse_iterator backIter = Card->punches.rbegin(); + + if (finishPunchCode != oPunch::PunchFinish) { + while (backIter != Card->punches.rend()) { + if (backIter->Type == finishPunchCode) + break; + ++backIter; + } + } + + if (backIter != Card->punches.rend() && backIter->Type == finishPunchCode) { + FinishTime = backIter->Time; + if (finishPunchCode == oPunch::PunchFinish) + backIter->tMatchControlId=oPunch::PunchFinish; + } + else if (FinishTime<=0) { + *refStatus=RunnerStatus(max(int(StatusDNF), int(tStatus))); + tProblemDescription = "Måltid saknas."; + FinishTime=0; + } + + if (*refStatus == StatusOK && maxTimeStatus == 1) + *refStatus = StatusMAX; //Maxtime + + if (!MissingPunches.empty()) { + tProblemDescription = "Stämplingar saknas: X#" + itos(MissingPunches[0]); + for (unsigned j = 1; j<3; j++) { + if (MissingPunches.size()>j) + tProblemDescription += ", " + itos(MissingPunches[j]); + } + if (MissingPunches.size()>3) + tProblemDescription += "..."; + else + tProblemDescription += "."; + } + + // Adjust times on course, including finish time + doAdjustTimes(course); + + tRogainingPointsGross = tRogainingPoints; + if (time_limit > 0) { + int rt = getRunningTime(); + if (rt > 0) { + int overTime = rt - time_limit; + if (overTime > 0) { + tRogainingOvertime = overTime; + tReduction = course->calculateReduction(overTime); + tProblemDescription = "Tidsavdrag: X poäng.#" + itos(tReduction); + tRogainingPoints = max(0, tRogainingPoints - tReduction); + } + } + } + + if (oldStatus!=*refStatus || oldFT!=FinishTime) { + clearSplitAnalysis = true; + } + + if ((inTeam || !tUseStartPunch) && doApply) + apply(sync, 0, false); //Post apply. Update start times. + + if (tCachedRunningTime != FinishTime - *refStartTime) { + tCachedRunningTime = FinishTime - *refStartTime; + clearSplitAnalysis = true; + } + + // Clear split analysis data if necessary + bool clear = splitTimes.size() != oldTimes.size() || clearSplitAnalysis; + for (size_t k = 0; !clear && kclearSplitAnalysis(); + } + + if (doApply) + storeTimes(); + if (Class && sync) { + bool update = false; + if (tInTeam) { + int t1 = Class->getTotalLegLeaderTime(tLeg, false); + int t2 = tInTeam->getLegRunningTime(tLeg, false); + if (t2<=t1 && t2>0) + update = true; + + int t3 = Class->getTotalLegLeaderTime(tLeg, true); + int t4 = tInTeam->getLegRunningTime(tLeg, true); + if (t4<=t3 && t4>0) + update = true; + } + + if (!update) { + int t1 = Class->getBestLegTime(tLeg); + int t2 = getRunningTime(); + if (t2<=t1 && t2>0) + update = true; + } + if (update) { + set cls; + cls.insert(Class->getId()); + oe->reEvaluateAll(cls, sync); + } + } + return true; +} + +void oRunner::clearOnChangedRunningTime() { + if (tCachedRunningTime != FinishTime - tStartTime) { + tCachedRunningTime = FinishTime - tStartTime; + normalizedSplitTimes.clear(); + if (Class) + Class->clearSplitAnalysis(); + } +} + +void oRunner::doAdjustTimes(pCourse course) { + if (!Card) + return; + + assert(course->nControls == splitTimes.size()); + int adjustment = 0; + oPunchList::iterator it = Card->punches.begin(); + + adjustTimes.resize(splitTimes.size()); + for (int n = 0; n < course->nControls; n++) { + pControl ctrl = course->Controls[n]; + if (!ctrl) + continue; + + while (it != Card->punches.end() && !it->isUsed) { + it->setTimeAdjust(adjustment); + ++it; + } + + int minTime = ctrl->getMinTime(); + if (ctrl->getStatus() == oControl::StatusNoTiming) { + int t = 0; + if (n>0 && splitTimes[n].time>0 && splitTimes[n-1].time>0) { + t = splitTimes[n].time + adjustment - splitTimes[n-1].time; + } + else if (n == 0 && splitTimes[n].time>0) { + t = splitTimes[n].time - tStartTime; + } + adjustment -= t; + } + else if (minTime>0) { + int t = 0; + if (n>0 && splitTimes[n].time>0 && splitTimes[n-1].time>0) { + t = splitTimes[n].time + adjustment - splitTimes[n-1].time; + } + else if (n == 0 && splitTimes[n].time>0) { + t = splitTimes[n].time - tStartTime; + } + int maxadjust = max(minTime-t, 0); + adjustment += maxadjust; + } + + if (it != Card->punches.end() && it->tMatchControlId == ctrl->getId()) { + it->adjustTimeAdjust(adjustment); + ++it; + } + + adjustTimes[n] = adjustment; + if (splitTimes[n].time>0) + splitTimes[n].time += adjustment; + } + + // Adjust remaining + while (it != Card->punches.end()) { + it->setTimeAdjust(adjustment); + ++it; + } + + FinishTime += adjustment; +} + +bool oRunner::storeTimes() { + bool updated = storeTimesAux(Class); + if (tInTeam && tInTeam->Class && tInTeam->Class != Class) + updated |= storeTimesAux(tInTeam->Class); + + return updated; +} + +bool oRunner::storeTimesAux(pClass targetClass) { + if (tInTeam) { + if (tInTeam->getNumShortening(tLeg) > 0) + return false; + } + else { + if (getNumShortening() > 0) + return false; + } + bool updated = false; + //Store best time in class + if (tInTeam && tInTeam->Class == targetClass) { + if (targetClass && unsigned(tLeg)tLeaderTime.size()) { + // Update for extra/optional legs + int firstLeg = tLeg; + int lastLeg = tLeg + 1; + while(firstLeg>0 && targetClass->legInfo[firstLeg].isOptional()) + firstLeg--; + int nleg = targetClass->legInfo.size(); + while(lastLeglegInfo[lastLeg].isOptional()) + lastLeg++; + + for (int leg = firstLeg; legtLeaderTime[leg].bestTimeOnLeg; + int rt=getRunningTime(); + if (rt > 0 && (bt == 0 || rt < bt)) { + bt=rt; + updated = true; + } + } + } + + bool updateTotal = true; + bool updateTotalInput = true; + + int basePLeg = firstLeg; + while (basePLeg > 0 && targetClass->legInfo[basePLeg].isParallel()) + basePLeg--; + + int ix = basePLeg; + while (ix < nleg && (ix == basePLeg || targetClass->legInfo[ix].isParallel()) ) { + updateTotal = updateTotal && tInTeam->getLegStatus(ix, false)==StatusOK; + updateTotalInput = updateTotalInput && tInTeam->getLegStatus(ix, true)==StatusOK; + ix++; + } + + if (updateTotal) { + int rt = 0; + int ix = basePLeg; + while (ix < nleg && (ix == basePLeg || targetClass->legInfo[ix].isParallel()) ) { + rt = max(rt, tInTeam->getLegRunningTime(ix, false)); + ix++; + } + + for (int leg = firstLeg; legtLeaderTime[leg].totalLeaderTime; + if (rt > 0 && (bt == 0 || rt < bt)) { + bt=rt; + updated = true; + } + } + } + if (updateTotalInput) { + //int rt=tInTeam->getLegRunningTime(tLeg, true); + int rt = 0; + int ix = basePLeg; + while (ix < nleg && (ix == basePLeg || targetClass->legInfo[ix].isParallel()) ) { + rt = max(rt, tInTeam->getLegRunningTime(ix, true)); + ix++; + } + for (int leg = firstLeg; legtLeaderTime[leg].totalLeaderTimeInput; + if (rt > 0 && (bt == 0 || rt < bt)) { + bt=rt; + updated = true; + } + } + } + } + } + else { + if (targetClass && unsigned(tDuplicateLeg)tLeaderTime.size()) { + if (tStatus==StatusOK) { + int &bt=targetClass->tLeaderTime[tDuplicateLeg].bestTimeOnLeg; + int rt=getRunningTime(); + if (rt > 0 && (bt==0 || rttLeaderTime[tDuplicateLeg].totalLeaderTime; + int rt=getRaceRunningTime(tDuplicateLeg); + if (rt>0 && (bt==0 || rttLeaderTime[tDuplicateLeg].totalLeaderTimeInput = rt; + } + } + } + + // Best input time + if (targetClass && unsigned(tLeg)tLeaderTime.size()) { + int &it = targetClass->tLeaderTime[tLeg].inputTime; + if (inputTime > 0 && inputStatus == StatusOK && (it == 0 || inputTime < it) ) { + it = inputTime; + updated = true; + } + } + + if (targetClass && tStatus==StatusOK) { + int rt = getRunningTime(); + pCourse pCrs = getCourse(false); + if (pCrs && rt > 0) { + map::iterator res = targetClass->tBestTimePerCourse.find(pCrs->getId()); + if (res == targetClass->tBestTimePerCourse.end()) { + targetClass->tBestTimePerCourse[pCrs->getId()] = rt; + updated = true; + } + else if (rt < res->second) { + res->second = rt; + updated = true; + } + } + } + return updated; +} + +int oRunner::getRaceRunningTime(int leg) const +{ + if (tParentRunner) + return tParentRunner->getRaceRunningTime(leg); + + if (leg==-1) + leg=multiRunner.size()-1; + + if (leg==0) { + if (getTotalStatus() == StatusOK) + return getRunningTime() + inputTime; + else return 0; + } + leg--; + + if (unsigned(leg) < multiRunner.size() && multiRunner[leg]) { + if (Class) { + pClass pc=Class; + LegTypes lt=pc->getLegType(leg); + pRunner r=multiRunner[leg]; + + switch(lt) { + case LTNormal: + if (r->statusOK()) { + int dt=leg>0 ? r->getRaceRunningTime(leg)+r->getRunningTime():0; + return max(r->getFinishTime()-tStartTime, dt); // ### Luckor, jaktstart??? + } + else return 0; + break; + + case LTSum: + if (r->statusOK()) + return r->getRunningTime()+getRaceRunningTime(leg); + else return 0; + + default: + return 0; + } + } + else return getRunningTime(); + } + return 0; +} + +bool oRunner::sortSplit(const oRunner &a, const oRunner &b) +{ + int acid=a.getClassId(); + int bcid=b.getClassId(); + if (acid!=bcid) + return acidgetClassStatus() != oClass::Normal) + return CompareString(LOCALE_USER_DEFAULT, 0, + tRealName.c_str(), tRealName.length(), + c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; + + if (oe->CurrentSortOrder==ClassStartTime) { + if (Class->Id != c.Class->Id) + return Class->tSortIndex < c.Class->tSortIndex; + else if (tStartTime != c.tStartTime) { + if (tStartTime <= 0 && c.tStartTime > 0) + return false; + else if (c.tStartTime <= 0 && tStartTime > 0) + return true; + else return tStartTime < c.tStartTime; + } + else { + //if (StartNo != c.StartNo && !(getBib().empty() && c.getBib().empty())) + // return StartNo < c.StartNo; + const string &b1 = getBib(); + const string &b2 = c.getBib(); + if (b1 != b2) { + return compareBib(b1, b2); + } + } + } + else if (oe->CurrentSortOrder==ClassResult) { + RunnerStatus stat = tStatus == StatusUnknown ? StatusOK : tStatus; + RunnerStatus cstat = c.tStatus == StatusUnknown ? StatusOK : c.tStatus; + + if (Class != c.Class) + return Class->tSortIndex < c.Class->tSortIndex; + else if (tLegEquClass != c.tLegEquClass) + return tLegEquClass < c.tLegEquClass; + else if (tDuplicateLeg != c.tDuplicateLeg) + return tDuplicateLeg < c.tDuplicateLeg; + else if (stat != cstat) + return RunnerStatusOrderMap[stat] < RunnerStatusOrderMap[cstat]; + else { + if (stat==StatusOK) { + if (Class->getNoTiming()) { + return CompareString(LOCALE_USER_DEFAULT, 0, + tRealName.c_str(), tRealName.length(), + c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; + } + int s = getNumShortening(); + int cs = c.getNumShortening(); + if (s != cs) + return s < cs; + + int t=getRunningTime(); + if (t<=0) + t = 3600*100; + int ct=c.getRunningTime(); + if (ct<=0) + ct = 3600*100; + + if (t!=ct) + return tCurrentSortOrder == ClassCourseResult) { + if (Class != c.Class) + return Class->tSortIndex < c.Class->tSortIndex; + + const pCourse crs1 = getCourse(false); + const pCourse crs2 = c.getCourse(false); + if (crs1 != crs2) { + int id1 = crs1 ? crs1->getId() : 0; + int id2 = crs2 ? crs2->getId() : 0; + return id1 < id2; + } + else if (tDuplicateLeg != c.tDuplicateLeg) + return tDuplicateLeg < c.tDuplicateLeg; + else if (tStatus != c.tStatus) + return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus]; + else { + if (tStatus==StatusOK) { + if (Class->getNoTiming()) { + return CompareString(LOCALE_USER_DEFAULT, 0, + tRealName.c_str(), tRealName.length(), + c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; + } + int s = getNumShortening(); + int cs = c.getNumShortening(); + if (s != cs) + return s < cs; + + int t=getRunningTime(); + int ct=c.getRunningTime(); + if (t!=ct) + return tCurrentSortOrder==SortByName) { + return CompareString(LOCALE_USER_DEFAULT, 0, + tRealName.c_str(), tRealName.length(), + c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; + } + else if (oe->CurrentSortOrder==SortByLastName) { + string a = getFamilyName(); + string b = c.getFamilyName(); + if (a.empty() && !b.empty()) + return false; + else if (b.empty() && !a.empty()) + return true; + else if (a != b) { + return CompareString(LOCALE_USER_DEFAULT, 0, + a.c_str(), a.length(), + b.c_str(), b.length()) == CSTR_LESS_THAN; + } + a = getGivenName(); + b = c.getGivenName(); + if (a != b) { + return CompareString(LOCALE_USER_DEFAULT, 0, + a.c_str(), a.length(), + b.c_str(), b.length()) == CSTR_LESS_THAN; + } + } + else if (oe->CurrentSortOrder==SortByFinishTime) { + if (tStatus != c.tStatus) + return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus]; + else { + int ft = getFinishTimeAdjusted(); + int cft = c.getFinishTimeAdjusted(); + if (tStatus==StatusOK && ft != cft) + return ft < cft; + } + } + else if (oe->CurrentSortOrder==SortByFinishTimeReverse) { + int ft = getFinishTimeAdjusted(); + int cft = c.getFinishTimeAdjusted(); + if (ft != cft) + return ft > cft; + } + else if (oe->CurrentSortOrder == ClassFinishTime){ + if (Class != c.Class) + return Class->tSortIndex < c.Class->tSortIndex; + if (tStatus != c.tStatus) + return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus]; + else{ + int ft = getFinishTimeAdjusted(); + int cft = c.getFinishTimeAdjusted(); + if (tStatus==StatusOK && ft != cft) + return ftCurrentSortOrder==SortByStartTime){ + if (tStartTime < c.tStartTime) + return true; + else if (tStartTime > c.tStartTime) + return false; + } + else if (oe->CurrentSortOrder == ClassPoints) { + if (Class != c.Class) + return Class->tSortIndex < c.Class->tSortIndex; + else if (tDuplicateLeg != c.tDuplicateLeg) + return tDuplicateLeg < c.tDuplicateLeg; + else if (tStatus != c.tStatus) + return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus]; + else { + if (tStatus==StatusOK) { + if (tRogainingPoints != c.tRogainingPoints) + return tRogainingPoints > c.tRogainingPoints; + int t=getRunningTime(); + int ct=c.getRunningTime(); + if (t != ct) + return t < ct; + } + } + } + else if (oe->CurrentSortOrder==ClassTotalResult) { + if (Class != c.Class) + return Class->tSortIndex < c.Class->tSortIndex; + else if (tDuplicateLeg != c.tDuplicateLeg) + return tDuplicateLeg < c.tDuplicateLeg; + else { + RunnerStatus s1, s2; + s1 = getTotalStatus(); + s2 = c.getTotalStatus(); + if (s1 != s2) + return s1 < s2; + else if (s1 == StatusOK) { + if (Class->getNoTiming()) { + return CompareString(LOCALE_USER_DEFAULT, 0, + tRealName.c_str(), tRealName.length(), + c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; + } + int t = getTotalRunningTime(FinishTime); + int ct = c.getTotalRunningTime(c.FinishTime); + if (t!=ct) + return t < ct; + } + } + } + else if (oe->CurrentSortOrder == CourseResult) { + const pCourse crs1 = getCourse(false); + const pCourse crs2 = c.getCourse(false); + if (crs1 != crs2) { + int id1 = crs1 ? crs1->getId() : 0; + int id2 = crs2 ? crs2->getId() : 0; + return id1 < id2; + } + else if (tStatus != c.tStatus) + return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus]; + else { + if (tStatus==StatusOK) { + + int s = getNumShortening(); + int cs = c.getNumShortening(); + if (s != cs) + return s < cs; + + int t=getRunningTime(); + int ct=c.getRunningTime(); + if (t != ct) { + return tCurrentSortOrder==ClassStartTimeClub) { + if (Class != c.Class) + return Class->tSortIndex < c.Class->tSortIndex; + else if (tStartTime != c.tStartTime) { + if (tStartTime <= 0 && c.tStartTime > 0) + return false; + else if (c.tStartTime <= 0 && tStartTime > 0) + return true; + else return tStartTime < c.tStartTime; + } + else if (Club != c.Club) { + return getClub() < c.getClub(); + } + } + else if (oe->CurrentSortOrder==ClassTeamLeg) { + if (Class->Id != c.Class->Id) + return Class->tSortIndex < c.Class->tSortIndex; + else if (tInTeam != c.tInTeam) { + if (tInTeam == 0) + return true; + else if (c.tInTeam == 0) + return false; + if (tInTeam->StartNo != c.tInTeam->StartNo) + return tInTeam->StartNo < c.tInTeam->StartNo; + else + return tInTeam->sName < c.tInTeam->sName; + } + else if (tInTeam && tLeg != c.tLeg) + return tLeg < c.tLeg; + else if (tStartTime != c.tStartTime) { + if (tStartTime <= 0 && c.tStartTime > 0) + return false; + else if (c.tStartTime <= 0 && tStartTime > 0) + return true; + else return tStartTime < c.tStartTime; + } + else { + const string &b1 = getBib(); + const string &b2 = c.getBib(); + if (StartNo != c.StartNo && b1 != b2) + return StartNo < c.StartNo; + } + } + + return CompareString(LOCALE_USER_DEFAULT, 0, + tRealName.c_str(), tRealName.length(), + c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; + +} + +void oAbstractRunner::setClub(const string &Name) +{ + pClub pc=Club; + Club = Name.empty() ? 0 : oe->getClubCreate(0, Name); + if (pc != Club) { + updateChanged(); + if (Class) { + // Vacant clubs have special logic + Class->tResultInfo.clear(); + } + } +} + +pClub oAbstractRunner::setClubId(int clubId) +{ + pClub pc=Club; + Club = oe->getClub(clubId); + if (pc != Club) { + updateChanged(); + if (Class) { + // Vacant clubs have special logic + Class->tResultInfo.clear(); + } + } + return Club; +} + +void oRunner::setClub(const string &Name) +{ + if (tParentRunner) + tParentRunner->setClub(Name); + else { + oAbstractRunner::setClub(Name); + + for (size_t k=0;kClub!=Club) { + multiRunner[k]->Club = Club; + multiRunner[k]->updateChanged(); + } + } +} + +pClub oRunner::setClubId(int clubId) +{ + if (tParentRunner) + tParentRunner->setClubId(clubId); + else { + oAbstractRunner::setClubId(clubId); + + for (size_t k=0;kClub!=Club) { + multiRunner[k]->Club = Club; + multiRunner[k]->updateChanged(); + } + } + return Club; +} + + +void oAbstractRunner::setStartNo(int no, bool tmpOnly) { + if (tmpOnly) { + tmpStore.startNo = no; + return; + } + + if (no!=StartNo) { + if (oe) + oe->bibStartNoToRunnerTeam.clear(); + StartNo=no; + updateChanged(); + } +} + +void oRunner::setStartNo(int no, bool tmpOnly) +{ + if (tParentRunner) + tParentRunner->setStartNo(no, tmpOnly); + else { + oAbstractRunner::setStartNo(no, tmpOnly); + + for (size_t k=0;koAbstractRunner::setStartNo(no, tmpOnly); + } +} + +int oRunner::getPlace() const +{ + return tPlace; +} + +int oRunner::getCoursePlace() const +{ + return tCoursePlace; +} + + +int oRunner::getTotalPlace() const +{ + if (tInTeam) + return tInTeam->getLegPlace(tLeg, true); + else + return tTotalPlace; +} + +string oAbstractRunner::getPlaceS() const +{ + char bf[16]; + int p=getPlace(); + if (p>0 && p<10000){ + _itoa_s(p, bf, 16, 10); + return bf; + } + else return _EmptyString; +} + +string oAbstractRunner::getPrintPlaceS(bool withDot) const +{ + char bf[16]; + int p=getPlace(); + if (p>0 && p<10000){ + if (withDot) { + _itoa_s(p, bf, 16, 10); + return string(bf)+"."; + } + else + return itos(p); + } + else return _EmptyString; +} + +string oAbstractRunner::getTotalPlaceS() const +{ + char bf[16]; + int p=getTotalPlace(); + if (p>0 && p<10000){ + _itoa_s(p, bf, 16, 10); + return bf; + } + else return _EmptyString; +} + +string oAbstractRunner::getPrintTotalPlaceS(bool withDot) const +{ + char bf[16]; + int p=getTotalPlace(); + if (p>0 && p<10000){ + if (withDot) { + _itoa_s(p, bf, 16, 10); + return string(bf)+"."; + } + else + return itos(p); + } + else return _EmptyString; +} +string oRunner::getGivenName() const +{ + return ::getGivenName(sName); +} + +string oRunner::getFamilyName() const +{ + return ::getFamilyName(sName); +} + +void oRunner::setCardNo(int cno, bool matchCard, bool updateFromDatabase) +{ + if (cno!=CardNo){ + int oldNo = CardNo; + CardNo=cno; + + oFreePunch::rehashPunches(*oe, oldNo, 0); + oFreePunch::rehashPunches(*oe, CardNo, 0); + + if (matchCard && !Card) { + pCard c=oe->getCardByNumber(cno); + + if (c && !c->tOwner) { + vector mp; + addPunches(c, mp); + } + } + + if (!updateFromDatabase) + updateChanged(); + } +} + +int oRunner::setCard(int cardId) +{ + pCard c=cardId ? oe->getCard(cardId) : 0; + int oldId=0; + + if (Card!=c) { + if (Card) { + oldId=Card->getId(); + Card->tOwner=0; + } + if (c) { + if (c->tOwner) { + pRunner otherR=c->tOwner; + assert(otherR!=this); + otherR->Card=0; + otherR->updateChanged(); + otherR->setStatus(StatusUnknown, true, false); + otherR->synchronize(true); + } + c->tOwner=this; + CardNo=c->cardNo; + } + Card=c; + vector mp; + evaluateCard(true, mp); + updateChanged(); + synchronize(true); + } + return oldId; +} + +void oAbstractRunner::setName(const string &n, bool manualUpdate) +{ + string tn = trim(n); + if (tn.empty()) + throw std::exception("Tomt namn är inte tillåtet."); + if (tn != sName){ + sName.swap(tn); + if (manualUpdate) + setFlag(FlagUpdateName, true); + updateChanged(); + } +} + +void oRunner::setName(const string &in, bool manualUpdate) +{ + string n = trim(in); + + if (n.empty()) + throw std::exception("Tomt namn är inte tillåtet."); + for (size_t k = 0; k < n.length(); k++) { + if (BYTE(n[k]) == BYTE(160)) + n[k] = ' '; + } + if (n.length() <= 4 || n == lang.tl("N.N.")) + manualUpdate = false; // Never consider default names manual + + if (tParentRunner) + tParentRunner->setName(n, manualUpdate); + else { + string oldName = sName; + string oldRealName = tRealName; + string newRealName; + getRealName(n, newRealName); + if (newRealName != tRealName || n != sName) { + sName = n; + tRealName = newRealName; + + if (manualUpdate) + setFlag(FlagUpdateName, true); + + updateChanged(); + } + + for (size_t k=0;ksName) { + multiRunner[k]->sName = n; + multiRunner[k]->tRealName = tRealName; + multiRunner[k]->updateChanged(); + } + } + if (tInTeam && Class && Class->isSingleRunnerMultiStage()) { + if (tInTeam->sName == oldName || tInTeam->sName == oldRealName) + tInTeam->setName(tRealName, manualUpdate); + } + } +} + +const string &oRunner::getName() const { + return tRealName; +} + +const string &oRunner::getNameLastFirst() const { + if (sName.find_first_of(',') != sName.npos) + return sName; // Already "Fiske, Eric" + if (sName.find_first_of(' ') == sName.npos) + return sName; // No space "Vacant", "Eric" + + string &res = StringCache::getInstance().get(); + res = getFamilyName() + ", " + getGivenName(); + return res; +} + +void oRunner::getRealName(const string &input, string &output) { + size_t comma = input.find_first_of(','); + if (comma == string::npos) + output = input; + else + output = trim(input.substr(comma+1) + " " + input.substr(0, comma)); +} + +bool oAbstractRunner::setStatus(RunnerStatus st, bool updateSource, bool tmpOnly, bool recalculate) { + assert(!(updateSource && tmpOnly)); + if (tmpOnly) { + tmpStore.status = st; + return false; + } + bool ch = false; + if (tStatus!=st) { + ch = true; + tStatus=st; + + if (Class) { + Class->clearCache(recalculate); + } + } + + if (st != status) { + status = st; + if (updateSource) + updateChanged(); + else + changedObject(); + } + + return ch; +} + +int oAbstractRunner::getPrelRunningTime() const +{ + if (FinishTime>0 && tStatus!=StatusDNS && tStatus!=StatusDNF && tStatus!=StatusNotCompetiting) + return getRunningTime(); + else if (tStatus==StatusUnknown) + return oe->getComputerTime()-tStartTime; + else return 0; +} + +string oAbstractRunner::getPrelRunningTimeS() const +{ + int rt=getPrelRunningTime(); + return formatTime(rt); +} + +oDataContainer &oRunner::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = 0; + return *oe->oRunnerData; +} + +void oEvent::getRunners(int classId, int courseId, vector &r, bool sort) { + if (sort) { + synchronizeList(oLRunnerId); + sortRunners(SortByName); + } + r.clear(); + if (Classes.size() > 0) + r.reserve((Runners.size()*min(Classes.size(), 4)) / Classes.size()); + + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + if (courseId > 0) { + pCourse pc = it->getCourse(false); + if (pc == 0 || pc->getId() != courseId) + continue; + } + + if (classId <= 0 || it->getClassId() == classId) + r.push_back(&*it); + } +} + +void oEvent::getRunnersByCard(int cardNo, vector &r) { + synchronizeList(oLRunnerId); + sortRunners(SortByName); + r.clear(); + + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->getCardNo() == cardNo) + r.push_back(&*it); + } +} + + +pRunner oEvent::getRunner(int Id, int stage) const +{ + pRunner value; + + if (runnerById.lookup(Id, value) && value) { + if (value->isRemoved()) + return 0; + assert(value->Id == Id); + if (stage==0) + return value; + else if (unsigned(stage)<=value->multiRunner.size()) + return value->multiRunner[stage-1]; + } + return 0; +} + +pRunner oRunner::nextNeedReadout() const { + if (tInTeam) { + // For a runner in a team, first the team for the card + for (size_t k = 0; k < tInTeam->Runners.size(); k++) { + pRunner tr = tInTeam->Runners[k]; + if (tr && tr->CardNo == CardNo && !tr->Card && !tr->statusOK()) + return tr; + } + } + + if (!Card || Card->cardNo!=CardNo || Card->isConstructedFromPunches()) //-1 means card constructed from punches + return pRunner(this); + + for (size_t k=0;kCard || + multiRunner[k]->Card->cardNo!=CardNo)) + return multiRunner[k]; + } + return 0; +} + +void oEvent::setupCardHash(bool clear) { + if (clear) { + cardHash.clear(); + } + else { + assert(cardHash.empty()); + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + if (it->CardNo != 0) + cardHash.insert(make_pair(it->CardNo, &*it)); + } + } +} + +typedef stdext::hash_multimap::const_iterator hashConstIter; + +pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, bool ignoreRunnersWithNoStart) const +{ + oRunnerList::const_iterator it; + vector cand; + bool forceRet = false; + if (!onlyWithNoCard && !cardHash.empty()) { + forceRet = true; + pair range = cardHash.equal_range(cardNo); + if (range.first != range.second) { + hashConstIter t = range.first; + ++t; + if (t == range.second) { + pRunner r = range.first->second; + assert(r->getCardNo() == cardNo); + if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS) + return 0; + if (r->getStatus() == StatusNotCompetiting) + return 0; + return r; // Only one runner with this card + } + } + + for (hashConstIter it = range.first; it != range.second; ++it) { + pRunner r = it->second; + assert(r->getCardNo() == cardNo); + if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS) + continue; + if (r->getStatus() == StatusNotCompetiting) + continue; + if (!r->isRemoved()) + cand.push_back(r); + } + } + else { + if (time <= 0) { //No time specified. Card readout search + //First try runners with no card read or a different card read. + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + if (ignoreRunnersWithNoStart && it->getStatus() == StatusDNS) + continue; + if (it->getStatus() == StatusNotCompetiting) + continue; + + pRunner ret; + if (it->CardNo==cardNo && (ret = it->nextNeedReadout()) != 0) + return ret; + } + } + else { + for (it=Runners.begin(); it != Runners.end(); ++it) { + pRunner r = pRunner(&*it); + if (r->CardNo != cardNo || r->isRemoved()) + continue; + if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS) + continue; + if (r->getStatus() == StatusNotCompetiting) + continue; + cand.push_back(r); + } + } + } + pRunner bestR = 0; + const int K = 3600*24; + int dist = 10*K; + for (size_t k = 0; k < cand.size(); k++) { + pRunner r = cand[k]; + if (time <= 0) + return r; // No time specified. + //int start = r->getStartTime(); + //int finish = r->getFinishTime(); + int start = r->getStartTime(); + int finish = r->getFinishTime(); + if (r->getCard()) { + pair cc = r->getCard()->getTimeRange(); + if (cc.first > 0) + start = min(start, cc.first); + if (cc.second > 0) + finish = max(finish, cc.second); + } + start = max(0, start - 3 * 60); // Allow some extra time before start + + if (start > 0 && finish > 0 && time >= start && time <= finish) + return r; + int d = 3*K; + if (start > 0 && finish > 0 && start finish) + d += K + (time-finish); + } + else { + if (start > 0) { + if (time < start) + d = K + start-time; + else + d = time - start; + } + if (finish > 0) { + if (time > finish) + d += K + time - finish; + } + } + if (d < dist) { + bestR = r; + dist = d; + } + } + + if (bestR != 0 || forceRet) + return bestR; + + if (!onlyWithNoCard) { + //Then try all runners. + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (ignoreRunnersWithNoStart && it->getStatus() == StatusDNS) + continue; + if (it->getStatus() == StatusNotCompetiting) + continue; + if (!it->isRemoved() && it->CardNo==cardNo) { + pRunner r = it->nextNeedReadout(); + return r ? r : pRunner(&*it); + } + } + } + + return 0; +} + +void oEvent::getRunnersByCardNo(int cardNo, bool ignoreRunnersWithNoStart, bool skipDuplicates, vector &out) const { + out.clear(); + if (!cardHash.empty()) { + pair range = cardHash.equal_range(cardNo); + + for (hashConstIter it = range.first; it != range.second; ++it) { + pRunner r = it->second; + assert(r->getCardNo() == cardNo); + if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS) + continue; + if (skipDuplicates && r->getRaceNo() != 0) + continue; + if (r->getStatus() == StatusNotCompetiting) + continue; + if (!r->isRemoved()) + out.push_back(r); + } + } + else { + for (oRunnerList::const_iterator it=Runners.begin(); it != Runners.end(); ++it) { + if (it->CardNo != cardNo) + continue; + if (ignoreRunnersWithNoStart && it->getStatus() == StatusDNS) + continue; + if (it->getStatus() == StatusNotCompetiting) + continue; + if (skipDuplicates && it->getRaceNo() != 0) + continue; + if (!it->isRemoved()) + out.push_back(pRunner(&*it)); + } + } +} + +int oRunner::getRaceIdentifier() const { + if (tParentRunner) + return tParentRunner->getRaceIdentifier();// A unique person has a unique race identifier, even if the race is "split" into several + + int stored = getDCI().getInt("RaceId"); + if (stored != 0) + return stored; + + if (!tInTeam) + return 1000000 + (Id&0xFFFFFFF) * 2;//Even + else + return 1000000 * (tLeg+1) + (tInTeam->Id & 0xFFFFFFF) * 2 + 1;//Odd +} + +static int getEncodedBib(const string &bib) { + int enc = 0; + for (size_t j = 0; j < bib.length(); j++) { + int x = toupper(bib[j])-32; + if (x<0) + return 0; // Not a valid bib + enc = enc * 97 - x; + } + return enc; +} + +int oAbstractRunner::getEncodedBib() const { + return ::getEncodedBib(getBib()); +} + + +typedef multimap::iterator BSRTIterator; + +pRunner oEvent::getRunnerByBibOrStartNo(const string &bib, bool findWithoutCardNo) const { + if (bib.empty() || bib == "0") + return 0; + + if (bibStartNoToRunnerTeam.empty()) { + for (oTeamList::const_iterator tit = Teams.begin(); tit != Teams.end(); ++tit) { + const oTeam &t=*tit; + if (t.skip()) + continue; + + int sno = t.getStartNo(); + if (sno != 0) + bibStartNoToRunnerTeam.insert(make_pair(sno, (oAbstractRunner *)&t)); + int enc = t.getEncodedBib(); + if (enc != 0) + bibStartNoToRunnerTeam.insert(make_pair(enc, (oAbstractRunner *)&t)); + } + + for (oRunnerList::const_iterator it=Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + const oRunner &t=*it; + + int sno = t.getStartNo(); + if (sno != 0) + bibStartNoToRunnerTeam.insert(make_pair(sno, (oAbstractRunner *)&t)); + int enc = t.getEncodedBib(); + if (enc != 0) + bibStartNoToRunnerTeam.insert(make_pair(enc, (oAbstractRunner *)&t)); + } + } + + int sno = atoi(bib.c_str()); + + pair res; + if (sno > 0) { + // Require that a bib starts with numbers + int bibenc = getEncodedBib(bib); + res = bibStartNoToRunnerTeam.equal_range(bibenc); + if (res.first == res.second) + res = bibStartNoToRunnerTeam.equal_range(sno); // Try startno instead + + for(BSRTIterator it = res.first; it != res.second; ++it) { + oAbstractRunner *pa = it->second; + if (pa->isRemoved()) + continue; + + if (typeid(*pa)==typeid(oRunner)) { + oRunner &r = dynamic_cast(*pa); + if (r.getStartNo()==sno || stringMatch(r.getBib(), bib)) { + if (findWithoutCardNo) { + if (r.getCardNo() == 0 && r.needNoCard() == false) + return &r; + } + else { + if (r.getNumMulti()==0 || r.tStatus == StatusUnknown) + return &r; + else { + for(int race = 0; race < r.getNumMulti(); race++) { + pRunner r2 = r.getMultiRunner(race); + if (r2 && r2->tStatus == StatusUnknown) + return r2; + } + return &r; + } + } + } + } + else { + oTeam &t = dynamic_cast(*pa); + if (t.getStartNo()==sno || stringMatch(t.getBib(), bib)) { + if (!findWithoutCardNo) { + for (int leg=0; leggetCardNo() > 0 && t.Runners[leg]->getStatus()==StatusUnknown) + return t.Runners[leg]; + } + } + else { + for (int leg=0; leggetCardNo() == 0 && t.Runners[leg]->needNoCard() == false) + return t.Runners[leg]; + } + } + } + } + } + } + return 0; +} + +pRunner oEvent::getRunnerByName(const string &pname, const string &pclub) const +{ + oRunnerList::const_iterator it; + vector cnd; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->skip() && (it->sName==pname || it->tRealName==pname)) { + if (pclub.empty() || pclub==it->getClub()) + cnd.push_back(pRunner(&*it)); + } + } + + if (cnd.size() == 1) + return cnd[0]; // Only return if uniquely defined. + + return 0; +} + +void oEvent::fillRunners(gdioutput &gdi, const string &id, bool longName, int filter) +{ + vector< pair > d; + oe->fillRunners(d, longName, filter, stdext::hash_set()); + gdi.addItem(id, d); +} + +const vector< pair > &oEvent::fillRunners(vector< pair > &out, + bool longName, int filter, + const stdext::hash_set &personFilter) +{ + const bool showAll = (filter & RunnerFilterShowAll) == RunnerFilterShowAll; + const bool noResult = (filter & RunnerFilterOnlyNoResult) == RunnerFilterOnlyNoResult; + const bool withResult = (filter & RunnerFilterWithResult) == RunnerFilterWithResult; + const bool compact = (filter & RunnerCompactMode) == RunnerCompactMode; + + synchronizeList(oLRunnerId); + oRunnerList::iterator it; + int lVacId = getVacantClub(); + if (getNameMode() == LastFirst) + CurrentSortOrder = SortByLastName; + else + CurrentSortOrder = SortByName; + Runners.sort(); + out.clear(); + if (personFilter.empty()) + out.reserve(Runners.size()); + else + out.reserve(personFilter.size()); + + char bf[512]; + const bool usePersonFilter = !personFilter.empty(); + + if (longName) { + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (noResult && (it->Card || it->FinishTime>0)) + continue; + if (withResult && !it->Card && it->FinishTime == 0) + continue; + if (usePersonFilter && personFilter.count(it->Id) == 0) + continue; + if (!it->skip() || (showAll && !it->isRemoved())) { + if (compact) { + sprintf_s(bf, "%s, %s (%s)", it->getNameAndRace(true).c_str(), + it->getClub().c_str(), + it->getClass().c_str()); + + } else { + sprintf_s(bf, "%s\t%s\t%s", it->getNameAndRace(true).c_str(), + it->getClass().c_str(), + it->getClub().c_str()); + } + out.push_back(make_pair(bf, it->Id)); + } + } + } + else { + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (noResult && (it->Card || it->FinishTime>0)) + continue; + if (withResult && !it->Card && it->FinishTime == 0) + continue; + if (usePersonFilter && personFilter.count(it->Id) == 0) + continue; + + if (!it->skip() || (showAll && !it->isRemoved())) { + if ( it->getClubId() != lVacId ) + out.push_back(make_pair(it->getUIName(), it->Id)); + else { + sprintf_s(bf, "%s (%s)", it->getUIName().c_str(), it->getClass().c_str()); + out.push_back(make_pair(bf, it->Id)); + } + } + } + } + return out; +} + +void oRunner::resetPersonalData() +{ + oDataInterface di = getDI(); + di.setInt("BirthYear", 0); + di.setString("Nationality", ""); + di.setString("Country", ""); + di.setInt64("ExtId", 0); + //getDI().initData(); +} + +string oRunner::getNameAndRace(bool userInterface) const +{ + if (tDuplicateLeg>0 || multiRunner.size()>0) { + char bf[16]; + sprintf_s(bf, " (%d)", getRaceNo()+1); + if (userInterface) + return getUIName() + bf; + return getName()+bf; + } + else if (userInterface) + return getUIName(); + else return getName(); +} + +pRunner oRunner::getMultiRunner(int race) const +{ + if (race==0) { + if (!tParentRunner) + return pRunner(this); + else return tParentRunner; + } + + const vector &mr = tParentRunner ? tParentRunner->multiRunner : multiRunner; + + if (unsigned(race-1)>=mr.size()) { + assert(tParentRunner); + return 0; + } + + return mr[race-1]; +} + +void oRunner::createMultiRunner(bool createMaster, bool sync) +{ + if (tDuplicateLeg) + return; //Never allow chains. + + if (multiRunnerId.size()>0) { + multiRunner.resize(multiRunnerId.size() - 1); + for (size_t k=0;kgetRunner(multiRunnerId[k], 0); + if (multiRunner[k]) { + if (multiRunner[k]->multiRunnerId.size() > 1 || !multiRunner[k]->multiRunner.empty()) + multiRunner[k]->markForCorrection(); + + multiRunner[k]->multiRunner.clear(); //Do not allow chains + multiRunner[k]->multiRunnerId.clear(); + multiRunner[k]->tDuplicateLeg = k+1; + multiRunner[k]->tParentRunner = this; + multiRunner[k]->CardNo=0; + + if (multiRunner[k]->Id != multiRunnerId[k]) + markForCorrection(); + } + else if (multiRunnerId[k]>0) + markForCorrection(); + + assert(multiRunner[k]); + } + multiRunnerId.clear(); + } + + if (!Class || !createMaster) + return; + + int ndup=0; + + if (!tInTeam) + ndup=Class->getNumMultiRunners(0); + else + ndup=Class->getNumMultiRunners(tLeg); + + bool update = false; + + vector toRemove; + + for (size_t k = ndup-1; kgetStatus()==StatusUnknown) { + toRemove.push_back(multiRunner[k]->getId()); + multiRunner[k]->tParentRunner = 0; + if (multiRunner[k]->tInTeam && size_t(multiRunner[k]->tLeg)tInTeam->Runners.size()) { + if (multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg]==multiRunner[k]) + multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] = 0; + } + } + } + + multiRunner.resize(ndup-1); + for(int k=1;kaddRunner(sName, getClubId(), + getClassId(), 0, 0, false); + multiRunner[k-1]->tDuplicateLeg=k; + multiRunner[k-1]->tParentRunner=this; + + if (sync) + multiRunner[k-1]->synchronize(); + } + } + if (update) + updateChanged(); + + if (sync) { + synchronize(true); + oe->removeRunner(toRemove); + } +} + +pRunner oRunner::getPredecessor() const +{ + if (!tParentRunner || unsigned(tDuplicateLeg-1)>=16) + return 0; + + if (tDuplicateLeg==1) + return tParentRunner; + else + return tParentRunner->multiRunner[tDuplicateLeg-2]; +} + +bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) { + createMultiRunner(false, sync); + tLeg = -1; + tLegEquClass = 0; + tUseStartPunch=true; + if (tInTeam) + tInTeam->apply(sync, this, setTmpOnly); + else { + if (Class && Class->hasMultiCourse()) { + pClass pc=Class; + StartTypes st=pc->getStartType(tDuplicateLeg); + if (st==STTime) { + pCourse crs = getCourse(false); + int startType = crs ? crs->getStartPunchType() : oPunch::PunchStart; + if (!Card || Card->getPunchByType(startType) == 0 || !pc->hasFreeStart()) { + setStartTime(pc->getStartData(tDuplicateLeg), false, setTmpOnly); + tUseStartPunch = false; + } + } + else if (st==STChange) { + pRunner r=getPredecessor(); + int lastStart=0; + if (r && r->FinishTime>0) + lastStart = r->FinishTime; + + int restart=pc->getRestartTime(tDuplicateLeg); + int rope=pc->getRopeTime(tDuplicateLeg); + + if (restart && rope && (lastStart>rope || lastStart==0)) + lastStart=restart; //Runner in restart + + setStartTime(lastStart, false, setTmpOnly); + tUseStartPunch=false; + } + else if (st==STHunting) { + pRunner r=getPredecessor(); + int lastStart=0; + + if (r && r->FinishTime>0 && r->statusOK()) { + int rt=r->getRaceRunningTime(tDuplicateLeg-1); + int timeAfter=rt-pc->getTotalLegLeaderTime(r->tDuplicateLeg, true); + if (rt>0 && timeAfter>=0) + lastStart=pc->getStartData(tDuplicateLeg)+timeAfter; + } + int restart=pc->getRestartTime(tDuplicateLeg); + int rope=pc->getRopeTime(tDuplicateLeg); + + if (restart && rope && (lastStart>rope || lastStart==0)) + lastStart=restart; //Runner in restart + + setStartTime(lastStart, false, setTmpOnly); + tUseStartPunch=false; + } + } + } + + if (tLeg==-1) { + tLeg=0; + tInTeam=0; + return false; + } + else return true; +} + +void oRunner::cloneStartTime(const pRunner r) { + if (tParentRunner) + tParentRunner->cloneStartTime(r); + else { + setStartTime(r->getStartTime(), true, false); + + for (size_t k=0; k < min(multiRunner.size(), r->multiRunner.size()); k++) { + if (multiRunner[k]!=0 && r->multiRunner[k]!=0) + multiRunner[k]->setStartTime(r->multiRunner[k]->getStartTime(), true, false); + } + apply(false, 0, false); + } +} + +void oRunner::cloneData(const pRunner r) { + if (tParentRunner) + tParentRunner->cloneData(r); + else { + size_t t = sizeof(oData); + memcpy(oData, r->oData, t); + } +} + + +Table *oEvent::getRunnersTB()//Table mode +{ + if (tables.count("runner") == 0) { + Table *table=new Table(this, 20, "Deltagare", "runners"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 200, false); + table->addColumn("Klass", 120, false); + table->addColumn("Bana", 120, false); + + table->addColumn("Klubb", 120, false); + table->addColumn("Lag", 120, false); + table->addColumn("Sträcka", 70, true); + + table->addColumn("SI", 90, true, false); + + table->addColumn("Start", 70, false, true); + table->addColumn("Mål", 70, false, true); + table->addColumn("Status", 70, false); + table->addColumn("Tid", 70, false, true); + table->addColumn("Plac.", 70, true, true); + table->addColumn("Start nr.", 70, true, false); + + oe->oRunnerData->buildTableCol(table); + + table->addColumn("Tid in", 70, false, true); + table->addColumn("Status in", 70, false, true); + table->addColumn("Poäng in", 70, true); + table->addColumn("Placering in", 70, true); + + tables["runner"] = table; + table->addOwnership(); + } + tables["runner"]->update(); + return tables["runner"]; +} + +void oEvent::generateRunnerTableData(Table &table, oRunner *addRunner) +{ + if (addRunner) { + addRunner->addTableRow(table); + return; + } + + synchronizeList(oLRunnerId); + oRunnerList::iterator it; + table.reserve(Runners.size()); + for (it=Runners.begin(); it != Runners.end(); ++it){ + if (!it->skip()){ + it->addTableRow(table); + } + } +} + +const string &oRunner::getUIName() const { + oEvent::NameMode nameMode = oe->getNameMode(); + + switch (nameMode) { + case oEvent::Raw: + return getNameRaw(); + case oEvent::LastFirst: + return getNameLastFirst(); + default: + return getName(); + } +} + + +void oRunner::addTableRow(Table &table) const +{ + oRunner &it = *pRunner(this); + table.addRow(getId(), &it); + + int row = 0; + table.set(row++, it, TID_ID, itos(getId()), false); + table.set(row++, it, TID_MODIFIED, getTimeStamp(), false); + + table.set(row++, it, TID_RUNNER, getUIName(), true); + + table.set(row++, it, TID_CLASSNAME, getClass(), true, cellSelection); + table.set(row++, it, TID_COURSE, getCourseName(), true, cellSelection); + table.set(row++, it, TID_CLUB, getClub(), true, cellCombo); + + table.set(row++, it, TID_TEAM, tInTeam ? tInTeam->getName() : "", false); + table.set(row++, it, TID_LEG, tInTeam ? itos(tLeg+1) : "" , false); + + int cno = getCardNo(); + table.set(row++, it, TID_CARD, cno>0 ? itos(cno) : "", true); + + table.set(row++, it, TID_START, getStartTimeS(), true); + table.set(row++, it, TID_FINISH, getFinishTimeS(), true); + table.set(row++, it, TID_STATUS, getStatusS(), true, cellSelection); + table.set(row++, it, TID_RUNNINGTIME, getRunningTimeS(), false); + + table.set(row++, it, TID_PLACE, getPlaceS(), false); + table.set(row++, it, TID_STARTNO, itos(getStartNo()), true); + + row = oe->oRunnerData->fillTableCol(it, table, true); + + table.set(row++, it, TID_INPUTTIME, getInputTimeS(), true); + table.set(row++, it, TID_INPUTSTATUS, getInputStatusS(), true, cellSelection); + table.set(row++, it, TID_INPUTPOINTS, itos(inputPoints), true); + table.set(row++, it, TID_INPUTPLACE, itos(inputPlace), true); +} + +bool oRunner::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + int t,s; + vector mp; + synchronize(false); + + if (id>1000) { + return oe->oRunnerData->inputData(this, id, input, + inputId, output, noUpdate); + } + switch(id) { + case TID_CARD: + setCardNo(atoi(input.c_str()), true); + synchronizeAll(); + output = itos(getCardNo()); + return true; + case TID_RUNNER: + if (trim(input).empty()) + throw std::exception("Tomt namn inte tillåtet."); + + if (sName != input && tRealName != input) { + updateFromDB(input, getClubId(), getClassId(), getCardNo(), getBirthYear()); + setName(input, true); + synchronizeAll(); + } + output=getName(); + return true; + break; + + case TID_START: + setStartTimeS(input); + t=getStartTime(); + evaluateCard(true, mp); + s=getStartTime(); + if (s!=t) + throw std::exception("Starttiden är definerad genom klassen eller löparens startstämpling."); + synchronize(true); + output=getStartTimeS(); + return true; + break; + + case TID_FINISH: + setFinishTimeS(input); + t=getFinishTime(); + evaluateCard(true, mp); + s=getFinishTime(); + if (s!=t) + throw std::exception("För att ändra måltiden måste löparens målstämplingstid ändras."); + synchronize(true); + output=getStartTimeS(); + return true; + break; + + case TID_COURSE: + setCourseId(inputId); + synchronize(true); + output = getCourseName(); + break; + + case TID_CLUB: + { + pClub pc = 0; + if (inputId > 0) + pc = oe->getClub(inputId); + else + pc = oe->getClubCreate(0, input); + + updateFromDB(getName(), pc ? pc->getId():0, getClassId(), getCardNo(), getBirthYear()); + + setClub(pc ? pc->getName() : ""); + synchronize(true); + output = getClub(); + } + break; + + case TID_CLASSNAME: + setClassId(inputId, true); + synchronize(true); + output = getClass(); + break; + + case TID_STATUS: { + setStatus(RunnerStatus(inputId), true, false); + int s = getStatus(); + evaluateCard(true, mp); + if (s!=getStatus()) + throw std::exception("Status matchar inte data i löparbrickan."); + synchronize(true); + output = getStatusS(); + } + break; + + case TID_STARTNO: + setStartNo(atoi(input.c_str()), false); + synchronize(true); + output = itos(getStartNo()); + break; + + case TID_INPUTSTATUS: + setInputStatus(RunnerStatus(inputId)); + synchronize(true); + output = getInputStatusS(); + break; + + case TID_INPUTTIME: + setInputTime(input); + synchronize(true); + output = getInputTimeS(); + break; + + case TID_INPUTPOINTS: + setInputPoints(atoi(input.c_str())); + synchronize(true); + output = itos(getInputPoints()); + break; + + case TID_INPUTPLACE: + setInputPlace(atoi(input.c_str())); + synchronize(true); + output = itos(getInputPlace()); + break; + } + + return false; +} + +void oRunner::fillInput(int id, vector< pair > &out, size_t &selected) +{ + if (id>1000) { + oe->oRunnerData->fillInput(oData, id, 0, out, selected); + return; + } + + if (id==TID_COURSE) { + oe->fillCourses(out, true); + out.push_back(make_pair(lang.tl("Klassens bana"), 0)); + selected = getCourseId(); + } + else if (id==TID_CLASSNAME) { + oe->fillClasses(out, oEvent::extraNone, oEvent::filterNone); + out.push_back(make_pair(lang.tl("Ingen klass"), 0)); + selected = getClassId(); + } + else if (id==TID_CLUB) { + oe->fillClubs(out); + out.push_back(make_pair(lang.tl("Klubblös"), 0)); + selected = getClubId(); + } + else if (id==TID_STATUS) { + oe->fillStatus(out); + selected = getStatus(); + } + else if (id==TID_INPUTSTATUS) { + oe->fillStatus(out); + selected = inputStatus; + } +} + +int oRunner::getSplitTime(int controlNumber, bool normalized) const +{ + const vector &st = getSplitTimes(normalized); + if (controlNumber>0 && controlNumber == st.size() && FinishTime>0) { + int t = st.back().time; + if (t >0) + return max(FinishTime - t, -1); + } + else if ( unsigned(controlNumber)0 && st[0].time>0) ? max(st[0].time-tStartTime, -1) : -1; + else if (st[controlNumber].time>0 && st[controlNumber-1].time>0) + return max(st[controlNumber].time - st[controlNumber-1].time, -1); + else return -1; + } + return -1; +} + +int oRunner::getTimeAdjust(int controlNumber) const +{ + if ( unsigned(controlNumber)=unsigned(crs->nControls) + || unsigned(controlNumber)>=splitTimes.size()) + return -1; + + pControl ctrl=crs->Controls[controlNumber]; + if (!ctrl || !ctrl->hasName()) + return -1; + + int k=controlNumber-1; + + //Measure from previous named control + while(k>=0) { + pControl c=crs->Controls[k]; + + if (c && c->hasName()) { + if (splitTimes[controlNumber].time>0 && splitTimes[k].time>0) + return max(splitTimes[controlNumber].time - splitTimes[k].time, -1); + else return -1; + } + k--; + } + + //Measure from start time + if (splitTimes[controlNumber].time>0) + return max(splitTimes[controlNumber].time - tStartTime, -1); + + return -1; +} + +string oRunner::getSplitTimeS(int controlNumber, bool normalized) const +{ + return formatTime(getSplitTime(controlNumber, normalized)); +} + +string oRunner::getNamedSplitS(int controlNumber) const +{ + return formatTime(getNamedSplit(controlNumber)); +} + +int oRunner::getPunchTime(int controlNumber, bool normalized) const +{ + const vector &st = getSplitTimes(normalized); + + if ( unsigned(controlNumber)0) + return st[controlNumber].time-tStartTime; + else return -1; + } + else if ( unsigned(controlNumber)==st.size() ) + return FinishTime-tStartTime; + + return -1; +} + +string oRunner::getPunchTimeS(int controlNumber, bool normalized) const +{ + return formatTime(getPunchTime(controlNumber, normalized)); +} + +bool oAbstractRunner::isVacant() const +{ + return getClubId()==oe->getVacantClubIfExist(); +} + +bool oRunner::needNoCard() const { + const_cast(this)->apply(false, 0, false); + return tNeedNoCard; +} + +void oRunner::getSplitTime(int courseControlId, RunnerStatus &stat, int &rt) const +{ + rt = 0; + stat = StatusUnknown; + int cardno = tParentRunner ? tParentRunner->CardNo : CardNo; + + if (courseControlId==oPunch::PunchFinish && + FinishTime>0 && tStatus!=StatusUnknown) { + stat = tStatus; + rt = getFinishTimeAdjusted(); + } + else if (Card) { + oPunch *p=Card->getPunchById(courseControlId); + if (p && p->Time>0) { + rt=p->getAdjustedTime(); + stat = StatusOK; + } + else if (p && p->Time == -1 && statusOK()) { + rt = getFinishTimeAdjusted(); + if (rt > 0) + stat = StatusOK; + else + stat = StatusMP; + } + else + stat = courseControlId==oPunch::PunchFinish ? StatusDNF: StatusMP; + } + else if (cardno) { + oFreePunch *fp=oe->getPunch(getId(), courseControlId, cardno); + + if (fp) { + rt=fp->getAdjustedTime(); + stat=StatusOK; + } + if (courseControlId==oPunch::PunchFinish && tStatus!=StatusUnknown) + stat = tStatus; + } + rt-=tStartTime; + + if (rt<0) + rt=0; +} + +void oRunner::fillSpeakerObject(int leg, int courseControlId, int previousControlCourseId, + bool totalResult, oSpeakerObject &spk) const { + spk.status=StatusUnknown; + spk.owner=const_cast(this); + + getSplitTime(courseControlId, spk.status, spk.runningTime.time); + + if (courseControlId == oPunch::PunchFinish) + spk.timeSinceChange = oe->getComputerTime() - FinishTime; + else + spk.timeSinceChange = oe->getComputerTime() - (spk.runningTime.time + tStartTime); + + spk.bib = getBib(); + spk.names.push_back(getName()); + + spk.club=getClub(); + spk.finishStatus=totalResult ? getTotalStatus() : getStatus(); + + spk.startTimeS=getStartTimeCompact(); + spk.missingStartTime = tStartTime<=0; + + spk.isRendered=false; + + map::const_iterator mapit = priority.find(courseControlId); + if (mapit!=priority.end()) + spk.priority=mapit->second; + else + spk.priority=0; + + spk.runningTime.preliminary = getPrelRunningTime(); + + if (spk.status==StatusOK) { + spk.runningTimeLeg=spk.runningTime; + spk.runningTime.preliminary = spk.runningTime.time; + spk.runningTimeLeg.preliminary = spk.runningTime.time; + } + else { + spk.runningTimeLeg.time = spk.runningTime.preliminary; + spk.runningTimeLeg.preliminary = spk.runningTime.preliminary; + } + + if (totalResult) { + if (spk.runningTime.preliminary > 0) + spk.runningTime.preliminary += inputTime; + if (spk.runningTime.time > 0) + spk.runningTime.time += inputTime; + + if (inputStatus != StatusOK) + spk.status = spk.finishStatus; + } +} + +pRunner oEvent::findRunner(const string &s, int lastId, const stdext::hash_set &inputFilter, + stdext::hash_set &matchFilter) const +{ + matchFilter.clear(); + string trm = trim(s); + int len = trm.length(); + int sn = atoi(trm.c_str()); + char s_lc[1024]; + strcpy_s(s_lc, s.c_str()); + CharLowerBuff(s_lc, len); + + pRunner res = 0; + + if (!inputFilter.empty() && inputFilter.size() < Runners.size() / 2) { + for (stdext::hash_set::const_iterator it = inputFilter.begin(); it!= inputFilter.end(); ++it) { + int id = *it; + pRunner r = getRunner(id, 0); + if (!r) + continue; + + if (sn>0) { + if (matchNumber(r->StartNo, s_lc) || matchNumber(r->CardNo, s_lc)) { + matchFilter.insert(id); + if (res == 0) + res = r; + } + } + else { + if (filterMatchString(r->tRealName, s_lc)) { + matchFilter.insert(id); + if (res == 0) + res = r; + } + } + } + return res; + } + + oRunnerList::const_iterator itstart = Runners.begin(); + + if (lastId) { + for (; itstart != Runners.end(); ++itstart) { + if (itstart->Id==lastId) { + ++itstart; + break; + } + } + } + + oRunnerList::const_iterator it; + for (it=itstart; it != Runners.end(); ++it) { + pRunner r = pRunner(&(*it)); + if (r->skip()) + continue; + + if (sn>0) { + if (matchNumber(r->StartNo, s_lc) || matchNumber(r->CardNo, s_lc)) { + matchFilter.insert(r->Id); + if (res == 0) + res = r; + } + } + else { + if (filterMatchString(r->tRealName, s_lc)) { + matchFilter.insert(r->Id); + if (res == 0) + res = r; + } + } + } + for (it=Runners.begin(); it != itstart; ++it) { + pRunner r = pRunner(&(*it)); + if (r->skip()) + continue; + + if (sn>0) { + if (matchNumber(r->StartNo, s_lc) || matchNumber(r->CardNo, s_lc)) { + matchFilter.insert(r->Id); + if (res == 0) + res = r; + } + } + else { + if (filterMatchString(r->tRealName, s_lc)) { + matchFilter.insert(r->Id); + if (res == 0) + res = r; + } + } + } + + return res; +} + +int oRunner::getTimeAfter(int leg) const +{ + if (leg==-1) + leg=tDuplicateLeg; + + if (!Class || Class->tLeaderTime.size()<=unsigned(leg)) + return -1; + + int t=getRaceRunningTime(leg); + + if (t<=0) + return -1; + + return t-Class->getTotalLegLeaderTime(leg, true); +} + +int oRunner::getTimeAfter() const +{ + int leg=0; + if (tInTeam) + leg=tLeg; + else + leg=tDuplicateLeg; + + if (!Class || Class->tLeaderTime.size()<=unsigned(leg)) + return -1; + + int t=getRunningTime(); + + if (t<=0) + return -1; + + return t-Class->getBestLegTime(leg); +} + +int oRunner::getTimeAfterCourse() const +{ + if (!Class) + return -1; + + const pCourse crs = getCourse(false); + if (!crs) + return -1; + + int t = getRunningTime(); + + if (t<=0) + return -1; + + int bt = Class->getBestTimeCourse(crs->getId()); + + if (bt <= 0) + return -1; + + return t - bt; +} + +bool oRunner::synchronizeAll() +{ + if (tParentRunner) + tParentRunner->synchronizeAll(); + else { + synchronize(); + for (size_t k=0;ksynchronize(); + } + if (Class && Class->isSingleRunnerMultiStage()) + if (tInTeam) + tInTeam->synchronize(false); + } + return true; +} + +const string &oAbstractRunner::getBib() const +{ + return getDCI().getString("Bib"); +} + +void oRunner::setBib(const string &bib, int bibNumerical, bool updateStartNo, bool tmpOnly) { + if (tParentRunner) + tParentRunner->setBib(bib, bibNumerical, updateStartNo, tmpOnly); + else { + if (updateStartNo) + setStartNo(bibNumerical, tmpOnly); // Updates multi too. + + if (tmpOnly) { + tmpStore.bib = bib; + return; + } + if (getDI().setString("Bib", bib)) { + if (oe) + oe->bibStartNoToRunnerTeam.clear(); + } + + for (size_t k=0;kgetDI().setString("Bib", bib); + } + } + } +} + + +void oEvent::analyseDNS(vector &unknown_dns, vector &known_dns, + vector &known, vector &unknown) +{ + autoSynchronizeLists(true); + + vector stUnknown; + vector stDNS; + + for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end();++it) { + if (!it->isRemoved() && !it->needNoCard()) { + if (it->getStatus() == StatusUnknown) + stUnknown.push_back(&*it); + else if (it->getStatus() == StatusDNS) + stDNS.push_back(&*it); + } + } + + // Map cardNo -> punch + multimap punchHash; + map cardCount; + + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (!it->isRemoved() && it->getCardNo() > 0) + ++cardCount[it->getCardNo()]; + } + + typedef multimap::const_iterator TPunchIter; + for (oFreePunchList::iterator it = punches.begin(); it != punches.end(); ++it) { + punchHash.insert(make_pair(it->getCardNo(), &*it)); + } + + set knownCards; + for (oCardList::iterator it = Cards.begin(); it!=Cards.end(); ++it) { + if (it->tOwner == 0) + knownCards.insert(it->cardNo); + } + + unknown.clear(); + known.clear(); + + for (size_t k=0;kCardNo; + if (card == 0) + unknown.push_back(stUnknown[k]); + else { + bool hitCard = knownCards.count(card)==1 && cardCount[card] == 1; + if (!hitCard) { + pair res = punchHash.equal_range(card); + while (res.first != res.second) { + if (cardCount[card] == 1 || res.first->second->tRunnerId == stUnknown[k]->getId()) { + hitCard = true; + break; + } + ++res.first; + } + } + if (hitCard) + known.push_back(stUnknown[k]); + else + unknown.push_back(stUnknown[k]); //These can be given "dns" + } + } + + unknown_dns.clear(); + known_dns.clear(); + + for (size_t k=0;kCardNo; + if (card == 0) + unknown_dns.push_back(stDNS[k]); + else { + bool hitCard = knownCards.count(card)==1 && cardCount[card] == 1; + if (!hitCard) { + pair res = punchHash.equal_range(card); + while (res.first != res.second) { + if (cardCount[card] == 1 || res.first->second->tRunnerId == stDNS[k]->getId()) { + hitCard = true; + break; + } + ++res.first; + } + } + if (hitCard) + known_dns.push_back(stDNS[k]); + else + unknown_dns.push_back(stDNS[k]); + } + } +} + +static int findNextControl(const vector &ctrl, int startIndex, int id, int &offset, bool supportRogaining) +{ + vector::const_iterator it=ctrl.begin(); + int index=0; + offset = 1; + while(startIndex>0 && it!=ctrl.end()) { + int multi = (*it)->getNumMulti(); + offset += multi-1; + ++it, --startIndex, ++index; + if (it!=ctrl.end() && (*it)->isRogaining(supportRogaining)) + index--; + } + + while(it!=ctrl.end() && (*it) && (*it)->getId()!=id) { + int multi = (*it)->getNumMulti(); + offset += multi-1; + ++it, ++index; + if (it!=ctrl.end() && (*it)->isRogaining(supportRogaining)) + index--; + } + + if (it==ctrl.end()) + return -1; + else + return index; +} + +static void gotoNextLine(gdioutput &gdi, int &xcol, int &cx, int &cy, int colDeltaX, int numCol, int baseCX) { + if (++xcol < numCol) { + cx += colDeltaX; + } + else { + xcol = 0; + cy += int(gdi.getLineHeight()*1.1); + cx = baseCX; + } +} + +static void addMissingControl(bool wideFormat, gdioutput &gdi, + int &xcol, int &cx, int &cy, + int colDeltaX, int numCol, int baseCX) { + int xx = cx; + string str = MakeDash("-"); + int posy = wideFormat ? cy : cy-int(gdi.getLineHeight()*0.4); + const int endx = cx + colDeltaX - 27; + + while (xx < endx) { + gdi.addStringUT(posy, xx, fontSmall, str); + xx += 20; + } + + // Make a thin line for list format, otherwise, take a full place + if (wideFormat) { + gotoNextLine(gdi, xcol, cx, cy, colDeltaX, numCol, baseCX); + } + else + cy+=int(gdi.getLineHeight()*0.3); +} + +void oRunner::printSplits(gdioutput &gdi) const { + bool withAnalysis = (oe->getDI().getInt("Analysis") & 1) == 0; + bool withSpeed = (oe->getDI().getInt("Analysis") & 2) == 0; + bool withResult = (oe->getDI().getInt("Analysis") & 4) == 0; + const bool wideFormat = oe->getPropertyInt("WideSplitFormat", 0) == 1; + const int numCol = 4; + + if (Class && Class->getNoTiming()) { + withResult = false; + withAnalysis = false; + } + + gdiFonts head = boldText; + gdiFonts normal = fontSmall; + gdiFonts bnormal = boldSmall; + if (wideFormat) { + head = boldLarge; + normal = normalText; + bnormal = boldText; + } + else { + gdi.setCX(10); + } + gdi.fillDown(); + gdi.addStringUT(head, oe->getName()); + gdi.addStringUT(normal, oe->getDate()); + gdi.dropLine(0.5); + pCourse pc = getCourse(true); + + gdi.addStringUT(bnormal, getName() + ", " + getClass()); + gdi.addStringUT(normal, getClub()); + gdi.dropLine(0.5); + gdi.addStringUT(normal, lang.tl("Start: ") + getStartTimeS() + lang.tl(", Mål: ") + getFinishTimeS()); + string statInfo = lang.tl("Status: ") + getStatusS() + lang.tl(", Tid: ") + getRunningTimeS(); + if (withSpeed && pc && pc->getLength() > 0) { + int kmt = (getRunningTime() * 1000) / pc->getLength(); + statInfo += " (" + formatTime(kmt) + lang.tl(" min/km") + ")"; + } + if (pc && withSpeed) { + if (pc->legLengths.empty() || *max_element(pc->legLengths.begin(), pc->legLengths.end()) <= 0) + withSpeed = false; // No leg lenghts available + } + gdi.addStringUT(normal, statInfo); + + int cy = gdi.getCY()+4; + int cx = gdi.getCX(); + + int spMax = 0; + int totMax = 0; + if (pc) { + for (int n = 0; n < pc->nControls; n++) { + spMax = max(spMax, getSplitTime(n, false)); + totMax = max(totMax, getPunchTime(n, false)); + } + } + bool moreThanHour = max(totMax, getRunningTime()) >= 3600; + bool moreThanHourSplit = spMax >= 3600; + + const int c1=35; + const int c2=95 + (moreThanHourSplit ? 65 : 55); + const int c3 = c2 + 10; + const int c4 = moreThanHour ? c3+153 : c3+133; + const int c5 = withSpeed ? c4 + 80 : c4; + const int baseCX = cx; + const int colDeltaX = c5 + 32; + + char bf[256]; + int lastIndex = -1; + int adjust = 0; + int offset = 1; + + vector ctrl; + + int finishType = -1; + int startType = -1, startOffset = 0; + if (pc) { + pc->getControls(ctrl); + finishType = pc->getFinishPunchType(); + + if (pc->useFirstAsStart()) { + startType = pc->getStartPunchType(); + startOffset = -1; + } + } + + set headerPos; + set checkedIndex; + + if (Card && pc) { + bool hasRogaining = pc->hasRogaining(); + + const int cyHead = cy; + cy += int(gdi.getLineHeight()*0.9); + int xcol = 0; + int baseY = cy; + + oPunchList &p=Card->punches; + for (oPunchList::iterator it=p.begin();it!=p.end();++it) { + if (headerPos.count(cx) == 0) { + headerPos.insert(cx); + gdi.addString("", cyHead, cx, italicSmall, "Kontroll"); + gdi.addString("", cyHead, cx+c2-55, italicSmall, "Tid"); + if (withSpeed) + gdi.addString("", cyHead, cx+c5, italicSmall|textRight, "min/km"); + } + + bool any = false; + if (it->tRogainingIndex>=0) { + const pControl c = pc->getControl(it->tRogainingIndex); + string point = c ? itos(c->getRogainingPoints()) + "p." : ""; + + gdi.addStringUT(cy, cx + c1 + 10, fontSmall, point); + any = true; + + sprintf_s(bf, "%d", it->Type); + gdi.addStringUT(cy, cx, fontSmall, bf); + int st = Card->getSplitTime(getStartTime(), &*it); + + if (st>0) + gdi.addStringUT(cy, cx + c2, fontSmall|textRight, formatTime(st)); + + gdi.addStringUT(cy, cx+c3, fontSmall, it->getTime()); + + int pt = it->getAdjustedTime(); + st = getStartTime(); + if (st>0 && pt>0 && pt>st) { + string punchTime = formatTime(pt-st); + gdi.addStringUT(cy, cx+c4, fontSmall|textRight, punchTime); + } + + cy+=int(gdi.getLineHeight()*0.9); + continue; + } + + int cid = it->tMatchControlId; + string punchTime; + int sp; + int controlLegIndex = -1; + if (it->isFinish(finishType)) { + // Check if the last normal control was missing, and indicate this + for (int j = pc->getNumControls() - 1; j >= 0; j--) { + pControl ctrl = pc->getControl(j); + if (ctrl && ctrl->isSingleStatusOK()) { + if (checkedIndex.count(j) == 0) { + addMissingControl(wideFormat, gdi, xcol, cx, cy, colDeltaX, numCol, baseCX); + } + break; + } + } + + gdi.addString("", cy, cx, fontSmall, "Mål"); + sp = getSplitTime(splitTimes.size(), false); + if (sp>0) { + gdi.addStringUT(cy, cx+c2, fontSmall|textRight, formatTime(sp)); + punchTime = formatTime(getRunningTime()); + } + gdi.addStringUT(cy, cx+c3, fontSmall, oe->getAbsTime(it->Time + adjust)); + any = true; + if (!punchTime.empty()) { + gdi.addStringUT(cy, cx+c4, fontSmall|textRight, punchTime); + } + controlLegIndex = pc->getNumControls(); + } + else if (it->Type>10) { //Filter away check and start + int index = -1; + if (cid>0) + index = findNextControl(ctrl, lastIndex+1, cid, offset, hasRogaining); + if (index>=0) { + if (index > lastIndex + 1) { + addMissingControl(wideFormat, gdi, xcol, cx, cy, colDeltaX, numCol, baseCX); + + /*int xx = cx; + string str = MakeDash("-"); + int posy = wideFormat ? cy : cy-int(gdi.getLineHeight()*0.4); + const int endx = cx+c5 + 5; + + while (xx < endx) { + gdi.addStringUT(posy, xx, fontSmall, str); + xx += 20; + } + + // Make a thin line for list format, otherwise, take a full place + if (wideFormat) { + gotoNextLine(gdi, xcol, cx, cy, colDeltaX, numCol, baseCX); + } + else + cy+=int(gdi.getLineHeight()*0.3);*/ + } + lastIndex = index; + + if (it->Type == startType && (index+offset) == 1) + continue; // Skip start control + + sprintf_s(bf, "%d.", index+offset+startOffset); + gdi.addStringUT(cy, cx, fontSmall, bf); + sprintf_s(bf, "(%d)", it->Type); + gdi.addStringUT(cy, cx+c1, fontSmall, bf); + + controlLegIndex = it->tIndex; + checkedIndex.insert(controlLegIndex); + adjust = getTimeAdjust(controlLegIndex); + sp = getSplitTime(controlLegIndex, false); + if (sp>0) { + punchTime = getPunchTimeS(controlLegIndex, false); + gdi.addStringUT(cy, cx+c2, fontSmall|textRight, formatTime(sp)); + } + } + else { + if (!it->isUsed) { + gdi.addStringUT(cy, cx, fontSmall, MakeDash("-")); + } + sprintf_s(bf, "(%d)", it->Type); + gdi.addStringUT(cy, cx+c1, fontSmall, bf); + } + if (it->Time > 0) + gdi.addStringUT(cy, cx+c3, fontSmall, oe->getAbsTime(it->Time + adjust)); + else { + string str = MakeDash("-"); + gdi.addStringUT(cy, cx+c3, fontSmall, str); + } + + if (!punchTime.empty()) { + gdi.addStringUT(cy, cx+c4, fontSmall|textRight, punchTime); + } + any = true; + } + + if (withSpeed && controlLegIndex>=0 && size_t(controlLegIndex) < pc->legLengths.size()) { + int length = pc->legLengths[controlLegIndex]; + if (length > 0) { + int tempo=(sp*1000)/length; + gdi.addStringUT(cy, cx+c5, fontSmall|textRight, formatTime(tempo)); + } + } + + if (any) { + if (!wideFormat) { + cy+=int(gdi.getLineHeight()*0.9); + } + else { + gotoNextLine(gdi, xcol, cx, cy, colDeltaX, numCol, baseCX); + } + } + } + gdi.dropLine(); + if (wideFormat) { + for (int i = 0; i < numCol-1; i++) { + RECT rc; + rc.top = baseY; + rc.bottom = cy; + rc.left = baseCX + colDeltaX*(i+1)-10; + rc.right = rc.left + 1; + gdi.addRectangle(rc, colorBlack); + } + } + + if (withAnalysis) { + vector misses; + int last = ctrl.size(); + if (pc->useLastAsFinish()) + last--; + + for (int k = pc->useFirstAsStart() ? 1 : 0; k < last; k++) { + int missed = getMissedTime(k); + if (missed>0) { + misses.push_back(pc->getControlOrdinal(k) + "/" + formatTime(missed)); + } + } + if (misses.size()==0) { + vector rOut; + oe->getRunners(0, pc->getId(), rOut, false); + int count = 0; + for (size_t k = 0; k < rOut.size(); k++) { + if (rOut[k]->getCard()) + count++; + } + + if (count < 3) + gdi.addString("", normal, "Underlag saknas för bomanalys."); + else + gdi.addString("", normal, "Inga bommar registrerade."); + } + else { + string out = lang.tl("Tidsförluster (kontroll-tid): "); + for (size_t k = 0; k (wideFormat ? 80u : (withSpeed ? 40u : 35u))) { + gdi.addStringUT(normal, out); + out.clear(); + } + out += misses[k]; + if (k < misses.size()-1) + out += ", "; + else + out += "."; + } + gdi.addStringUT(fontSmall, out); + } + } + + if (withResult && statusOK()) { + gdi.dropLine(0.5); + oe->calculateResults(oEvent::RTClassResult); + if (hasInputData()) + oe->calculateResults(oEvent::RTTotalResult); + if (tInTeam) + oe->calculateTeamResults(tLeg, true); + + string place = oe->formatListString(lRunnerGeneralPlace, pRunner(this), "%s"); + string timestatus; + if (tInTeam || hasInputData()) { + timestatus = oe->formatListString(lRunnerGeneralTimeStatus, pRunner(this)); + if (!place.empty() && !timestatus.empty()) + timestatus = ", " + timestatus; + } + + string after = oe->formatListString(lRunnerGeneralTimeAfter, pRunner(this)); + if (!after.empty() && !(place.empty() && timestatus.empty())) + after = ", " + after; + + gdi.fillRight(); + gdi.pushX(); + if (!place.empty()) + gdi.addString("", bnormal, "Placering:"); + else + gdi.addString("", bnormal, "Resultat:"); + gdi.fillDown(); + gdi.addString("", normal, place + timestatus + after); + gdi.popX(); + } + } + gdi.dropLine(); + + vector< pair > lines; + oe->getExtraLines("SPExtra", lines); + + for (size_t k = 0; k < lines.size(); k++) { + gdi.addStringUT(lines[k].second, lines[k].first); + } + if (lines.size()>0) + gdi.dropLine(0.5); + + gdi.addString("", fontSmall, "Av MeOS: www.melin.nu/meos"); +} + + +void oRunner::printStartInfo(gdioutput &gdi) const { + gdi.setCX(10); + gdi.fillDown(); + gdi.addString("", boldText, "Startbevis X#" + oe->getName()); + gdi.addStringUT(fontSmall, oe->getDate()); + gdi.dropLine(0.5); + + string bib = getBib(); + if (!bib.empty()) + bib = bib + ": "; + + gdi.addStringUT(boldSmall, bib + getName() + ", " + getClass()); + gdi.addStringUT(fontSmall, getClub()); + gdi.dropLine(0.5); + + string startName; + if (getCourse(false)) { + startName = trim(getCourse(false)->getStart()); + if (!startName.empty()) + startName = " (" + startName + ")"; + } + if (getStartTime() > 0) + gdi.addStringUT(fontSmall, lang.tl("Start: ") + getStartTimeS() + startName); + else + gdi.addStringUT(fontSmall, lang.tl("Fri starttid") + startName); + + string borrowed = getDCI().getInt("CardFee") != 0 ? " (" + lang.tl("Hyrd") + ")" : ""; + + gdi.addStringUT(fontSmall, lang.tl("Bricka: ") + itos(getCardNo()) + borrowed); + + int cardFee = getDCI().getInt("CardFee"); + if (cardFee < 0) + cardFee = 0; + + int fee = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy) ? getDCI().getInt("Fee") + cardFee : 0; + + if (fee > 0) { + string info; + if (getDCI().getInt("Paid") == fee) + info = lang.tl("Betalat"); + else + info = lang.tl("Faktureras"); + + gdi.addStringUT(fontSmall, lang.tl("Anmälningsavgift: ") + itos(fee) + " (" + info + ")"); + } + + gdi.dropLine(1); + vector< pair > lines; + oe->getExtraLines("EntryExtra", lines); + + for (size_t k = 0; k < lines.size(); k++) { + gdi.addStringUT(lines[k].second, lines[k].first); + } + if (lines.size()>0) + gdi.dropLine(0.5); + + gdi.addStringUT(fontSmall, "Av MeOS " + getMeosCompectVersion() + " / www.melin.nu/meos"); +} + +vector oRunner::getRunnersOrdered() const { + if (tParentRunner) + return tParentRunner->getRunnersOrdered(); + + vector r(multiRunner.size()+1); + r[0] = (pRunner)this; + for (size_t k=0;k &r = tParentRunner->multiRunner; + + for (size_t k=0;ktParentRunner = 0; + r->tLeg = 0; + r->tLegEquClass = 0; + if (i+1==multiRunner.size()) + multiRunner.pop_back(); + + correctionNeeded = true; + r->correctionNeeded = true; + } +} + +void oEvent::updateRunnersFromDB() +{ + oRunnerList::iterator it; + if (!oe->useRunnerDb()) + return; + + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (!it->isVacant() && !it->isRemoved()) + it->updateFromDB(it->sName, it->getClubId(), it->getClassId(), it->getCardNo(), it->getBirthYear()); + } +} + +bool oRunner::updateFromDB(const string &name, int clubId, int classId, + int cardNo, int birthYear) { + if (!oe->useRunnerDb()) + return false; + + pRunner db_r = 0; + if (cardNo>0) { + db_r = oe->dbLookUpByCard(cardNo); + + if (db_r && db_r->matchName(name)) { + //setName(db_r->getName()); + //setClub(db_r->getClub()); Don't... + setExtIdentifier(db_r->getExtIdentifier()); + setBirthYear(db_r->getBirthYear()); + setSex(db_r->getSex()); + setNationality(db_r->getNationality()); + return true; + } + } + + db_r = oe->dbLookUpByName(name, clubId, classId, birthYear); + + if (db_r) { + setExtIdentifier(db_r->getExtIdentifier()); + setBirthYear(db_r->getBirthYear()); + setSex(db_r->getSex()); + setNationality(db_r->getNationality()); + return true; + } + else if (getExtIdentifier()>0) { + db_r = oe->dbLookUpById(getExtIdentifier()); + if (db_r && db_r->matchName(name)) { + setBirthYear(db_r->getBirthYear()); + setSex(db_r->getSex()); + setNationality(db_r->getNationality()); + return true; + } + // Reset external identifier + setExtIdentifier(0); + setBirthYear(0); + // Do not reset nationality and sex, + // since they are likely correct. + } + + return false; +} + +void oRunner::setSex(PersonSex sex) +{ + getDI().setString("Sex", encodeSex(sex)); +} + +PersonSex oRunner::getSex() const +{ + return interpretSex(getDCI().getString("Sex")); +} + +void oRunner::setBirthYear(int year) +{ + getDI().setInt("BirthYear", year); +} + +int oRunner::getBirthYear() const +{ + return getDCI().getInt("BirthYear"); +} + +void oAbstractRunner::setSpeakerPriority(int year) +{ + if (Class) { + oe->classChanged(Class, false); + } + getDI().setInt("Priority", year); +} + +int oAbstractRunner::getSpeakerPriority() const +{ + return getDCI().getInt("Priority"); +} + +int oRunner::getSpeakerPriority() const { + int p = oAbstractRunner::getSpeakerPriority(); + + if (tParentRunner) + p = max(p, tParentRunner->getSpeakerPriority()); + else if (tInTeam) { + p = max(p, tInTeam->getSpeakerPriority()); + } + + return p; +} + +void oRunner::setNationality(const string &nat) +{ + getDI().setString("Nationality", nat); +} + +string oRunner::getNationality() const +{ + return getDCI().getString("Nationality"); +} + +bool oRunner::matchName(const string &pname) const +{ + if (pname == sName || pname == tRealName) + return true; + + vector myNames, inNames; + + split(tRealName, " ", myNames); + split(pname, " ", inNames); + + for (size_t k = 0; k < myNames.size(); k++) + myNames[k] = canonizeName(myNames[k].c_str()); + + int nMatched = 0; + for (size_t j = 0; j < inNames.size(); j++) { + string inName = canonizeName(inNames[j].c_str()); + for (size_t k = 0; k < myNames.size(); k++) { + if (myNames[k] == inName) { + nMatched++; + + // Suppert changed last name in the most common case + if (j == 0 && k == 0 && inNames.size() == 2 && myNames.size() == 2) { + return true; + } + break; + } + } + } + + return nMatched >= min(myNames.size(), 2); +} + +bool oRunner::autoAssignBib() { + if (Class == 0 || !getBib().empty()) + return !getBib().empty(); + + int maxbib = 0; + char pattern[32]; + int noBib = 0; + int withBib = 0; + for(oRunnerList::iterator it = oe->Runners.begin(); it !=oe->Runners.end();++it) { + if (it->Class == Class) { + const string &bib = it->getBib(); + if (!bib.empty()) { + withBib++; + int ibib = oClass::extractBibPattern(bib, pattern); + maxbib = max(ibib, maxbib); + } + else + noBib++; + } + } + + if (maxbib>0 && withBib>noBib) { + char bib[32]; + sprintf_s(bib, pattern, maxbib+1); + setBib(bib, maxbib+1, true, false); + return true; + } + return false; +} + +void oRunner::getSplitAnalysis(vector &deltaTimes) const { + deltaTimes.clear(); + vector mp; + + if (splitTimes.empty() || !Class) + return; + + if (Class->tSplitRevision == tSplitRevision) + deltaTimes = tMissedTime; + + pCourse pc = getCourse(true); + if (!pc) + return; + vector reorder; + if (pc->isAdapted()) + reorder = pc->getMapToOriginalOrder(); + else { + reorder.reserve(pc->nControls+1); + for (int k = 0; k <= pc->nControls; k++) + reorder.push_back(k); + } + + int id = pc->getId(); + + if (Class->tSplitAnalysisData.count(id) == 0) + Class->calculateSplits(); + + const vector &baseLine = Class->tSplitAnalysisData[id]; + const unsigned nc = pc->getNumControls(); + + if (baseLine.size() != nc+1) + return; + + vector res(nc+1); + + double resSum = 0; + double baseSum = 0; + double bestTime = 0; + for (size_t k = 0; k <= nc; k++) { + res[k] = getSplitTime(k, false); + if (res[k] > 0) { + resSum += res[k]; + baseSum += baseLine[reorder[k]]; + } + bestTime += baseLine[reorder[k]]; + } + + deltaTimes.resize(nc+1); + + // Adjust expected time by removing mistakes + for (size_t k = 0; k <= nc; k++) { + if (res[k] > 0) { + double part = res[k]*baseSum/(resSum * bestTime); + double delta = part - baseLine[reorder[k]] / bestTime; + int deltaAbs = int(floor(delta * resSum + 0.5)); + if (res[k]-deltaAbs < baseLine[reorder[k]]) + deltaAbs = int(res[k] - baseLine[reorder[k]]); + + if (deltaAbs>0) + resSum -= deltaAbs; + } + } + + for (size_t k = 0; k <= nc; k++) { + if (res[k] > 0) { + double part = res[k]*baseSum/(resSum * bestTime); + double delta = part - baseLine[reorder[k]] / bestTime; + + int deltaAbs = int(floor(delta * resSum + 0.5)); + + if (deltaAbs > 0) { + if ( fabs(delta) > 1.0/100 && (20.0*deltaAbs)>res[k] && deltaAbs>=15) + deltaTimes[k] = deltaAbs; + + res[k] -= deltaAbs; + if (res[k] < baseLine[reorder[k]]) + res[k] = baseLine[reorder[k]]; + } + } + } + + resSum = 0; + for (size_t k = 0; k <= nc; k++) { + if (res[k] > 0) { + resSum += res[k]; + } + } + + for (size_t k = 0; k <= nc; k++) { + if (res[k] > 0) { + double part = res[k]*baseSum/(resSum * bestTime); + double delta = part - baseLine[reorder[k]] / bestTime; + int deltaAbs = int(floor(delta * resSum + 0.5)); + + if (deltaTimes[k]==0 && fabs(delta) > 1.0/100 && deltaAbs>=15) + deltaTimes[k] = deltaAbs; + } + } +} + +void oRunner::getLegPlaces(vector &places) const +{ + places.clear(); + pCourse pc = getCourse(true); + if (!pc || !Class || splitTimes.empty()) + return; + if (Class->tSplitRevision == tSplitRevision) + places = tPlaceLeg; + + int id = pc->getId(); + + if (Class->tSplitAnalysisData.count(id) == 0) + Class->calculateSplits(); + + const unsigned nc = pc->getNumControls(); + + places.resize(nc+1); + int cc = pc->getCommonControl(); + for (unsigned k = 0; k<=nc; k++) { + int to = cc; + if (kgetControl(k) ? pc->getControl(k)->getId() : 0; + int from = cc; + if (k>0) + from = pc->getControl(k-1) ? pc->getControl(k-1)->getId() : 0; + + int time = getSplitTime(k, false); + + if (time>0) + places[k] = Class->getLegPlace(from, to, time); + else + places[k] = 0; + } +} + +void oRunner::getLegTimeAfter(vector ×) const +{ + times.clear(); + if (splitTimes.empty() || !Class) + return; + if (Class->tSplitRevision == tSplitRevision) { + times = tAfterLeg; + return; + } + + pCourse pc = getCourse(false); + if (!pc) + return; + + int id = pc->getId(); + + if (Class->tCourseLegLeaderTime.count(id) == 0) + Class->calculateSplits(); + + const unsigned nc = pc->getNumControls(); + + const vector leaders = Class->tCourseLegLeaderTime[id]; + + if (leaders.size() != nc + 1) + return; + + times.resize(nc+1); + + for (unsigned k = 0; k<=nc; k++) { + int s = getSplitTime(k, true); + + if (s>0) { + times[k] = s - leaders[k]; + if (times[k]<0) + times[k] = -1; + } + else + times[k] = -1; + } + // Normalized order + const vector &reorder = getCourse(true)->getMapToOriginalOrder(); + if (!reorder.empty()) { + vector orderedTimes(times.size()); + for (size_t k = 0; k < times.size(); k++) { + orderedTimes[k] = times[reorder[k]]; + } + times.swap(orderedTimes); + } +} + +void oRunner::getLegTimeAfterAcc(vector ×) const +{ + times.clear(); + if (splitTimes.empty() || !Class || tStartTime<=0) + return; + if (Class->tSplitRevision == tSplitRevision) + times = tAfterLegAcc; + + pCourse pc = getCourse(false); //XXX Does not work for loop courses + if (!pc) + return; + + int id = pc->getId(); + + if (Class->tCourseAccLegLeaderTime.count(id) == 0) + Class->calculateSplits(); + + const unsigned nc = pc->getNumControls(); + + const vector leaders = Class->tCourseAccLegLeaderTime[id]; + const vector &sp = getSplitTimes(true); + if (leaders.size() != nc + 1) + return; + //xxx reorder output + times.resize(nc+1); + + for (unsigned k = 0; k<=nc; k++) { + int s = 0; + if (k < sp.size()) + s = sp[k].time; + else if (k==nc) + s = FinishTime; + + if (s>0) { + times[k] = s - tStartTime - leaders[k]; + if (times[k]<0) + times[k] = -1; + } + else + times[k] = -1; + } + + // Normalized order + const vector &reorder = getCourse(true)->getMapToOriginalOrder(); + if (!reorder.empty()) { + vector orderedTimes(times.size()); + for (size_t k = 0; k < times.size(); k++) { + orderedTimes[k] = times[reorder[k]]; + } + times.swap(orderedTimes); + } +} + +void oRunner::getLegPlacesAcc(vector &places) const +{ + places.clear(); + pCourse pc = getCourse(false); + if (!pc || !Class) + return; + if (splitTimes.empty() || tStartTime<=0) + return; + if (Class->tSplitRevision == tSplitRevision) { + places = tPlaceLegAcc; + return; + } + + int id = pc->getId(); + const unsigned nc = pc->getNumControls(); + const vector &sp = getSplitTimes(true); + places.resize(nc+1); + for (unsigned k = 0; k<=nc; k++) { + int s = 0; + if (k < sp.size()) + s = sp[k].time; + else if (k==nc) + s = FinishTime; + + if (s>0) { + int time = s - tStartTime; + + if (time>0) + places[k] = Class->getAccLegPlace(id, k, time); + else + places[k] = 0; + } + } + + // Normalized order + const vector &reorder = getCourse(true)->getMapToOriginalOrder(); + if (!reorder.empty()) { + vector orderedPlaces(places.size()); + for (size_t k = 0; k < places.size(); k++) { + orderedPlaces[k] = places[reorder[k]]; + } + places.swap(orderedPlaces); + } +} + +void oRunner::setupRunnerStatistics() const +{ + if (!Class) + return; + if (Class->tSplitRevision == tSplitRevision) + return; + + getSplitAnalysis(tMissedTime); + getLegPlaces(tPlaceLeg); + getLegTimeAfter(tAfterLeg); + getLegPlacesAcc(tPlaceLegAcc); + getLegPlacesAcc(tAfterLegAcc); + tSplitRevision = Class->tSplitRevision; +} + +int oRunner::getMissedTime(int ctrlNo) const { + setupRunnerStatistics(); + if (unsigned(ctrlNo) < tMissedTime.size()) + return tMissedTime[ctrlNo]; + else + return -1; +} + +string oRunner::getMissedTimeS() const +{ + setupRunnerStatistics(); + int t = 0; + for (size_t k = 0; k0) + t += tMissedTime[k]; + + return getTimeMS(t); +} + +string oRunner::getMissedTimeS(int ctrlNo) const +{ + int t = getMissedTime(ctrlNo); + if (t>0) + return getTimeMS(t); + else + return ""; +} + +int oRunner::getLegPlace(int ctrlNo) const { + setupRunnerStatistics(); + if (unsigned(ctrlNo) < tPlaceLeg.size()) + return tPlaceLeg[ctrlNo]; + else + return 0; +} + +int oRunner::getLegTimeAfter(int ctrlNo) const { + setupRunnerStatistics(); + if (unsigned(ctrlNo) < tAfterLeg.size()) + return tAfterLeg[ctrlNo]; + else + return -1; +} + +int oRunner::getLegPlaceAcc(int ctrlNo) const { + setupRunnerStatistics(); + if (unsigned(ctrlNo) < tPlaceLegAcc.size()) + return tPlaceLegAcc[ctrlNo]; + else + return 0; +} + +int oRunner::getLegTimeAfterAcc(int ctrlNo) const { + setupRunnerStatistics(); + if (unsigned(ctrlNo) < tAfterLegAcc.size()) + return tAfterLegAcc[ctrlNo]; + else + return -1; +} + +int oRunner::getTimeWhenPlaceFixed() const { + if (!Class || !statusOK()) + return -1; + +#ifndef MEOSDB + if (unsigned(tLeg) >= Class->tResultInfo.size()) { + oe->analyzeClassResultStatus(); + if (unsigned(tLeg) >= Class->tResultInfo.size()) + return -1; + } +#endif + + int lst = Class->tResultInfo[tLeg].lastStartTime; + return lst > 0 ? lst + getRunningTime() : lst; +} + + +pRunner oRunner::getMatchedRunner(const SICard &sic) const { + if (multiRunner.size() == 0 && tParentRunner == 0) + return pRunner(this); + if (!Class) + return pRunner(this); + if (Class->getLegType(tLeg) != LTExtra) + return pRunner(this); + + const vector &multiV = tParentRunner ? tParentRunner->multiRunner : multiRunner; + + vector multiOrdered; + multiOrdered.push_back( tParentRunner ? tParentRunner : pRunner(this)); + multiOrdered.insert(multiOrdered.end(), multiV.begin(), multiV.end()); + + int Distance=-1000; + pRunner r = 0; //Best runner + + for (size_t k = 0; kCard || multiOrdered[k]->getStatus() != StatusUnknown) + continue; + + if (Class->getLegType(multiOrdered[k]->tLeg) != LTExtra) + return pRunner(this); + + vector crs; + + if (Class->hasCoursePool()) { + Class->getCourses(multiOrdered[k]->tLeg, crs); + } + else { + pCourse pc = multiOrdered[k]->getCourse(false); + crs.push_back(pc); + } + + for (size_t j = 0; j < crs.size(); j++) { + pCourse pc = crs[j]; + if (!pc) + continue; + + int d = pc->distance(sic); + + if (d>=0) { + if (Distance<0) Distance=1000; + if (dDistance) { + Distance=d; + r = multiOrdered[k]; + } + } + } + } + + if (r) + return r; + else + return pRunner(this); +} + +int oRunner::getTotalRunningTime(int time) const { + if (tStartTime < 0) + return 0; + if (tInTeam == 0 || tLeg == 0) { + if (time == FinishTime) + return getRunningTime() + inputTime; + else + return time-tStartTime + inputTime; + } + else { + if (Class == 0 || unsigned(tLeg) >= Class->legInfo.size()) + return 0; + + if (time == FinishTime) { + return tInTeam->getLegRunningTime(tLeg, true); // Use the official running time in this case (which works with parallel legs) + } + + int baseleg = tLeg; + while (baseleg>0 && (Class->legInfo[baseleg].isParallel() || + Class->legInfo[baseleg].isOptional())) { + baseleg--; + } + + int leg = baseleg-1; + while (leg>0 && (Class->legInfo[leg].legMethod == LTExtra || Class->legInfo[leg].legMethod == LTIgnore)) { + leg--; + } + + int pt = leg>=0 ? tInTeam->getLegRunningTime(leg, true) : 0; + if (pt>0) + return pt + time - tStartTime; + else if (tInTeam->tStartTime > 0) + return (time - tInTeam->tStartTime) + tInTeam->inputTime; + else + return 0; + } +} + + // Get the complete name, including team and club. +string oRunner::getCompleteIdentification(bool includeExtra) const { + if (tInTeam == 0 || !Class || tInTeam->getName() == sName) { + if (Club) + return getName() + " (" + Club->name + ")"; + else + return getName(); + } + else { + string names; + pClass clsToUse = tInTeam->Class != 0 ? tInTeam->Class : Class; + // Get many names for paralell legs + int firstLeg = tLeg; + LegTypes lt=clsToUse->getLegType(firstLeg--); + while(firstLeg>=0 && (lt==LTIgnore || lt==LTParallel || lt==LTParallelOptional || (lt==LTExtra && includeExtra)) ) + lt=clsToUse->getLegType(firstLeg--); + + for (size_t k = firstLeg+1; k < clsToUse->legInfo.size(); k++) { + pRunner r = tInTeam->getRunner(k); + if (r) { + if (names.empty()) + names = r->tRealName; + else + names += "/" + r->tRealName; + } + lt = clsToUse->getLegType(k + 1); + if ( !(lt==LTIgnore || lt==LTParallel || lt == LTParallelOptional || (lt==LTExtra && includeExtra))) + break; + } + + if (clsToUse->legInfo.size() <= 2) + return names + " (" + tInTeam->sName + ")"; + else + return tInTeam->sName + " (" + names + ")"; + } +} + +RunnerStatus oAbstractRunner::getTotalStatus() const { + if (tStatus == StatusUnknown && inputStatus != StatusNotCompetiting) + return StatusUnknown; + else if (inputStatus == StatusUnknown) + return StatusDNS; + + return max(tStatus, inputStatus); +} + +RunnerStatus oRunner::getTotalStatus() const { + if (tStatus == StatusUnknown && inputStatus != StatusNotCompetiting) + return StatusUnknown; + else if (inputStatus == StatusUnknown) + return StatusDNS; + + if (tInTeam == 0 || tLeg == 0) + return max(tStatus, inputStatus); + else { + RunnerStatus st = tInTeam->getLegStatus(tLeg-1, true); + + if (tLeg + 1 == tInTeam->getNumRunners()) + st = max(st, tInTeam->getStatus()); + + if (st == StatusOK || st == StatusUnknown) + return tStatus; + else + return max(max(tStatus, st), inputStatus); + } +} + +void oRunner::remove() +{ + if (oe) { + vector me; + me.push_back(Id); + oe->removeRunner(me); + } +} + +bool oRunner::canRemove() const +{ + return !oe->isRunnerUsed(Id); +} + +void oAbstractRunner::setInputTime(const string &time) { + int t = convertAbsoluteTimeMS(time); + if (t != inputTime) { + inputTime = t; + updateChanged(); + } +} + +string oAbstractRunner::getInputTimeS() const { + if (inputTime > 0) + return formatTime(inputTime); + else + return "-"; +} + +void oAbstractRunner::setInputStatus(RunnerStatus s) { + if (inputStatus != s) { + inputStatus = s; + updateChanged(); + } +} + +string oAbstractRunner::getInputStatusS() const { + return oe->formatStatus(inputStatus); +} + +void oAbstractRunner::setInputPoints(int p) +{ + if (p != inputPoints) { + inputPoints = p; + updateChanged(); + } +} + +void oAbstractRunner::setInputPlace(int p) +{ + if (p != inputPlace) { + inputPlace = p; + updateChanged(); + } +} + +void oRunner::setInputData(const oRunner &r) { + if (!r.multiRunner.empty() && r.multiRunner.back() && r.multiRunner.back() != &r) + setInputData(*r.multiRunner.back()); + else { + oDataInterface dest = getDI(); + oDataConstInterface src = r.getDCI(); + + if (r.tStatus != StatusNotCompetiting) { + inputTime = r.getTotalRunningTime(r.FinishTime); + inputStatus = r.getTotalStatus(); + if (r.tInTeam) { // If a team has not status ok, transfer this status to all team members. + if (r.tInTeam->getTotalStatus() > StatusOK) + inputStatus = r.tInTeam->getTotalStatus(); + } + inputPoints = r.getRogainingPoints(true) + r.inputPoints; + inputPlace = r.tTotalPlace < 99000 ? r.tTotalPlace : 0; + } + else { + // Copy input + inputTime = r.inputTime; + inputStatus = r.inputStatus; + inputPoints = r.inputPoints; + inputPlace = r.inputPlace; + } + + if (r.getClubRef()) + setClub(r.getClub()); + + if (!Card && r.isTransferCardNoNextStage()) { + setCardNo(r.getCardNo(), false); + dest.setInt("CardFee", src.getInt("CardFee")); + setTransferCardNoNextStage(true); + } + // Copy flags. + // copy.... + + dest.setInt("TransferFlags", src.getInt("TransferFlags")); + dest.setString("Nationality", src.getString("Nationality")); + dest.setString("Country", src.getString("Country")); + + dest.setInt("Fee", src.getInt("Fee")); + dest.setInt("Paid", src.getInt("Paid")); + dest.setInt("Taxable", src.getInt("Taxable")); + } +} + +void oEvent::getDBRunnersInEvent(intkeymap &runners) const { + runners.clear(); + for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->isRemoved()) + continue; + __int64 id = it->getExtIdentifier(); + if (id != 0) + runners.insert(id, it->Class); + } +} + +void oRunner::init(const RunnerDBEntry &dbr) { + setTemporary(); + dbr.getName(sName); + getRealName(sName, tRealName); + CardNo = dbr.cardNo; + Club = oe->getRunnerDatabase().getClub(dbr.clubNo); + getDI().setString("Nationality", dbr.getNationality()); + getDI().setInt("BirthYear", dbr.getBirthYear()); + getDI().setString("Sex", dbr.getSex()); + setExtIdentifier(dbr.getExtId()); +} + +void oEvent::selectRunners(const string &classType, int lowAge, + int highAge, const string &firstDate, + const string &lastDate, bool includeWithFee, + vector &output) const { + oRunnerList::const_iterator it; + int cid = 0; + if (classType.length() > 2 && classType.substr(0,2) == "::") + cid = atoi(classType.c_str() + 2); + + output.clear(); + + int firstD = 0, lastD = 0; + if (!firstDate.empty()) { + firstD = convertDateYMS(firstDate, true); + if (firstD <= 0) + throw meosException("Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD).#" + firstDate); + } + + if (!lastDate.empty()) { + lastD = convertDateYMS(lastDate, true); + if (lastD <= 0) + throw meosException("Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD).#" + lastDate); + } + + + bool allClass = classType == "*"; + for (it=Runners.begin(); it != Runners.end(); ++it) { + if (it->skip()) + continue; + + const pClass pc = it->Class; + if (cid > 0 && (pc == 0 || pc->getId() != cid)) + continue; + + if (cid == 0 && !allClass) { + if ((pc && pc->getType()!=classType) || (pc==0 && !classType.empty())) + continue; + } + + int age = it->getBirthAge(); + if (age > 0 && (lowAge > 0 || highAge > 0)) { + if (lowAge > highAge) + throw meosException("Undre åldersgränsen är högre än den övre."); + + if (age < lowAge || age > highAge) + continue; + /* + bool ageOK = false; + if (lowAge > 0 && age <= lowAge) + ageOK = true; + else if (highAge > 0 && age >= highAge) + ageOK = true; + + if (!ageOK) + continue;*/ + } + + int date = it->getDCI().getInt("EntryDate"); + if (date > 0) { + if (firstD > 0 && date < firstD) + continue; + if (lastD > 0 && date > lastD) + continue; + + } + + if (!includeWithFee) { + int fee = it->getDCI().getInt("Fee"); + if (fee != 0) + continue; + } + // string date = di.getDate("EntryDate"); + + output.push_back(pRunner(&*it)); + } +} + +void oRunner::changeId(int newId) { + pRunner old = oe->runnerById[Id]; + if (old == this) + oe->runnerById.remove(Id); + + oBase::changeId(newId); + + oe->runnerById[newId] = this; +} + +const vector &oRunner::getSplitTimes(bool normalized) const { + if (!normalized) + return splitTimes; + else { + pCourse pc = getCourse(true); + if (pc && pc->isAdapted() && splitTimes.size() == pc->nControls) { + if (!normalizedSplitTimes.empty()) + return normalizedSplitTimes; + const vector &mapToOriginal = pc->getMapToOriginalOrder(); + normalizedSplitTimes.resize(splitTimes.size()); // nControls + vector orderedSplits(splitTimes.size() + 1, -1); + + for (int k = 0; k < pc->nControls; k++) { + if (splitTimes[k].hasTime()) { + int t = -1; + int j = k - 1; + while (j >= -1 && t == -1) { + if (j == -1) + t = getStartTime(); + else if (splitTimes[j].hasTime()) + t = splitTimes[j].time; + j--; + } + orderedSplits[mapToOriginal[k]] = splitTimes[k].time - t; + } + } + + // Last to finish + { + int t = -1; + int j = pc->nControls - 1; + while (j >= -1 && t == -1) { + if (j == -1) + t = getStartTime(); + else if (splitTimes[j].hasTime()) + t = splitTimes[j].time; + j--; + } + orderedSplits[mapToOriginal[pc->nControls]] = FinishTime - t; + } + + int accumulatedTime = getStartTime(); + for (int k = 0; k < pc->nControls; k++) { + if (orderedSplits[k] > 0) { + accumulatedTime += orderedSplits[k]; + normalizedSplitTimes[k].setPunchTime(accumulatedTime); + } + else + normalizedSplitTimes[k].setNotPunched(); + } + + return normalizedSplitTimes; + } + return splitTimes; + } +} + +void oRunner::markClassChanged(int controlId) { + assert(controlId < 4096); + if (Class) { + Class->markSQLChanged(tLeg, controlId); + if (tInTeam && tInTeam->Class != Class && tInTeam->Class) { + tInTeam->Class->markSQLChanged(tLeg, controlId); + } + } + else if (oe) + oe->globalModification = true; +} + +void oAbstractRunner::changedObject() { + markClassChanged(-1); +} + +int oAbstractRunner::getTimeAdjustment() const { + if (oe->dataRevision != tAdjustDataRevision) { + oDataConstInterface dci = getDCI(); + tTimeAdjustment = dci.getInt("TimeAdjust"); + tPointAdjustment = dci.getInt("PointAdjust"); + tAdjustDataRevision = oe->dataRevision; + } + return tTimeAdjustment; +} + +int oAbstractRunner::getPointAdjustment() const { + if (oe->dataRevision != tAdjustDataRevision) { + getTimeAdjustment(); //Setup cache + } + return tPointAdjustment; +} + +void oAbstractRunner::setTimeAdjustment(int adjust) { + tTimeAdjustment = adjust; + getDI().setInt("TimeAdjust", adjust); +} + +void oAbstractRunner::setPointAdjustment(int adjust) { + tPointAdjustment = adjust; + getDI().setInt("PointAdjust", adjust); +} + +int oRunner::getRogainingPoints(bool multidayTotal) const { + if (multidayTotal) + return inputPoints + tRogainingPoints; + else + return tRogainingPoints; +} + +int oRunner::getRogainingReduction() const { + return tReduction; +} + +int oRunner::getRogainingPointsGross() const { + return tRogainingPointsGross; +} + +int oRunner::getRogainingOvertime() const { + return tRogainingOvertime; +} + +void oAbstractRunner::TempResult::reset() { + runningTime = 0; + timeAfter = 0; + points = 0; + place = 0; + startTime = 0; + status = StatusUnknown; + internalScore = 0; +} + +oAbstractRunner::TempResult::TempResult() { + reset(); +} + +oAbstractRunner::TempResult::TempResult(RunnerStatus statusIn, + int startTimeIn, + int runningTimeIn, + int pointsIn) :status(statusIn), + startTime(startTimeIn), runningTime(runningTimeIn), + timeAfter(0), points(0), place(0) { +} + +const oAbstractRunner::TempResult &oAbstractRunner::getTempResult(int tempResultIndex) const { + return tmpResult; //Ignore index for now... + /*if (tempResultIndex == 0) + return tmpResult; + else + throw meosException("Not implemented");*/ +} + +oAbstractRunner::TempResult &oAbstractRunner::getTempResult() { + return tmpResult; +} + + +void oAbstractRunner::setTempResultZero(const TempResult &tr) { + tmpResult = tr; +} + +const string &oAbstractRunner::TempResult::getStatusS(RunnerStatus inputStatus) const { + if (inputStatus == StatusOK) + return oEvent::formatStatus(getStatus()); + else if (inputStatus == StatusUnknown) + return oEvent::formatStatus(StatusUnknown); + else + return oEvent::formatStatus(max(inputStatus, getStatus())); +} + +const string &oAbstractRunner::TempResult::getPrintPlaceS(bool withDot) const { + int p=getPlace(); + if (p>0 && p<10000){ + if (withDot) { + string &res = StringCache::getInstance().get(); + res = itos(p); + res += "."; + return res; + } + else + return itos(p); + } + return _EmptyString; +} + +const string &oAbstractRunner::TempResult::getRunningTimeS(int inputTime) const { + return formatTime(getRunningTime() + inputTime); +} + +const string &oAbstractRunner::TempResult::getFinishTimeS(const oEvent *oe) const { + return oe->getAbsTime(getFinishTime()); +} + +const string &oAbstractRunner::TempResult::getStartTimeS(const oEvent *oe) const { + int st = getStartTime(); + if (st > 0) + return oe->getAbsTime(st); + else return MakeDash("-"); +} + +const string &oAbstractRunner::TempResult::getOutputTime(int ix) const { + int t = size_t(ix) < outputTimes.size() ? outputTimes[ix] : 0; + return formatTime(t); +} + +int oAbstractRunner::TempResult::getOutputNumber(int ix) const { + return size_t(ix) < outputNumbers.size() ? outputNumbers[ix] : 0; +} + +void oAbstractRunner::resetInputData() { + setInputPlace(0); + if (0 != inputTime) { + inputTime = 0; + updateChanged(); + } + setInputStatus(StatusNotCompetiting); + setInputPoints(0); +} + +bool oRunner::isTransferCardNoNextStage() const { + return hasFlag(FlagUpdateCard); +} + +void oRunner::setTransferCardNoNextStage(bool state) { + setFlag(FlagUpdateCard, state); +} + +bool oAbstractRunner::hasFlag(TransferFlags flag) const { + return (getDCI().getInt("TransferFlags") & flag) != 0; +} + +void oAbstractRunner::setFlag(TransferFlags flag, bool onoff) { + int cf = getDCI().getInt("TransferFlags"); + cf = onoff ? (cf | flag) : (cf & (~flag)); + getDI().setInt("TransferFlags", cf); +} + +int oRunner::getNumShortening() const { + if (oe->dataRevision != tShortenDataRevision) { + oDataConstInterface dci = getDCI(); + tNumShortening = dci.getInt("Shorten"); + tShortenDataRevision = oe->dataRevision; + } + return tNumShortening; +} + +void oRunner::setNumShortening(int numShorten) { + tNumShortening = numShorten; + tShortenDataRevision = oe->dataRevision; + oDataInterface di = getDI(); + di.setInt("Shorten", numShorten); +} + +int oAbstractRunner::getEntrySource() const { + return getDCI().getInt("EntrySource"); +} + +void oAbstractRunner::setEntrySource(int src) { + getDI().setInt("EntrySource", src); +} + +void oAbstractRunner::flagEntryTouched(bool flag) { + tEntryTouched = flag; +} + +bool oAbstractRunner::isEntryTouched() const { + return tEntryTouched; +} + +int oRunner::getTotalTimeInput() const { + if (tInTeam) { + if (getLegNumber()>0) { + return tInTeam->getLegRunningTime(getLegNumber()-1, true); + } + else { + return tInTeam->getInputTime(); + } + } + else { + return getInputTime(); + } +} + + +RunnerStatus oRunner::getTotalStatusInput() const { + RunnerStatus inStatus = StatusOK; + if (tInTeam) { + const pTeam t = tInTeam; + if (getLegNumber()>0) { + inStatus = t->getLegStatus(getLegNumber()-1, true); + } + else { + inStatus = t->getInputStatus(); + } + } + else { + inStatus = getInputStatus(); + } + return inStatus; +} + +bool oAbstractRunner::startTimeAvailable() const { + if (getFinishTime() > 0) + return true; + + return getStartTime() > 0; +} + +bool oRunner::startTimeAvailable() const { + if (getFinishTime() > 0) + return true; + + int st = getStartTime(); + bool definedTime = st > 0; + + if (!definedTime) + return false; + + if (!Class || !tInTeam || tLeg == 0) + return definedTime; + + // Check if time is restart time + int restart = Class->getRestartTime(tLeg); + if (st == restart && Class->getStartType(tLeg) == STChange) { + int currentTime = oe->getComputerTime(); + int rope = Class->getRopeTime(tLeg); + return rope != 0 && currentTime + 600 > rope; + } + + return true; +} + +int oRunner::getRanking() const { + int rank = getDCI().getInt("Rank"); + if (rank <= 0) + return MaxRankingConstant; + else + return rank; +} + +void oAbstractRunner::hasManuallyUpdatedTimeStatus() { + if (Class && Class->hasClassGlobalDependance()) { + set cls; + oe->reEvaluateAll(cls, false); + } +} + +bool oRunner::canShareCard(const pRunner other, int newCardNo) const { + if (!other || other->CardNo != newCardNo || newCardNo == 0) + return true; + + if (getCard() && getCard()->getCardNo() == newCardNo) + return true; + + if (other->skip() || other->getCard() || other == this || + other->getMultiRunner(0) == getMultiRunner(0)) + return true; + + if (!getTeam() || other->getTeam() != getTeam()) + return false; + + pClass tCls = getTeam()->getClassRef(); + if (!tCls || tCls != Class) + return false; + + LegTypes lt1 = tCls->getLegType(tLeg); + LegTypes lt2 = tCls->getLegType(other->tLeg); + + if (lt1 == LTGroup || lt2 == LTGroup) + return false; + + int ln1, ln2, ord; + tCls->splitLegNumberParallel(tLeg, ln1, ord); + tCls->splitLegNumberParallel(other->tLeg, ln2, ord); + return ln1 != ln2; +} + +int oAbstractRunner::getPaymentMode() const { + return getDCI().getInt("PayMode"); +} + +void oAbstractRunner::setPaymentMode(int mode) { + getDI().setInt("PayMode", mode); +} + +bool oAbstractRunner::hasLateEntryFee() const { + if (!Class) + return false; + int highFee = Class->getDCI().getInt("HighClassFee"); + int normalFee = Class->getDCI().getInt("ClassFee"); + + int fee = getDCI().getInt("Fee"); + if (fee == normalFee || fee == 0) + return false; + else if (fee == highFee && highFee > normalFee && normalFee > 0) + return true; + + string date = getEntryDate(true); + oDataConstInterface odc = oe->getDCI(); + string oentry = odc.getDate("OrdinaryEntry"); + bool late = date > oentry && oentry>="2010-01-01"; + + return late; +} diff --git a/code/oRunner.h b/code/oRunner.h new file mode 100644 index 0000000..c7361c2 --- /dev/null +++ b/code/oRunner.h @@ -0,0 +1,755 @@ +// oRunner.h: interface for the oRunner class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_ORUNNER_H__D3B8D6C8_C90A_4F86_B776_7D77E5C76F42__INCLUDED_) +#define AFX_ORUNNER_H__D3B8D6C8_C90A_4F86_B776_7D77E5C76F42__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include + +#include "oBase.h" +#include "oClub.h" +#include "oClass.h" +#include "oCard.h" +#include "oSpeaker.h" +#include "oDataContainer.h" + +class oRunner; +typedef oRunner* pRunner; +typedef const oRunner* cRunner; + +class oTeam; +typedef oTeam* pTeam; +typedef const oTeam* cTeam; + +struct SICard; + +const int MaxRankingConstant = 99999999; + +class oAbstractRunner : public oBase { +protected: + string sName; + pClub Club; + pClass Class; + + int startTime; + int tStartTime; + + int FinishTime; + RunnerStatus status; + RunnerStatus tStatus; + + /** Temporary storage for set operations to be applied later*/ + struct TempSetStore { + int startTime; + RunnerStatus status; + int startNo; + string bib; + }; + + TempSetStore tmpStore; + + void resetTmpStore(); + +public: + + struct TempResult { + private: + int startTime; + int runningTime; + int timeAfter; + int points; + int place; + int internalScore; + vector outputTimes; + vector outputNumbers; + RunnerStatus status; + void reset(); + TempResult(); + public: + int getRunningTime() const {return runningTime;} + int getFinishTime() const {return runningTime > 0 ? startTime + runningTime : 0;} + int getStartTime() const {return startTime;} + int getTimeAfter() const {return timeAfter;} + int getPoints() const {return points;} + int getPlace() const {return place;} + RunnerStatus getStatus() const {return status;} + + const string &getStatusS(RunnerStatus inputStatus) const; + const string &getPrintPlaceS(bool withDot) const; + const string &getRunningTimeS(int inputTime) const; + const string &getFinishTimeS(const oEvent *oe) const; + const string &getStartTimeS(const oEvent *oe) const; + + const string &getOutputTime(int ix) const; + int getOutputNumber(int ix) const; + + friend class GeneralResult; + friend class oAbstractRunner; + friend class oEvent; + friend class DynamicResult; + TempResult(RunnerStatus statusIn, int startTime, + int runningTime, int points); + }; + +protected: + TempResult tmpResult; + + // Sets result to object. Returns true if status/time changed + bool setTmpStore(); + + mutable int tTimeAdjustment; + mutable int tPointAdjustment; + mutable int tAdjustDataRevision; + //Used for automatically assigning courses form class. + //Set when drawn or by team or... + int StartNo; + + // Data used for multi-days events + int inputTime; + RunnerStatus inputStatus; + int inputPoints; + int inputPlace; + + bool sqlChanged; + bool tEntryTouched; + + void changedObject(); +public: + /** Call this method after doing something to just this + runner/team that changed the time/status etc, that effects + the result. May make a global evaluation of the class. + Never call "for each" runner. */ + void hasManuallyUpdatedTimeStatus(); + + /** Returs true if the class is a patrol class */ + bool isPatrolMember() const { + return Class && Class->getClassType() == oClassPatrol; + } + + /** Returns true if the team / runner has a start time available*/ + virtual bool startTimeAvailable() const; + + int getEntrySource() const; + void setEntrySource(int src); + void flagEntryTouched(bool flag); + bool isEntryTouched() const; + + /** Returns number of shortenings taken. */ + virtual int getNumShortening() const = 0; + + int getPaymentMode() const; + void setPaymentMode(int mode); + + enum TransferFlags { + FlagTransferNew = 1, + FlagUpdateCard = 2, + FlagTransferSpecified = 4, + FlagFeeSpecified = 8, + FlagUpdateClass = 16, + FlagUpdateName = 32, + }; + + bool hasFlag(TransferFlags flag) const; + void setFlag(TransferFlags flag, bool state); + + // Get the runners team or the team itself + virtual cTeam getTeam() const = 0; + virtual pTeam getTeam() = 0; + + virtual string getEntryDate(bool useTeamEntryDate = true) const = 0; + + // Set default fee, from class + // a non-zero fee is changed only if resetFee is true + void addClassDefaultFee(bool resetFees); + + /** Returns true if the entry fee is a late fee. */ + bool hasLateEntryFee() const; + + bool hasInputData() const {return inputTime > 0 || inputStatus != StatusOK || inputPoints > 0;} + + /** Reset input data to no input and the input status to NotCompeting. */ + void resetInputData(); + + /** Return results for a specific result module. */ + const TempResult &getTempResult(int tempResultIndex) const; + TempResult &getTempResult(); + + void setTempResultZero(const TempResult &tr); + + // Time + void setInputTime(const string &time); + string getInputTimeS() const; + int getInputTime() const {return inputTime;} + + // Status + void setInputStatus(RunnerStatus s); + string getInputStatusS() const; + RunnerStatus getInputStatus() const {return inputStatus;} + + // Points + void setInputPoints(int p); + int getInputPoints() const {return inputPoints;} + + // Place + void setInputPlace(int p); + int getInputPlace() const {return inputPlace;} + + bool isVacant() const; + + bool wasSQLChanged() const {return sqlChanged;} + + /** Use -1 for all, PunchFinish or controlId */ + virtual void markClassChanged(int controlId) = 0; + + string getInfo() const; + + virtual bool apply(bool sync, pRunner src, bool setTmpOnly) = 0; + + //Get time after on leg/for race + virtual int getTimeAfter(int leg) const = 0; + + + virtual void fillSpeakerObject(int leg, int controlCourseId, int previousControlCourseId, bool totalResult, + oSpeakerObject &spk) const = 0; + + virtual int getBirthAge() const; + + virtual void setName(const string &n, bool manualChange); + virtual const string &getName() const {return sName;} + + virtual void setFinishTimeS(const string &t); + virtual void setFinishTime(int t); + + /** Sets start time, if updatePermanent is true, the stored start time is updated, + otherwise the value is considered deduced. */ + bool setStartTime(int t, bool updatePermanent, bool setTmpOnly, bool recalculate = true); + void setStartTimeS(const string &t); + + const pClub getClubRef() const {return Club;} + pClub getClubRef() {return Club;} + + const pClass getClassRef() const {return Class;} + pClass getClassRef() {return Class;} + + virtual const string &getClub() const {if (Club) return Club->name; else return _EmptyString;} + virtual int getClubId() const {if (Club) return Club->Id; else return 0;} + virtual void setClub(const string &Name); + virtual pClub setClubId(int clubId); + + virtual const string &getClass() const {if (Class) return Class->Name; else return _EmptyString;} + virtual int getClassId() const {if (Class) return Class->Id; else return 0;} + virtual void setClassId(int id, bool isManualUpdate); + virtual int getStartNo() const {return StartNo;} + virtual void setStartNo(int no, bool storeTmpOnly); + + // Start number is equal to bib-no, but bib + // is only set when it should be shown in lists etc. + const string &getBib() const; + virtual void setBib(const string &bib, int numericalBib, bool updateStartNo, bool setTmpOnly) = 0; + int getEncodedBib() const; + + virtual int getStartTime() const {return tStartTime;} + virtual int getFinishTime() const {return FinishTime;} + + int getFinishTimeAdjusted() const {return getFinishTime() + getTimeAdjustment();} + + virtual int getRogainingPoints(bool multidayTotal) const = 0; + virtual int getRogainingReduction() const = 0; + virtual int getRogainingOvertime() const = 0; + virtual int getRogainingPointsGross() const = 0; + + virtual const string &getStartTimeS() const; + virtual const string &getStartTimeCompact() const; + virtual const string &getFinishTimeS() const; + + virtual const string &getTotalRunningTimeS() const; + virtual const string &getRunningTimeS() const; + virtual int getRunningTime() const; + + /// Get total running time (including earlier stages / races) + virtual int getTotalRunningTime() const; + + virtual int getPrelRunningTime() const; + virtual string getPrelRunningTimeS() const; + + virtual string getPlaceS() const; + virtual string getPrintPlaceS(bool withDot) const; + + virtual string getTotalPlaceS() const; + virtual string getPrintTotalPlaceS(bool withDot) const; + + virtual int getPlace() const = 0; + virtual int getTotalPlace() const = 0; + + virtual RunnerStatus getStatus() const {return tStatus;} + inline bool statusOK() const {return tStatus==StatusOK;} + inline bool prelStatusOK() const {return tStatus==StatusOK || (tStatus == StatusUnknown && getRunningTime() > 0);} + + /** Sets the status. If updatePermanent is true, the stored start + time is updated, otherwise the value is considered deduced. + if setTmp is true, the status is only stored in a temporary container. + */ + virtual bool setStatus(RunnerStatus st, bool updatePermanent, bool setTmp, bool recalculate = true); + + /** Returns the ranking of the runner or the team (first runner in it?) */ + virtual int getRanking() const = 0; + + /// Get total status for this running (including team/earlier races) + virtual RunnerStatus getTotalStatus() const; + + virtual const string &getStatusS() const; + virtual string getIOFStatusS() const; + + virtual const string &getTotalStatusS() const; + virtual string getIOFTotalStatusS() const; + + void setSpeakerPriority(int pri); + virtual int getSpeakerPriority() const; + + int getTimeAdjustment() const; + int getPointAdjustment() const; + + void setTimeAdjustment(int adjust); + void setPointAdjustment(int adjust); + + oAbstractRunner(oEvent *poe, bool loading); + virtual ~oAbstractRunner() {}; + + friend class oListInfo; + friend class GeneralResult; +}; + +struct RunnerDBEntry; + +struct SplitData { + enum SplitStatus {OK, Missing, NoTime}; + int time; + SplitStatus status; + SplitData() {}; + SplitData(int t, SplitStatus s) : time(t), status(s) {}; + + void setPunchTime(int t) { + time = t; + status = OK; + } + + void setPunched() { + time = -1; + status = NoTime; + } + + void setNotPunched() { + time = -1; + status = Missing; + } + + bool hasTime() const { + return time > 0 && status == OK; + } + + bool isMissing() const { + return status == Missing; + } +}; + +class oRunner : public oAbstractRunner +{ +protected: + pCourse Course; + + int CardNo; + pCard Card; + + vector multiRunner; + vector multiRunnerId; + + string tRealName; + + //Can be changed by apply + mutable int tPlace; + mutable int tCoursePlace; + mutable int tTotalPlace; + mutable int tLeg; + mutable int tLegEquClass; + mutable pTeam tInTeam; + mutable pRunner tParentRunner; + mutable bool tNeedNoCard; + mutable bool tUseStartPunch; + mutable int tDuplicateLeg; + mutable int tNumShortening; + mutable int tShortenDataRevision; + + //Temporary status and running time + RunnerStatus tempStatus; + int tempRT; + + bool isTemporaryObject; + int tTimeAfter; // Used in time line calculations, time after "last radio". + int tInitialTimeAfter; // Used in time line calculations, time after when started. + //Speaker data + map priority; + int cPriority; + + static const int dataSize = 192; + int getDISize() const {return dataSize;} + + BYTE oData[dataSize]; + BYTE oDataOld[dataSize]; + + bool storeTimes(); // Returns true if best times were updated + + bool storeTimesAux(pClass targetClass); // Returns true if best times were updated + + // Adjust times for fixed time controls + void doAdjustTimes(pCourse course); + + vector adjustTimes; + vector splitTimes; + mutable vector normalizedSplitTimes; //Loop courses + + vector tLegTimes; + + string codeMultiR() const; + void decodeMultiR(const string &r); + + pRunner getPredecessor() const; + + void markForCorrection() {correctionNeeded = true;} + //Remove by force the runner from a multirunner definition + void correctRemove(pRunner r); + + vector getRunnersOrdered() const; + int getMultiIndex(); //Returns the index into multi runners, 0 - n, -1 on error. + + void exportIOFRunner(xmlparser &xml, bool compact); + void exportIOFStart(xmlparser &xml); + + // Revision number of runners statistics cache + mutable int tSplitRevision; + // Running time as calculated by evalute. Used to detect changes. + int tCachedRunningTime; + + void clearOnChangedRunningTime(); + + // Cached runner statistics + mutable vector tMissedTime; + mutable vector tPlaceLeg; + mutable vector tAfterLeg; + mutable vector tPlaceLegAcc; + mutable vector tAfterLegAcc; + + // Rogainig results. Control and punch time + vector< pair > tRogaining; + int tRogainingPoints; + int tRogainingPointsGross; + int tReduction; + int tRogainingOvertime; + string tProblemDescription; + // Sets up mutable data above + void setupRunnerStatistics() const; + + // Update hash + void changeId(int newId); + + class RaceIdFormatter : public oDataDefiner { + public: + const string &formatData(oBase *obj) const; + string setData(oBase *obj, const string &input) const; + int addTableColumn(Table *table, const string &description, int minWidth) const; + }; + + static RaceIdFormatter raceIdFormatter; + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + + // Course adapted to loops + mutable pCourse tAdaptedCourse; + mutable int tAdaptedCourseRevision; + +public: + const string &getUIName() const; + const string &getNameRaw() const {return sName;} + virtual const string &getName() const; + const string &getNameLastFirst() const; + static void getRealName(const string &input, string &output); + + /** Returns true if this runner can use the specified card, + or false if it conflicts with the card of the other runner. */ + bool canShareCard(const pRunner other, int newCardNumber) const; + + void markClassChanged(int controlId); + + int getRanking() const; + + /** Returns true if the team / runner has a valid start time available*/ + virtual bool startTimeAvailable() const; + + /** Get a total input time from previous legs and stages*/ + int getTotalTimeInput() const; + + /** Get a total input time from previous legs and stages*/ + RunnerStatus getTotalStatusInput() const; + + // Returns public unqiue identifier of runner's race (for binding card numbers etc.) + int getRaceIdentifier() const; + + // Get entry date of runner (or its team) + string getEntryDate(bool useTeamEntryDate = true) const; + + // Get date of birth + int getBirthAge() const; + + // Multi day data input + void setInputData(const oRunner &source); + + // Returns true if the card number is suppossed to be transferred to the next stage + bool isTransferCardNoNextStage() const; + + // Set wheather the card number should be transferred to the next stage + void setTransferCardNoNextStage(bool state); + + int getLegNumber() const {return tLeg;} + int getSpeakerPriority() const; + + void remove(); + bool canRemove() const; + + cTeam getTeam() const {return tInTeam;} + pTeam getTeam() {return tInTeam;} + + /// Get total running time for multi/team runner at the given time + int getTotalRunningTime(int time) const; + + // Get total running time at finish time (@override) + int getTotalRunningTime() const; + + //Get total running time after leg + int getRaceRunningTime(int leg) const; + + // Get the complete name, including team and club. + string getCompleteIdentification(bool includeExtra = true) const; + + /// Get total status for this running (including team/earlier races) + RunnerStatus getTotalStatus() const; + + // Return the runner in a multi-runner set matching the card, if course type is extra + pRunner getMatchedRunner(const SICard &sic) const; + + int getRogainingPoints(bool multidayTotal) const; + int getRogainingPointsGross() const; + int getRogainingReduction() const; + int getRogainingOvertime() const; + + const string &getProblemDescription() const {return tProblemDescription;} + + // Leg statistics access methods + string getMissedTimeS() const; + string getMissedTimeS(int ctrlNo) const; + + int getMissedTime(int ctrlNo) const; + int getLegPlace(int ctrlNo) const; + int getLegTimeAfter(int ctrlNo) const; + int getLegPlaceAcc(int ctrlNo) const; + int getLegTimeAfterAcc(int ctrlNo) const; + + /** Calculate the time when the runners place is fixed, i.e, + when no other runner can threaten the place. + Returns -1 if undeterminable. + Return 0 if place is fixed. */ + int getTimeWhenPlaceFixed() const; + + /** Automatically assign a bib. Returns true if bib is assigned. */ + bool autoAssignBib(); + + /** Flag as temporary */ + void setTemporary() {isTemporaryObject=true;} + + /** Init from dbrunner */ + void init(const RunnerDBEntry &entry); + + /** Use db to pdate runner */ + bool updateFromDB(const string &name, int clubId, int classId, + int cardNo, int birthYear); + + void printSplits(gdioutput &gdi) const; + + void printStartInfo(gdioutput &gdi) const; + + /** Take the start time from runner r*/ + void cloneStartTime(const pRunner r); + + /** Clone data from other runner */ + void cloneData(const pRunner r); + + // Leg to run for this runner. Maps into oClass.MultiCourse. + // Need to check index in bounds. + int legToRun() const {return tInTeam ? tLeg : tDuplicateLeg;} + void setName(const string &n, bool manualUpdate); + void setClassId(int id, bool isManualUpdate); + void setClub(const string &Name); + pClub setClubId(int clubId); + + // Start number is equal to bib-no, but bib + // is only set when it should be shown in lists etc. + // Need not be so for teams. Course depends on start number, + // which should be more stable. + void setBib(const string &bib, int bibNumerical, bool updateStartNo, bool setTmpOnly); + void setStartNo(int no, bool setTmpOnly); + + pRunner nextNeedReadout() const; + + // Synchronize this runner and parents/sibllings and team + bool synchronizeAll(); + + void setFinishTime(int t); + int getTimeAfter(int leg) const; + int getTimeAfter() const; + int getTimeAfterCourse() const; + + bool skip() const {return isRemoved() || tDuplicateLeg!=0;} + + pRunner getMultiRunner(int race) const; + int getNumMulti() const {return multiRunner.size();} //Returns number of multi runners (zero=no multi) + void createMultiRunner(bool createMaster, bool sync); + int getRaceNo() const {return tDuplicateLeg;} + string getNameAndRace(bool useUIName) const; + + void fillSpeakerObject(int leg, int courseControlId, int previousControlCourseId, bool totalResult, + oSpeakerObject &spk) const; + + bool needNoCard() const; + int getPlace() const; + int getCoursePlace() const; + int getTotalPlace() const; + + // Normalized = true means permuted to the unlooped version of the course + const vector &getSplitTimes(bool normalized) const; + + void getSplitAnalysis(vector &deltaTimes) const; + void getLegPlaces(vector &places) const; + void getLegTimeAfter(vector &deltaTimes) const; + + void getLegPlacesAcc(vector &places) const; + void getLegTimeAfterAcc(vector &deltaTimes) const; + + // Normalized = true means permuted to the unlooped version of the course + int getSplitTime(int controlNumber, bool normalized) const; + int getTimeAdjust(int controlNumber) const; + + int getNamedSplit(int controlNumber) const; + // Normalized = true means permuted to the unlooped version of the course + int getPunchTime(int controlNumber, bool normalized) const; + // Normalized = true means permuted to the unlooped version of the course + string getSplitTimeS(int controlNumber, bool normalized) const; + // Normalized = true means permuted to the unlooped version of the course + string getPunchTimeS(int controlNumber, bool normalized) const; + string getNamedSplitS(int controlNumber) const; + + void addTableRow(Table &table) const; + bool inputData(int id, const string &input, + int inputId, string &output, bool noUpdate); + void fillInput(int id, vector< pair > &elements, size_t &selected); + + bool apply(bool sync, pRunner src, bool setTmpOnly); + void resetPersonalData(); + + //Local user data. No Update. + void setPriority(int courseControlId, int p){priority[courseControlId]=p;} + + string getGivenName() const; + string getFamilyName() const; + + pCourse getCourse(bool getAdaptedCourse) const; + const string &getCourseName() const; + + int getNumShortening() const; + void setNumShortening(int numShorten); + + pCard getCard() const {return Card;} + int getCardId(){if (Card) return Card->Id; else return 0;} + + bool operator<(const oRunner &c); + bool static CompareSINumber(const oRunner &a, const oRunner &b){return a.CardNo &missingPunches, int addpunch=0, bool synchronize=false); + void addPunches(pCard card, vector &missingPunches); + + /** Get split time for a controlId and optionally controlIndex on course (-1 means unknown, uses the first occurance on course)*/ + void getSplitTime(int courseControlId, RunnerStatus &stat, int &rt) const; + + //const string &getClubNameDB() const {return ClubName;} + + //Returns only Id of a runner-specific course, not classcourse + int getCourseId() const {if (Course) return Course->Id; else return 0;} + void setCourseId(int id); + + int getCardNo() const {return tParentRunner ? tParentRunner->CardNo : CardNo;} + void setCardNo(int card, bool matchCard, bool updateFromDatabase = false); + /** Sets the card to a given card. An existing card is marked as unpaired. + CardNo is updated. Returns id of old card (or 0). + */ + int setCard(int cardId); + + void Set(const xmlobject &xo); + + bool Write(xmlparser &xml); + bool WriteSmall(xmlparser &xml); + + oRunner(oEvent *poe); + oRunner(oEvent *poe, int id); + + void setSex(PersonSex sex); + PersonSex getSex() const; + + void setBirthYear(int year); + int getBirthYear() const; + void setNationality(const string &nat); + string getNationality() const; + + // Return true if the input name is considered equal to output name + bool matchName(const string &pname) const; + + virtual ~oRunner(); + + friend class MeosSQL; + friend class oEvent; + friend class oTeam; + friend class oClass; + friend bool CompareRunnerSPList(const oRunner &a, const oRunner &b); + friend bool CompareRunnerResult(const oRunner &a, const oRunner &b); + friend bool compareClubClassTeamName(const oRunner &a, const oRunner &b); + friend class RunnerDB; + friend class oListInfo; + static bool sortSplit(const oRunner &a, const oRunner &b); + +}; + +#endif // !defined(AFX_ORUNNER_H__D3B8D6C8_C90A_4F86_B776_7D77E5C76F42__INCLUDED_) diff --git a/code/oTeam.cpp b/code/oTeam.cpp new file mode 100644 index 0000000..d8f1fd6 --- /dev/null +++ b/code/oTeam.cpp @@ -0,0 +1,2162 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "meos_util.h" +#include "oEvent.h" +#include +#include +#include "meosdb/sqltypes.h" +#include "Table.h" +#include "localizer.h" +#include "meosException.h" +#include "gdioutput.h" + +oTeam::oTeam(oEvent *poe): oAbstractRunner(poe, false) +{ + Id=oe->getFreeTeamId(); + getDI().initData(); + correctionNeeded = false; + StartNo=0; +} + +oTeam::oTeam(oEvent *poe, int id): oAbstractRunner(poe, true) { + Id=id; + oe->qFreeTeamId = max(id, oe->qFreeTeamId); + getDI().initData(); + correctionNeeded = false; + StartNo=0; +} + +oTeam::~oTeam(void) { + /*for(unsigned i=0; itInTeam==this) { + assert(Runners[i]->tInTeam!=this); + Runners[i]=0; + } + }*/ +} + +void oTeam::prepareRemove() +{ + for(unsigned i=0; iId); + if (Class) xml.write("Class", Class->Id); + + xml.write("InputPoint", inputPoints); + if (inputStatus != StatusOK) + xml.write("InputStatus", itos(inputStatus)); //Force write of 0 + xml.write("InputTime", inputTime); + xml.write("InputPlace", inputPlace); + + + getDI().write(xml); + xml.endTag(); + + return true; +} + +void oTeam::set(const xmlobject &xo) +{ + xmlList xl; + xo.getObjects(xl); + xmlList::const_iterator it; + + for(it=xl.begin(); it != xl.end(); ++it){ + if (it->is("Id")){ + Id=it->getInt(); + } + else if (it->is("Name")){ + sName=it->get(); + } + else if (it->is("StartNo")){ + StartNo=it->getInt(); + } + else if (it->is("Start")){ + tStartTime = startTime = it->getInt(); + } + else if (it->is("Finish")){ + FinishTime=it->getInt(); + } + else if (it->is("Status")) { + unsigned rawStatus = it->getInt(); + tStatus = status=RunnerStatus(rawStatus < 100u ? rawStatus : 0); + } + else if (it->is("Class")){ + Class=oe->getClass(it->getInt()); + } + else if (it->is("Club")){ + Club=oe->getClub(it->getInt()); + } + else if (it->is("Runners")){ + vector r; + decodeRunners(it->get(), r); + importRunners(r); + } + else if (it->is("InputTime")) { + inputTime = it->getInt(); + } + else if (it->is("InputStatus")) { + unsigned rawStatus = it->getInt(); + inputStatus = RunnerStatus(rawStatus < 100u ? rawStatus : 0); + } + else if (it->is("InputPoint")) { + inputPoints = it->getInt(); + } + else if (it->is("InputPlace")) { + inputPlace = it->getInt(); + } + else if (it->is("Updated")){ + Modified.setStamp(it->get()); + } + else if (it->is("oData")) { + getDI().set(*it); + } + } +} + +string oTeam::getRunners() const +{ + string str=""; + char bf[16]; + unsigned m=0; + + for(m=0;mId); + str+=bf; + } + else str+="0;"; + } + return str; +} + +void oTeam::decodeRunners(const string &rns, vector &rid) +{ + const char *str=rns.c_str(); + rid.clear(); + + int n=0; + + while (*str) { + int cid=atoi(str); + + while(*str && (*str!=';' && *str!=',')) str++; + if (*str==';' || *str==',') str++; + + rid.push_back(cid); + n++; + } +} + +void oTeam::importRunners(const vector &rns) +{ + Runners.resize(rns.size()); + for (size_t n=0;n0) + Runners[n] = oe->getRunner(rns[n], 0); + else + Runners[n] = 0; + } +} + +void oTeam::importRunners(const vector &rns) +{ + // Unlink old runners + for (size_t k = rns.size(); ktInTeam == this) { + Runners[k]->tInTeam = 0; + Runners[k]->tLeg = 0; + } + } + + Runners.resize(rns.size()); + for (size_t n=0;ntInTeam == this) { + Runners[n]->tInTeam = 0; + Runners[n]->tLeg = 0; + } + } + Runners[n] = rns[n]; + } +} + + +void oEvent::removeTeam(int Id) +{ + oTeamList::iterator it; + for (it = Teams.begin(); it != Teams.end(); ++it) { + if (it->getId() == Id) { + if (HasDBConnection && !it->isRemoved()) + msRemove(&*it); + dataRevision++; + it->prepareRemove(); + Teams.erase(it); + teamById.erase(Id); + updateTabs(); + return; + } + } +} + +void oTeam::setRunner(unsigned i, pRunner r, bool sync) +{ + if (i>=Runners.size()) { + if (i>=0 && i<100) + Runners.resize(i+1); + else + throw std::exception("Bad runner index"); + } + + if (Runners[i]==r) + return; + + int oldRaceId = 0; + if (Runners[i]) { + oldRaceId = Runners[i]->getDCI().getInt("RaceId"); + Runners[i]->getDI().setInt("RaceId", 0); + } + setRunnerInternal(i, r); + + if (r) { + if (tStatus == StatusDNS) + setStatus(StatusUnknown, true, false); + r->getDI().setInt("RaceId", oldRaceId); + r->tInTeam=this; + r->tLeg=i; + r->createMultiRunner(true, sync); + } + + if (Class) { + int index=1; //Set multi runners + for (unsigned k=i+1;kgetNumStages(); k++) { + if (Class->getLegRunner(k)==i) { + if (r!=0) { + pRunner mr=r->getMultiRunner(index++); + + if (mr) { + mr->setName(r->getName(), true); + mr->synchronize(); + setRunnerInternal(k, mr); + } + } + else setRunnerInternal(k, 0); + } + } + } +} + +void oTeam::setRunnerInternal(int k, pRunner r) +{ + if (r==Runners[k]) { + if (r) { + r->tInTeam = this; + r->tLeg = k; + } + return; + } + + if (Runners[k]) { + assert(Runners[k]->tInTeam == 0 || Runners[k]->tInTeam == this); + Runners[k]->tInTeam = 0; + Runners[k]->tLeg = 0; + } + + // Reset old team + if (r && r->tInTeam) { + if (r->tInTeam->Runners[r->tLeg] != 0) { + r->tInTeam->Runners[r->tLeg] = 0; + r->tInTeam->updateChanged(); + if (r->tInTeam != this) + r->tInTeam->synchronize(true); + } + } + + Runners[k]=r; + + if (Runners[k]) { + Runners[k]->tInTeam = this; + Runners[k]->tLeg = k; + if (Class && Class->getLegType(k) != LTGroup) + Runners[k]->setClassId(getClassId(), false); + } + updateChanged(); +} + +string oTeam::getLegFinishTimeS(int leg) const +{ + if (leg==-1) + leg=Runners.size()-1; + + if (unsigned(leg)getFinishTimeS(); + else return "-"; +} + +int oTeam::getLegToUse(int leg) const { + if (Runners.empty()) + return 0; + if (leg==-1) + leg=Runners.size()-1; + int oleg = leg; + if (Class && !Runners[leg]) { + LegTypes lt = Class->getLegType(leg); + while (leg>=0 && (lt == LTParallelOptional || lt == LTExtra || lt == LTIgnore) && !Runners[leg]) { + if (leg == 0) + return oleg; //Suitable leg not found + leg--; + lt = Class->getLegType(leg); + } + } + return leg; +} + +int oTeam::getLegFinishTime(int leg) const +{ + leg = getLegToUse(leg); + //if (leg==-1) + //leg=Runners.size()-1; + + if (Class) { + pClass pc = Class; + LegTypes lt = pc->getLegType(leg); + while (leg> 0 && (lt == LTIgnore || + (lt == LTExtra && (!Runners[leg] || Runners[leg]->getFinishTime() <= 0)) ) ) { + leg--; + lt = pc->getLegType(leg); + } + } + + if (unsigned(leg)getFinishTime(); + if (Class) { + bool extra = Class->getLegType(leg) == LTExtra || + Class->getLegType(leg+1) == LTExtra; + + bool par = Class->isParallel(leg) || + Class->isParallel(leg+1); + + if (extra) { + ft = 0; + // Minimum over extra legs + int ileg = leg; + while (ileg > 0 && Class->getLegType(ileg) == LTExtra) + ileg--; + + while (size_t(ileg) < Class->getNumStages()) { + int ift = 0; + if (Runners[ileg]) { + ift = Runners[ileg]->getFinishTimeAdjusted(); + } + + if (ift > 0) { + if (ft == 0) + ft = ift; + else + ft = min(ft, ift); + } + + ileg++; + if (Class->getLegType(ileg) != LTExtra) + break; + } + } + else if (par) { + ft = 0; + // Maximum over parallel legs + int ileg = leg; + while (ileg > 0 && Class->isParallel(ileg)) + ileg--; + + while (size_t(ileg) < Class->getNumStages()) { + int ift = 0; + if (Runners[ileg]) { + ift = Runners[ileg]->getFinishTimeAdjusted(); + } + + if (ift > 0) { + if (ft == 0) + ft = ift; + else + ft = max(ft, ift); + } + + ileg++; + if (!Class->isParallel(ileg)) + break; + } + } + } + return ft; + } + else return 0; +} + +int oTeam::getRunningTime() const { + return getLegRunningTime(-1, false); +} + +int oTeam::getLegRunningTime(int leg, bool multidayTotal) const { + return getLegRunningTimeUnadjusted(leg, multidayTotal) + getTimeAdjustment(); +} + +int oTeam::getLegRestingTime(int leg) const { + if (!Class) + return 0; + + int rest = 0; + int R = min(Runners.size(), leg+1); + for (int k = 1; k < R; k++) { + if (Class->getStartType(k) == STHunting && !Class->isParallel(k) && + Runners[k] && Runners[k-1]) { + + int ft = getLegRunningTimeUnadjusted(k-1, false) + tStartTime; + int st = Runners[k]->getStartTime(); + + if (ft > 0 && st > 0) + rest += st - ft; + } + } + return rest; +} + + +int oTeam::getLegRunningTimeUnadjusted(int leg, bool multidayTotal) const { + leg = getLegToUse(leg); + + int addon = 0; + if (multidayTotal) + addon = inputTime; + + if (unsigned(leg)getLegType(leg); + LegTypes ltNext = pc->getLegType(leg+1); + if (ltNext == LTParallel || ltNext == LTParallelOptional || ltNext == LTExtra) // If the following leg is parallel, then so is this. + lt = ltNext; + + switch(lt) { + case LTNormal: + if (Runners[leg]->prelStatusOK()) { + int dt = leg>0 ? getLegRunningTimeUnadjusted(leg-1, false)+Runners[leg]->getRunningTime():0; + return addon + max(Runners[leg]->getFinishTimeAdjusted()-(tStartTime + getLegRestingTime(leg)), dt); + } + else return 0; + break; + + case LTParallelOptional: + case LTParallel: //Take the longest time of this runner and the previous + if (Runners[leg]->prelStatusOK()) { + int pt=leg>0 ? getLegRunningTimeUnadjusted(leg-1, false) : 0; + int rest = getLegRestingTime(leg); + int finishT = Runners[leg]->getFinishTimeAdjusted(); + return addon + max(finishT-(tStartTime + rest), pt); + } + else return 0; + break; + + case LTExtra: //Take the best time of this runner and the previous + if (leg==0) + return addon + max(Runners[leg]->getFinishTime()-tStartTime, 0); + else { + int baseLeg = leg; + while (baseLeg > 0 && pc->getLegType(baseLeg) == LTExtra) + baseLeg--; + int baseTime = 0; + if (baseLeg > 0) + baseTime = getLegRunningTimeUnadjusted(baseLeg-1, multidayTotal); + else + baseTime = addon; + + int cLeg = baseLeg; + int legTime = 0; + bool bad = false; + do { + if (Runners[cLeg] && Runners[cLeg]->getFinishTime() > 0) { + int rt = Runners[cLeg]->getRunningTime(); + if (legTime == 0 || rt < legTime) { + bad = !Runners[cLeg]->prelStatusOK(); + legTime = rt; + } + } + cLeg++; + } + while (pc->getLegType(cLeg) == LTExtra); + + if (bad || legTime == 0) + return 0; + else + return baseTime + legTime; + } + break; + + case LTSum: + if (Runners[leg]->prelStatusOK()) { + if (leg==0) + return addon + Runners[leg]->getRunningTime(); + else { + int prev = getLegRunningTimeUnadjusted(leg-1, multidayTotal); + if (prev == 0) + return 0; + else + return Runners[leg]->getRunningTime() + prev; + } + } + else return 0; + + case LTIgnore: + if (leg==0) + return 0; + else + return getLegRunningTimeUnadjusted(leg-1, multidayTotal); + + break; + + case LTGroup: + return 0; + } + } + else { + int dt=addon + max(Runners[leg]->getFinishTime()-tStartTime, 0); + int dt2=0; + + if (leg>0) + dt2=getLegRunningTimeUnadjusted(leg-1, multidayTotal)+Runners[leg]->getRunningTime(); + + return max(dt, dt2); + } + } + return 0; +} + +string oTeam::getLegRunningTimeS(int leg, bool multidayTotal) const +{ + if (leg==-1) + leg = Runners.size()-1; + + int rt=getLegRunningTime(leg, multidayTotal); + + if (rt>0) { + char bf[16]; + if (rt>=3600) + sprintf_s(bf, 16, "%d:%02d:%02d", rt/3600,(rt/60)%60, rt%60); + else + sprintf_s(bf, 16, "%d:%02d", (rt/60), rt%60); + + if ((unsigned(leg)getStartTime()==Class->getRestartTime(leg)) || getNumShortening(leg)>0) + return "*" + string(bf); + else + return bf; + } + return "-"; +} + + +RunnerStatus oTeam::getLegStatus(int leg, bool multidayTotal) const +{ + if (leg==-1) + leg=Runners.size()-1; + + if (unsigned(leg)>=Runners.size()) + return StatusUnknown; + + if (multidayTotal) { + RunnerStatus s = getLegStatus(leg, false); + if (s == StatusUnknown && inputStatus != StatusNotCompetiting) + return StatusUnknown; + if (inputStatus == StatusUnknown) + return StatusDNS; + return max(inputStatus, s); + } + + //Let the user specify a global team status disqualified. + if (leg == (Runners.size()-1) && tStatus==StatusDQ) + return tStatus; + + leg = getLegToUse(leg); // Ignore optional runners + + int s=0; + + if (!Class) + return StatusUnknown; + + while(leg>0 && Class->getLegType(leg)==LTIgnore) + leg--; + + for (int i=0;i<=leg;i++) { + // Ignore runners to be ignored + while(igetLegType(i)==LTIgnore) + i++; + + int st=Runners[i] ? Runners[i]->getStatus(): StatusDNS; + int bestTime=Runners[i] ? Runners[i]->getFinishTime():0; + + //When Type Extra is used, the runner with the best time + //is used for change. Then the status of this runner + //should be carried forward. + if (Class) while( (i+1) < int(Runners.size()) && Class->getLegType(i+1)==LTExtra) { + i++; + + if (Runners[i]) { + if (bestTime==0 || (Runners[i]->getFinishTime()>0 && + Runners[i]->getFinishTime()getStatus(); + bestTime = Runners[i]->getFinishTime(); + } + } + } + + if (st==0) + return RunnerStatus(s==StatusOK ? 0 : s); + + s=max(s, st); + } + + // Allow global status DNS + if (s==StatusUnknown && tStatus==StatusDNS) + return tStatus; + + return RunnerStatus(s); +} + +const string &oTeam::getLegStatusS(int leg, bool multidayTotal) const +{ + return oe->formatStatus(getLegStatus(leg, multidayTotal)); +} + +int oTeam::getLegPlace(int leg, bool multidayTotal) const { + if (Class) { + while(size_t(leg) < Class->legInfo.size() && Class->legInfo[leg].legMethod == LTIgnore) + leg--; + } + if (!multidayTotal) + return leg>=0 && leg=0 && leg0 && p<10000){ + sprintf_s(bf, "%d", p); + return bf; + } + return _EmptyString; +} + +string oTeam::getLegPrintPlaceS(int leg, bool multidayTotal, bool withDot) const +{ + int p=getLegPlace(leg, multidayTotal); + char bf[16]; + if (p>0 && p<10000){ + if (withDot) { + sprintf_s(bf, "%d.", p); + return bf; + } + else + return itos(p); + } + return _EmptyString; +} + +bool oTeam::compareResult(const oTeam &a, const oTeam &b) +{ + if (a.Class != b.Class) { + if (a.Class) { + if (b.Class) return a.Class->tSortIndex < b.Class->tSortIndex; + else return true; + } + else return false; + } + else if (a._sortStatus!=b._sortStatus) + return a._sortStatustSortIndextSortIndex; + else return true; + } + } + else if (a.tStartTime != b.tStartTime) + return a.tStartTime < b.tStartTime; + + const string &as = a.getBib(); + const string &bs = b.getBib(); + if (as != bs) { + return compareBib(as, bs); + } + + int aix = a.getDCI().getInt("SortIndex"); + int bix = b.getDCI().getInt("SortIndex"); + if (aix != bix) + return aix < bix; + + return CompareString(LOCALE_USER_DEFAULT, 0, + a.sName.c_str(), a.sName.length(), + b.sName.c_str(), b.sName.length()) == CSTR_LESS_THAN; +} + +bool oTeam::compareSNO(const oTeam &a, const oTeam &b) { + const string &as = a.getBib(); + const string &bs = b.getBib(); + + if (as != bs) { + return compareBib(as, bs); + } + else if (a.Class != b.Class) { + if (a.Class) { + if (b.Class) return a.Class->tSortIndextSortIndex; + else return true; + } + } + + return CompareString(LOCALE_USER_DEFAULT, 0, + a.sName.c_str(), a.sName.length(), + b.sName.c_str(), b.sName.length()) == CSTR_LESS_THAN; +} + + +bool oTeam::isRunnerUsed(int Id) const +{ + for(unsigned i=0;iId==Id) + return true; + } + return false; +} + +void oTeam::setTeamNoStart(bool dns) +{ + if (dns) { + setStatus(StatusDNS, true, false); + for(unsigned i=0;igetStatus()==StatusUnknown) { + Runners[i]->setStatus(StatusDNS, true, false); + } + } + } + else { + setStatus(StatusUnknown, true, false); + for(unsigned i=0;igetStatus()==StatusDNS) { + Runners[i]->setStatus(StatusUnknown, true, false); + } + } + } + // Do not sync here +} + +static void compressStartTimes(vector &availableStartTimes, int finishTime) +{ + for (size_t j=0; j &availableStartTimes, int finishTime) +{ + for (size_t k=0; k= availableStartTimes[k]) { + availableStartTimes.insert(availableStartTimes.begin()+k, finishTime); + return; + } + + availableStartTimes.push_back(finishTime); +} + +static int getBestStartTime(vector &availableStartTimes) { + if (availableStartTimes.empty()) + return 0; + int t = availableStartTimes.back(); + availableStartTimes.pop_back(); + return t; +} + +void oTeam::quickApply() { + if (unsigned(status) >= 100) + status = StatusUnknown; // Enforce valid + + if (Class && Runners.size()!=size_t(Class->getNumStages())) { + for (size_t k = Class->getNumStages(); k < Runners.size(); k++) { + if (Runners[k] && Runners[k]->tInTeam) { + Runners[k]->tInTeam = 0; + Runners[k]->tLeg = 0; + Runners[k]->tLegEquClass = 0; + if (Runners[k]->Class == Class) + Runners[k]->Class = 0; + Runners[k]->updateChanged(); + } + } + Runners.resize(Class->getNumStages()); + } + + for (size_t i = 0; i < Runners.size(); i++) { + if (Runners[i]) { + if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) { + Runners[i]->tInTeam->correctRemove(Runners[i]); + } + Runners[i]->tInTeam=this; + Runners[i]->tLeg=i; + } + } +} + + + +bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { + if (unsigned(status) >= 100) + status = StatusUnknown; // Enforce correct status + + int lastStartTime = 0; + RunnerStatus lastStatus = StatusUnknown; + bool freeStart = Class ? Class->hasFreeStart() : false; + int extraFinishTime = -1; + + if (Class && Runners.size()!=size_t(Class->getNumStages())) { + for (size_t k = Class->getNumStages(); k < Runners.size(); k++) { + if (Runners[k] && Runners[k]->tInTeam) { + Runners[k]->tInTeam = 0; + Runners[k]->tLeg = 0; + Runners[k]->tLegEquClass = 0; + if (Runners[k]->Class == Class) + Runners[k]->Class = 0; + Runners[k]->updateChanged(); + } + } + Runners.resize(Class->getNumStages()); + } + const string &bib = getBib(); + BibMode bibMode = (BibMode)-1; + tNumRestarts = 0; + vector availableStartTimes; + for (size_t i=0;i0 && source!=0 && Runners[i-1] == source) + return true; + if (!Runners[i] && Class) { + unsigned lr = Class->getLegRunner(i); + + if (lrcreateMultiRunner(false, sync); + int dup=Class->getLegRunnerIndex(i); + Runners[i]=Runners[lr]->getMultiRunner(dup); + } + } + + if (sync && Runners[i] && Class) { + unsigned lr = Class->getLegRunner(i); + if (lr == i && Runners[i]->tParentRunner) { + pRunner parent = Runners[i]->tParentRunner; + for (size_t kk = 0; kkmultiRunner.size(); ++kk) { + if (parent->multiRunner[kk] == Runners[i]) { + parent->multiRunner.erase(parent->multiRunner.begin() + kk); + Runners[i]->tParentRunner = 0; + Runners[i]->tDuplicateLeg = 0; + parent->markForCorrection(); + parent->updateChanged(); + Runners[i]->markForCorrection(); + Runners[i]->updateChanged(); + break; + } + } + } + } + // Avoid duplicates, same runner running more + // than one leg + //(note: quadric complexity, assume total runner count is low) + if (Runners[i]) { + for (size_t k=0;ktInTeam && Runners[i]->tInTeam!=this) { + Runners[i]->tInTeam->correctRemove(Runners[i]); + } + //assert(Runners[i]->tInTeam==0 || Runners[i]->tInTeam==this); + Runners[i]->tInTeam = this; + Runners[i]->tLeg = i; + if (Class) { + int unused; + Class->splitLegNumberParallel(i, Runners[i]->tLegEquClass, unused); + } + else { + Runners[i]->tLegEquClass = i; + } + + Runners[i]->setStartNo(StartNo, setTmpOnly); + if (!bib.empty() && Runners[i]->isChanged()) { + if (bibMode == -1 && Class) + bibMode = Class->getBibMode(); + if (bibMode == BibSame) + Runners[i]->setBib(bib, 0, false, setTmpOnly); + else if (bibMode == BibAdd) { + char pattern[32], bf[32]; + int ibib = oClass::extractBibPattern(bib, pattern) + i; + sprintf_s(bf, pattern, ibib); + Runners[i]->setBib(bf, 0, false, setTmpOnly); + } + else if (bibMode == BibLeg) { + string rbib = bib + "-" + Class->getLegNumber(i); + Runners[i]->setBib(rbib, 0, false, setTmpOnly); + } + } + LegTypes legType = Class ? Class->getLegType(i) : LTIgnore; + + if (Runners[i]->Class!=Class && legType != LTGroup) { + Runners[i]->Class=Class; + Runners[i]->updateChanged(); + } + + Runners[i]->tNeedNoCard=false; + if (Class) { + pClass pc=Class; + + //Ignored runners need no SI-card (used by SI assign function) + if (legType == LTIgnore) { + Runners[i]->tNeedNoCard=true; + if (lastStatus != StatusUnknown) { + Runners[i]->setStatus(max(Runners[i]->tStatus, lastStatus), false, setTmpOnly); + } + } + else + lastStatus = Runners[i]->getStatus(); + + StartTypes st = pc->getStartType(i); + LegTypes lt = legType; + + if ((lt==LTParallel || lt==LTParallelOptional) && i==0) { + pc->setLegType(0, LTNormal); + throw std::exception("Första sträckan kan inte vara parallell."); + } + if (lt==LTIgnore || lt==LTExtra) { + if (st != STDrawn) + Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); + Runners[i]->tUseStartPunch = (st == STDrawn); + } + else { //Calculate start time. + switch (st) { + case STDrawn: //Do nothing + if (lt==LTParallel || lt==LTParallelOptional) { + Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); + Runners[i]->tUseStartPunch=false; + } + else + lastStartTime = Runners[i]->getStartTime(); + + break; + + case STTime: { + bool prs = false; + if (Runners[i] && Runners[i]->Card && freeStart) { + pCourse crs = Runners[i]->getCourse(false); + int startType = crs ? crs->getStartPunchType() : oPunch::PunchStart; + oPunch *pnc = Runners[i]->Card->getPunchByType(startType); + if (pnc && pnc->getAdjustedTime() > 0) { + prs = true; + lastStartTime = pnc->getAdjustedTime(); + } + } + if (!prs) { + if (lt==LTNormal || lt==LTSum || lt == LTGroup) + lastStartTime=pc->getStartData(i); + + Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); + Runners[i]->tUseStartPunch=false; + } + } + break; + + case STChange: { + int probeIndex = 1; + int startData = pc->getStartData(i); + + if (startData < 0) { + // A specified leg + probeIndex = -startData; + } + else { + // Allow for empty slots when ignore/extra + while ((i-probeIndex)>=0 && !Runners[i-probeIndex]) { + LegTypes tlt = pc->getLegType(i-probeIndex); + if (tlt == LTIgnore || tlt==LTExtra || tlt == LTGroup) + probeIndex++; + else + break; + } + } + + if ( (i-probeIndex)>=0 && Runners[i-probeIndex]) { + int z = i-probeIndex; + LegTypes tlt = pc->getLegType(z); + int ft = 0; + if (availableStartTimes.empty() || startData < 0) { + + if (!availableStartTimes.empty()) { + // Parallel, but there is a specification. Take one from parallel anyway. + ft = getBestStartTime(availableStartTimes); + } + + //We are not involved in parallel legs + ft = (tlt != LTIgnore) ? Runners[z]->getFinishTime() : 0; + + // Take the best time for extra runners + while (z>0 && (tlt==LTExtra || tlt==LTIgnore)) { + tlt = pc->getLegType(--z); + if (Runners[z] && Runners[z]->getStatus() == StatusOK) { + int tft = Runners[z]->getFinishTime(); + if (tft>0 && tlt != LTIgnore) + ft = ft>0 ? min(tft, ft) : tft; + } + } + } + else { + ft = getBestStartTime(availableStartTimes); + } + + if (ft<=0) + ft=0; + + int restart=pc->getRestartTime(i); + int rope=pc->getRopeTime(i); + + if ((restart>0 && rope>0 && (ft==0 || ft>rope)) || (ft == 0 && restart>0)) { + ft=restart; //Runner in restart + tNumRestarts++; + } + + if (ft > 0) + Runners[i]->setStartTime(ft, false, setTmpOnly); + Runners[i]->tUseStartPunch=false; + lastStartTime=ft; + } + else {//The else below should only be run by mistake (for an incomplete team) + Runners[i]->setStartTime(Class->getRestartTime(i), false, setTmpOnly); + Runners[i]->tUseStartPunch=false; + //Runners[i]->setStatus(StatusDNS); + } + } + break; + + case STHunting: { + bool setStart = false; + if (i>0 && Runners[i-1]) { + if (lt == LTNormal || lt == LTSum || availableStartTimes.empty()) { + int rt = getLegRunningTimeUnadjusted(i-1, false); + + if (rt>0) + setStart = true; + int leaderTime = pc->getTotalLegLeaderTime(i-1, false); + int timeAfter = leaderTime > 0 ? rt - leaderTime : 0; + + if (rt>0 && timeAfter>=0) + lastStartTime=pc->getStartData(i)+timeAfter; + + int restart=pc->getRestartTime(i); + int rope=pc->getRopeTime(i); + + RunnerStatus hst = getLegStatus(i-1, false); + if (hst != StatusUnknown && hst != StatusOK) { + setStart = true; + lastStartTime = restart; + } + + if (restart>0 && rope>0 && (lastStartTime>rope)) { + lastStartTime=restart; //Runner in restart + tNumRestarts++; + } + if (!availableStartTimes.empty()) { + // Single -> to parallel pursuit + if (setStart) + fill(availableStartTimes.begin(), availableStartTimes.end(), lastStartTime); + else + fill(availableStartTimes.begin(), availableStartTimes.end(), 0); + + availableStartTimes.pop_back(); // Used one + } + } + else if (lt == LTParallel || lt == LTParallelOptional) { + lastStartTime = getBestStartTime(availableStartTimes); + setStart = true; + } + + if (Runners[i]->getFinishTime()>0) { + setStart = true; + if (lastStartTime == 0) + lastStartTime = pc->getRestartTime(i); + } + if (!setStart) + lastStartTime=0; + } + else + lastStartTime=0; + + Runners[i]->tUseStartPunch=false; + Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); + } + break; + } + } + + size_t nextNonPar = i+1; + while (nextNonPar < Runners.size() && pc->isOptional(nextNonPar) && Runners[nextNonPar] == 0) + nextNonPar++; + + int nextBaseLeg = nextNonPar; + while (nextNonPar < Runners.size() && pc->isParallel(nextNonPar)) + nextNonPar++; + + // Extra finish time is used to split extra legs to parallel legs + if (lt == LTExtra || pc->getLegType(i+1) == LTExtra) { + if (Runners[i]->getFinishTime()>0) { + if (extraFinishTime <= 0) + extraFinishTime = Runners[i]->getFinishTime(); + else + extraFinishTime = min(extraFinishTime, Runners[i]->getFinishTime()); + } + } + else + extraFinishTime = -1; + + //Add available start times for parallel + if (nextNonPar < Runners.size()) { + st=pc->getStartType(nextNonPar); + int finishTime = Runners[i]->getFinishTime(); + if (lt == LTExtra) + finishTime = extraFinishTime; + + if (st==STDrawn || st==STTime) + availableStartTimes.clear(); + else if (finishTime>0) { + int nRCurrent = pc->getNumParallel(i); + int nRNext = pc->getNumParallel(nextBaseLeg); + if (nRCurrent>1 || nRNext>1) { + if (nRCurrentsynchronize(true); + } + } + + if (!Runners.empty() && Runners[0]) { + if (setTmpOnly) + setStartTime(Runners[0]->tmpStore.startTime, false, setTmpOnly); + else + setStartTime(Runners[0]->getStartTime(), false, setTmpOnly); + } + else if (Class && Class->getStartType(0) != STDrawn) + setStartTime(Class->getStartData(0), false, setTmpOnly); + + setFinishTime(getLegFinishTime(-1)); + setStatus(getLegStatus(-1, false), false, setTmpOnly); //XXX Maybe getLegStatus needs to work agains tmp store? + + if (sync) + synchronize(true); + return true; +} + +void oTeam::evaluate(bool sync) +{ + for(unsigned i=0;iresetTmpStore(); + } + resetTmpStore(); + + apply(false, 0, true); + vector mp; + for(unsigned i=0;ievaluateCard(false, mp); + } + apply(false, 0, true); + + for(unsigned i=0;isetTmpStore(); + if (sync) + Runners[i]->synchronize(true); + } + } + setTmpStore(); + if (sync) + synchronize(true); +} + +void oTeam::correctRemove(pRunner r) { + for(unsigned i=0;itInTeam = 0; + r->tLeg = 0; + r->tLegEquClass = 0; + correctionNeeded = true; + r->correctionNeeded = true; + } +} + +void oTeam::speakerLegInfo(int leg, int specifiedLeg, int courseControlId, + int &missingLeg, int &totalLeg, + RunnerStatus &status, int &runningTime) const { + missingLeg = 0; + totalLeg = 0; + bool extra = false, firstExtra = true; + for (int i = leg; i <= specifiedLeg; i++) { + LegTypes lt=Class->getLegType(i); + if (lt == LTExtra) + extra = true; + + if (lt == LTSum || lt == LTNormal || lt == LTParallel || lt == LTParallelOptional || lt == LTExtra) { + int lrt = 0; + RunnerStatus lst = StatusUnknown; + if (Runners[i]) { + Runners[i]->getSplitTime(courseControlId, lst, lrt); + totalLeg++; + } + else if (lt == LTParallelOptional) { + lst = StatusOK; // No requrement + } + else if (!extra) { + totalLeg++; // will never reach... + } + + if (extra) { + // Extra legs, take best result + if (firstExtra && i > 0 && !Runners[i-1]) { + missingLeg = 0; + totalLeg = 0; + } + firstExtra = false; + if (lrt>0 && (lrt < runningTime || runningTime == 0)) { + runningTime = lrt; + status = lst; // Take status/time from best runner + } + if (Runners[i] && lst == StatusUnknown) + missingLeg++; + } + else { + if (lst > StatusOK) { + status = lst; + break; + } + else if (lst == StatusUnknown) { + missingLeg++; + } + else { + runningTime = max(lrt, runningTime); + } + } + } + } + + if (missingLeg == 0 && status == StatusUnknown) + status = StatusOK; +} + +void oTeam::fillSpeakerObject(int leg, int courseControlId, int previousControlCourseId, + bool totalResult, oSpeakerObject &spk) const { + if (leg==-1) + leg = Runners.size()-1; + + spk.club = getName(); + spk.missingStartTime = true; + //Defaults (if early return) + + if (totalResult && inputStatus > StatusOK) + spk.status = spk.finishStatus = inputStatus; + else + spk.status = spk.finishStatus = StatusUnknown; + + if (!Class || unsigned(leg) >= Runners.size()) + return; + + // Ignore initial optional and not used legs + while (leg > 0 && !Runners[leg]) { + Class->isOptional(leg); + leg--; + } + + if (!Runners[leg]) + return; + + // Get many names for paralell legs + int firstLeg = leg; + int requestedLeg = leg; + LegTypes lt=Class->getLegType(firstLeg--); + while(firstLeg>=0 && (lt==LTIgnore || lt==LTParallel || lt==LTParallelOptional || lt==LTExtra) ) + lt=Class->getLegType(firstLeg--); + + spk.names.clear(); + for(int k=firstLeg+1;k<=leg;k++) { + if (Runners[k]) { + const string &n = Runners[k]->getName(); + spk.names.push_back(n); + } + } + // Add start number + spk.bib = getBib(); + + if (courseControlId == 2) { + unsigned nextLeg = leg + 1; + while (nextLeg < Runners.size()) { + if (Runners[nextLeg]) + spk.outgoingnames.push_back(Runners[nextLeg]->getName()); + + nextLeg++; + if (nextLeg < Runners.size()) { + LegTypes lt=Class->getLegType(nextLeg); + if (!(lt==LTIgnore || lt==LTParallel || lt==LTParallelOptional || lt==LTExtra)) + break; + } + } + } + + int specifiedLeg = leg; + leg = firstLeg+1; //This does not work well with parallel or extra... + while (!Runners[leg]) // Ensure the leg is set + leg++; + + int missingLeg = 0; + + int timeOffset=0; + RunnerStatus inheritStatus = StatusUnknown; + if (firstLeg>=0) { + timeOffset = getLegRunningTime(firstLeg, totalResult); + inheritStatus = getLegStatus(firstLeg, totalResult); + } + else if (totalResult) { + timeOffset = getInputTime(); + inheritStatus = getInputStatus(); + } + + speakerLegInfo(leg, specifiedLeg, courseControlId, + missingLeg, spk.runnersTotalLeg, spk.status, spk.runningTimeLeg.time); + + spk.runnersFinishedLeg = spk.runnersTotalLeg - missingLeg; + if (spk.runnersTotalLeg > 1) { + spk.parallelScore = (spk.runnersFinishedLeg * 100) / spk.runnersTotalLeg; + } + if (previousControlCourseId > 0 && spk.status <= 1 && Class->getStartType(0) == STTime) { + spk.useSinceLast = true; + RunnerStatus pStat = StatusUnknown; + int lastTime = 0; + int dummy; + speakerLegInfo(leg, specifiedLeg, previousControlCourseId, + missingLeg, dummy, pStat, lastTime); + + if (pStat == StatusOK) { + if (spk.runningTimeLeg.time > 0) { + spk.runningTimeSinceLast.time = spk.runningTimeLeg.time - lastTime; + spk.runningTimeSinceLast.preliminary = spk.runningTimeSinceLast.time; + } + else if (spk.runningTimeLeg.time == 0) { + spk.runningTimeSinceLast.preliminary = oe->getComputerTime() - lastTime; + //string db = Name + " " + itos(lastTime) + " " + itos(spk.runningTimeSinceLast.preliminary) +"\n"; + //OutputDebugString(db.c_str()); + } + } + } + + spk.timeSinceChange = oe->getComputerTime() - (spk.runningTimeLeg.time + Runners[leg]->tStartTime); + + spk.owner=Runners[leg]; + spk.finishStatus=getLegStatus(specifiedLeg, totalResult); + + spk.missingStartTime = false; + int stMax = 0; + for (int i = leg; i <= requestedLeg; i++) { + if (!Runners[i]) + continue; + if (Class->getLegType(i) == LTIgnore || Class->getLegType(i) == LTGroup) + continue; + + int st=Runners[i]->getStartTime(); + if (st <= 0) + spk.missingStartTime = true; + else { + if (st > stMax) { + spk.startTimeS = Runners[i]->getStartTimeCompact(); + stMax = st; + } + } + } + + map::iterator mapit=Runners[leg]->priority.find(courseControlId); + if (mapit!=Runners[leg]->priority.end()) + spk.priority=mapit->second; + else + spk.priority=0; + + spk.runningTimeLeg.preliminary = 0; + for (int i = leg; i <= requestedLeg; i++) { + if (!Runners[i]) + continue; + int pt = Runners[i]->getPrelRunningTime(); + if (Class->getLegType(i) == LTParallel) + spk.runningTimeLeg.preliminary = max(spk.runningTimeLeg.preliminary, pt); + else if (Class->getLegType(i) == LTExtra) { + if (spk.runningTimeLeg.preliminary == 0) + spk.runningTimeLeg.preliminary = pt; + else if (pt > 0) + spk.runningTimeLeg.preliminary = min(spk.runningTimeLeg.preliminary, pt); + } + else + spk.runningTimeLeg.preliminary = pt; + } + + if (inheritStatus>StatusOK) + spk.status=inheritStatus; + + if (spk.status==StatusOK) { + if (courseControlId == 2) + spk.runningTime.time = getLegRunningTime(requestedLeg, totalResult); // Get official time + + if (spk.runningTime.time == 0) + spk.runningTime.time = spk.runningTimeLeg.time + timeOffset; //Preliminary time + + spk.runningTime.preliminary = spk.runningTime.time; + spk.runningTimeLeg.preliminary = spk.runningTimeLeg.time; + } + else if (spk.status==StatusUnknown && spk.finishStatus==StatusUnknown) { + spk.runningTime.time = spk.runningTimeLeg.preliminary + timeOffset; + spk.runningTime.preliminary = spk.runningTimeLeg.preliminary + timeOffset; + spk.runningTimeLeg.time = spk.runningTimeLeg.preliminary; + } + else if (spk.status==StatusUnknown) + spk.status=StatusMP; + + if (totalResult && inputStatus != StatusOK) + spk.status = spk.finishStatus; +} + +int oTeam::getTimeAfter(int leg) const +{ + if (leg==-1) + leg=Runners.size()-1; + + if (!Class || Class->tLeaderTime.size()<=unsigned(leg)) + return -1; + + int t=getLegRunningTime(leg, false); + + if (t<=0) + return -1; + + return t-Class->getTotalLegLeaderTime(leg, false); +} + +int oTeam::getLegStartTime(int leg) const +{ + if (leg==0) + return tStartTime; + else if (unsigned(leg)getStartTime(); + else return 0; +} + +string oTeam::getLegStartTimeS(int leg) const +{ + int s=getLegStartTime(leg); + if (s>0) + return oe->getAbsTime(s); + else return "-"; +} + +string oTeam::getLegStartTimeCompact(int leg) const +{ + int s=getLegStartTime(leg); + if (s>0) + if (oe->useStartSeconds()) + return oe->getAbsTime(s); + else + return oe->getAbsTimeHM(s); + + else return "-"; +} + +void oTeam::setBib(const string &bib, int bibnumerical, bool updateStartNo, bool setTmpOnly) { + if (setTmpOnly) { + tmpStore.bib = bib; + if (updateStartNo) + setStartNo(bibnumerical, true); + return; + } + + if (getDI().setString("Bib", bib)) { + if (oe) + oe->bibStartNoToRunnerTeam.clear(); + } + + if (updateStartNo) { + setStartNo(bibnumerical, false); + } +} + +oDataContainer &oTeam::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { + data = (pvoid)oData; + olddata = (pvoid)oDataOld; + strData = 0; + return *oe->oTeamData; +} + +pRunner oTeam::getRunner(unsigned leg) const +{ + if (leg==-1) + leg=Runners.size()-1; + + return legtRogainingPoints; + } + } + else { + std::set rogainingControls; + for (size_t k = 0; k < Runners.size(); k++) { + if (Runners[k]) { + pCard c = Runners[k]->getCard(); + pCourse crs = Runners[k]->getCourse(true); + if (c && crs) { + for (oPunchList::const_iterator it = c->punches.begin(); it != c->punches.end();++it) { + if (rogainingControls.count(it->tMatchControlId) == 0) { + rogainingControls.insert(it->tMatchControlId); + pt += it->tRogainingPoints; + } + } + } + } + } + } + pt = max(pt - getRogainingReduction(), 0); + // Manual point adjustment + pt = max(0, pt + getPointAdjustment()); + + if (multidayTotal) + return pt + inputPoints; + return pt; +} + +int oTeam::getRogainingOvertime() const { + int overTime = 0; + for (size_t k = 0; k < Runners.size(); k++) { + if (Runners[k]) { + overTime += Runners[k]->tRogainingOvertime; + } + } + return overTime; +} + +int oTeam::getRogainingPointsGross() const { + int gross = 0; + for (size_t k = 0; k < Runners.size(); k++) { + if (Runners[k]) { + gross += Runners[k]->tRogainingPointsGross; + } + } + return gross; +} + + +int oTeam::getRogainingReduction() const { + pCourse sampleCourse = 0; + int overTime = 0; + for (size_t k = 0; k < Runners.size(); k++) { + if (Runners[k]) { + if (sampleCourse == 0 &&(Runners[k]->tRogainingPoints > 0 || Runners[k]->tReduction > 0)) + sampleCourse = Runners[k]->getCourse(false); + overTime += Runners[k]->tRogainingOvertime; + } + } + return sampleCourse->calculateReduction(overTime); +} + +void oTeam::remove() +{ + if (oe) + oe->removeTeam(Id); +} + +bool oTeam::canRemove() const +{ + return true; +} + +string oTeam::getDisplayName() const { + if (!Class) + return sName; + + ClassType ct = Class->getClassType(); + if (ct == oClassIndividRelay || ct == oClassPatrol) { + if (Club) { + string cname = getDisplayClub(); + if (!cname.empty()) + return cname; + } + } + return sName; +} + +string oTeam::getDisplayClub() const { + vector clubs; + if (Club) + clubs.push_back(Club); + for (size_t k = 0; kClub) { + if (count(clubs.begin(), clubs.end(), Runners[k]->Club) == 0) + clubs.push_back(Runners[k]->Club); + } + } + if (clubs.size() == 1) + return clubs[0]->getDisplayName(); + + string res; + for (size_t k = 0; kgetDisplayName(); + else + res += " / " + clubs[k]->getDisplayName(); + } + return res; +} + +void oTeam::setInputData(const oTeam &t) { + inputTime = t.getTotalRunningTime(); + inputStatus = t.getTotalStatus(); + inputPoints = t.getRogainingPoints(true); + int tp = t.getTotalPlace(); + inputPlace = tp < 99000 ? tp : 0; + + oDataInterface dest = getDI(); + oDataConstInterface src = t.getDCI(); + + dest.setInt("TransferFlags", src.getInt("TransferFlags")); + + dest.setString("Nationality", src.getString("Nationality")); + dest.setString("Country", src.getString("Country")); + dest.setInt("Fee", src.getInt("Fee")); + dest.setInt("Paid", src.getInt("Paid")); + dest.setInt("Taxable", src.getInt("Taxable")); +} + +RunnerStatus oTeam::getTotalStatus() const { + if (tStatus == StatusUnknown) + return StatusUnknown; + else if (inputStatus == StatusUnknown) + return StatusDNS; + + return max(tStatus, inputStatus); +} + +void oEvent::getTeams(int classId, vector &t, bool sort) { + if (sort) { + synchronizeList(oLTeamId); + //sortTeams(SortByName); + } + t.clear(); + if (Classes.size() > 0) + t.reserve((Teams.size()*min(Classes.size(), 4)) / Classes.size()); + + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved()) + continue; + + if (classId == 0 || it->getClassId() == classId) + t.push_back(&*it); + } +} + +string oTeam::getEntryDate(bool dummy) const { + oDataConstInterface dci = getDCI(); + int date = dci.getInt("EntryDate"); + if (date == 0) { + (const_cast(this)->getDI()).setDate("EntryDate", getLocalDate()); + } + return dci.getDate("EntryDate"); +} + +unsigned static nRunnerMaxStored = -1; + +Table *oEvent::getTeamsTB() //Table mode +{ + + vector cls; + oe->getClasses(cls, true); + unsigned nRunnerMax = 0; + for (size_t k = 0; k < cls.size(); k++) { + nRunnerMax = max(nRunnerMax, cls[k]->getNumStages()); + } + + bool forceUpdate = nRunnerMax != nRunnerMaxStored; + + if (forceUpdate && tables.count("team")) { + tables["team"]->releaseOwnership(); + tables.erase("team"); + } + + if (tables.count("team") == 0) { + + oCardList::iterator it; + + Table *table=new Table(this, 20, "Lag(flera)", "teams"); + + table->addColumn("Id", 70, true, true); + table->addColumn("Ändrad", 70, false); + + table->addColumn("Namn", 200, false); + table->addColumn("Klass", 120, false); + table->addColumn("Klubb", 120, false); + + table->addColumn("Start", 70, false, true); + table->addColumn("Mål", 70, false, true); + table->addColumn("Status", 70, false); + table->addColumn("Tid", 70, false, true); + + table->addColumn("Plac.", 70, true, true); + table->addColumn("Start nr.", 70, true, false); + + for (unsigned k = 0; k < nRunnerMax; k++) { + table->addColumn("Sträcka X#" + itos(k+1), 200, false, false); + table->addColumn("Bricka X#" + itos(k+1), 70, true, true); + } + nRunnerMaxStored = nRunnerMax; + + oe->oTeamData->buildTableCol(table); + + table->addColumn("Tid in", 70, false, true); + table->addColumn("Status in", 70, false, true); + table->addColumn("Poäng in", 70, true); + table->addColumn("Placering in", 70, true); + + tables["team"] = table; + table->addOwnership(); + } + + tables["team"]->update(); + return tables["team"]; +} + + +void oEvent::generateTeamTableData(Table &table, oTeam *addTeam) +{ + vector cls; + oe->getClasses(cls, true); + unsigned nRunnerMax = 0; + + for (size_t k = 0; k < cls.size(); k++) { + nRunnerMax = max(nRunnerMax, cls[k]->getNumStages()); + } + + if (nRunnerMax != nRunnerMaxStored) + throw meosException("Internal table error: Restart MeOS"); + + if (addTeam) { + addTeam->addTableRow(table); + return; + } + + synchronizeList(oLTeamId); + oTeamList::iterator it; + table.reserve(Teams.size()); + for (it=Teams.begin(); it != Teams.end(); ++it){ + if (!it->skip()){ + it->addTableRow(table); + } + } +} + +void oTeam::addTableRow(Table &table) const { + oRunner &it = *pRunner(this); + table.addRow(getId(), &it); + + int row = 0; + table.set(row++, it, TID_ID, itos(getId()), false); + table.set(row++, it, TID_MODIFIED, getTimeStamp(), false); + + table.set(row++, it, TID_NAME, getName(), true); + table.set(row++, it, TID_CLASSNAME, getClass(), true, cellSelection); + table.set(row++, it, TID_CLUB, getClub(), true, cellCombo); + + table.set(row++, it, TID_START, getStartTimeS(), true); + table.set(row++, it, TID_FINISH, getFinishTimeS(), true); + table.set(row++, it, TID_STATUS, getStatusS(), true, cellSelection); + table.set(row++, it, TID_RUNNINGTIME, getRunningTimeS(), false); + + table.set(row++, it, TID_PLACE, getPlaceS(), false); + table.set(row++, it, TID_STARTNO, itos(getStartNo()), true); + + for (unsigned k = 0; k < nRunnerMaxStored; k++) { + pRunner r = getRunner(k); + if (r) { + table.set(row++, it, 100+2*k, r->getUIName(), r->getRaceNo() == 0); + table.set(row++, it, 101+2*k, itos(r->getCardNo()), true); + } + else { + table.set(row++, it, 100+2*k, "", Class && Class->getLegRunner(k) == k); + table.set(row++, it, 101+2*k, "", false); + } + } + + row = oe->oTeamData->fillTableCol(it, table, true); + + table.set(row++, it, TID_INPUTTIME, getInputTimeS(), true); + table.set(row++, it, TID_INPUTSTATUS, getInputStatusS(), true, cellSelection); + table.set(row++, it, TID_INPUTPOINTS, itos(inputPoints), true); + table.set(row++, it, TID_INPUTPLACE, itos(inputPlace), true); +} + +bool oTeam::inputData(int id, const string &input, + int inputId, string &output, bool noUpdate) +{ + int s,t; + synchronize(false); + + if (id>1000) { + return oe->oTeamData->inputData(this, id, input, + inputId, output, noUpdate); + } + else if (id >= 100) { + + bool isName = (id&1) == 0; + size_t ix = (id-100)/2; + if (ix < Runners.size()) { + if (Runners[ix]) { + if (isName) { + if (input.empty()) { + removeRunner(oe->gdibase, false, ix); + } + else { + Runners[ix]->setName(input, true); + Runners[ix]->synchronize(true); + output = Runners[ix]->getName(); + } + } + else { + Runners[ix]->setCardNo(atoi(input.c_str()), true); + Runners[ix]->synchronize(true); + output = itos(Runners[ix]->getCardNo()); + } + } + else { + if (isName && !input.empty() && Class) { + pRunner r = oe->addRunner(input, getClubId(), getClassId(), 0, 0, false); + setRunner(ix, r, true); + output = r->getName(); + } + + } + } + } + + switch(id) { + + case TID_NAME: + setName(input, true); + synchronize(true); + output = getName(); + break; + + case TID_START: + setStartTimeS(input); + if (getRunner(0)) + getRunner(0)->setStartTimeS(input); + t=getStartTime(); + apply(false, 0, false); + s=getStartTime(); + if (s!=t) + throw std::exception("Starttiden är definerad genom klassen eller löparens startstämpling."); + synchronize(true); + output=getStartTimeS(); + return true; + break; + + case TID_CLUB: + { + pClub pc = 0; + if (inputId > 0) + pc = oe->getClub(inputId); + else + pc = oe->getClubCreate(0, input); + + setClub(pc ? pc->getName() : ""); + synchronize(true); + output = getClub(); + } + break; + + case TID_CLASSNAME: + setClassId(inputId, true); + synchronize(true); + output = getClass(); + break; + + case TID_STATUS: { + RunnerStatus sIn = RunnerStatus(inputId); + if (sIn != StatusDNS) { + if (getStatus() == StatusDNS && sIn == StatusUnknown) + setTeamNoStart(false); + else + setStatus(sIn, true, false); + } + else if (getStatus() != StatusDNS) + setTeamNoStart(true); + + apply(true, 0, false); + RunnerStatus sOut = getStatus(); + if (sOut != sIn) + throw meosException("Status matchar inte deltagarnas status."); + output = getStatusS(); + } + break; + + case TID_STARTNO: + setStartNo(atoi(input.c_str()), false); + synchronize(true); + output = itos(getStartNo()); + break; + + case TID_INPUTSTATUS: + setInputStatus(RunnerStatus(inputId)); + synchronize(true); + output = getInputStatusS(); + break; + + case TID_INPUTTIME: + setInputTime(input); + synchronize(true); + output = getInputTimeS(); + break; + + case TID_INPUTPOINTS: + setInputPoints(atoi(input.c_str())); + synchronize(true); + output = itos(getInputPoints()); + break; + + case TID_INPUTPLACE: + setInputPlace(atoi(input.c_str())); + synchronize(true); + output = itos(getInputPlace()); + break; + + } + return false; +} + +void oTeam::fillInput(int id, vector< pair > &out, size_t &selected) +{ + if (id>1000) { + oe->oRunnerData->fillInput(oData, id, 0, out, selected); + return; + } + else if (id==TID_CLASSNAME) { + oe->fillClasses(out, oEvent::extraNone, oEvent::filterOnlyMulti); + out.push_back(make_pair(lang.tl("Ingen klass"), 0)); + selected = getClassId(); + } + else if (id==TID_CLUB) { + oe->fillClubs(out); + out.push_back(make_pair(lang.tl("Klubblös"), 0)); + selected = getClubId(); + } + else if (id==TID_STATUS || id==TID_INPUTSTATUS) { + oe->fillStatus(out); + selected = getStatus(); + } +} + +void oTeam::removeRunner(gdioutput &gdi, bool askRemoveRunner, int i) { + pRunner p_old = getRunner(i); + setRunner(i, 0, true); + + //Remove multi runners + if (Class) { + for (unsigned k = i+1;k < Class->getNumStages(); k++) { + if (Class->getLegRunner(k)==i) + setRunner(k, 0, true); + } + } + + //No need to delete multi runners. Disappears when parent is gone. + if (p_old && !oe->isRunnerUsed(p_old->getId())){ + if (!askRemoveRunner || gdi.ask("Ska X raderas från tävlingen?#" + p_old->getName())){ + vector oldR; + oldR.push_back(p_old->getId()); + oe->removeRunner(oldR); + } + else { + p_old->getDI().setInt("RaceId", 0); // Clear race id. + p_old->setClassId(0, false); // Clear class + p_old->synchronize(true); + } + } +} + +int oTeam::getTeamFee() const { + int f = getDCI().getInt("Fee"); + for (size_t k = 0; k < Runners.size(); k++) { + if (Runners[k]) + f += Runners[k]->getDCI().getInt("Fee"); + } + return f; +} + +void oTeam::markClassChanged(int controlId) { + if (Class) + Class->markSQLChanged(-1, controlId); +} + +void oTeam::resetResultCalcCache() const { + resultCalculationCache.resize(RCCLast); + for (int k = 0; k < RCCLast; k++) + resultCalculationCache[k].resize(Runners.size()); +} + +vector< vector > &oTeam::getResultCache(ResultCalcCacheSymbol symb) const { + return resultCalculationCache[symb]; +} + +void oTeam::setResultCache(ResultCalcCacheSymbol symb, int leg, vector &data) const { + if (!resultCalculationCache.empty() && size_t(leg) < resultCalculationCache[symb].size()) + resultCalculationCache[symb][leg].swap(data); +} + +int oTeam::getNumShortening() const { + return getNumShortening(-1); +} + +int oTeam::getNumShortening(int leg) const { + int ns = 0; + if (Class) { + for (size_t k = 0; k < Runners.size() && k <= size_t(leg); k++) { + if (Runners[k] && !Class->isOptional(k)) + ns += Runners[k]->getNumShortening(); + } + } + else { + for (size_t k = 0; k < Runners.size() && k <= size_t(leg); k++) { + if (Runners[k]) + ns += Runners[k]->getNumShortening(); + } + } + return ns; +} + +bool oTeam::checkValdParSetup() { + if (!Class) + return false; + bool cor = false; + for (size_t k = 0; k < Runners.size(); k++) { + if (!Class->isOptional(k) && !Class->isParallel(k) && !Runners[k]) { + int m = 1; + while((m+k) < Runners.size() && (Class->isOptional(k+m) || Class->isParallel(k+m))) { + if (Runners[m+k]) { + // Move to where a runner is needed + Runners[k] = Runners[k+m]; + Runners[k]->tLeg = k; + Runners[k+m] = 0; + updateChanged(); + cor = true; + k+=m; + break; + } + else + m++; + } + } + } + return cor; +} + + +int oTeam::getRanking() const { + for (size_t k = 0; k < Runners.size(); k++) { + if (Runners[k]) { + return Runners[k]->getRanking(); + } + } + return MaxRankingConstant; +} \ No newline at end of file diff --git a/code/oTeam.h b/code/oTeam.h new file mode 100644 index 0000000..e475b92 --- /dev/null +++ b/code/oTeam.h @@ -0,0 +1,221 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "oBase.h" +#include "oRunner.h" + +class oTeam;//:public oBase {}; +typedef oTeam* pTeam; +typedef const oTeam* cTeam; + +const unsigned int maxRunnersTeam=32; + +class oTeam : public oAbstractRunner +{ +public: + enum ResultCalcCacheSymbol { + RCCCourse, + RCCSplitTime, + RCCCardTimes, + RCCCardPunches, + RCCCardControls, + RCCLast + }; + +private: + int getLegRunningTimeUnadjusted(int leg, bool multidayTotal) const; + /** Return the total time the team has been resting (pursuit start etc.) up to the specified leg */ + int getLegRestingTime(int leg) const; + + void speakerLegInfo(int leg, int specifiedLeg, int courseControlId, + int &missingLeg, int &totalLeg, + RunnerStatus &status, int &runningTime) const; + +protected: + //pRunner Runners[maxRunnersTeam]; + vector Runners; + void setRunnerInternal(int k, pRunner r); + + static const int dataSize = 96; + int getDISize() const {return dataSize;} + BYTE oData[dataSize]; + BYTE oDataOld[dataSize]; + + // Remove runner r by force and mark as need correction + void correctRemove(pRunner r); + + // Update hash + void changeId(int newId); + + struct TeamPlace { + int p; // Day result + int totalP; // Total result + }; + + TeamPlace _places[maxRunnersTeam]; + + int _sortTime; + int _sortStatus; + RunnerStatus _cachedStatus; + + mutable vector< vector< vector > > resultCalculationCache; + + string getRunners() const; + bool matchTeam(int number, const char *s_lc) const; + int tNumRestarts; //Number of restarts for team + + int getLegToUse(int leg) const; // Get the number of the actual + // runner to consider for a given leg + // Maps -1 to last runner + + void addTableRow(Table &table) const; + + bool inputData(int id, const string &input, + int inputId, string &output, bool noUpdate); + + void fillInput(int id, vector< pair > &out, size_t &selected); + + /** Get internal data buffers for DI */ + oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; + +public: + /** Check the the main leg is set if any parallel is set. Returns true if corrections where made.*/ + bool checkValdParSetup(); + + int getRanking() const; + + void resetResultCalcCache() const; + vector< vector > &getResultCache(ResultCalcCacheSymbol symb) const; + void setResultCache(ResultCalcCacheSymbol symb, int leg, vector &data) const; + + void markClassChanged(int controlId); + + /// Returns team fee (including participating runners fees) + int getTeamFee() const; + + /** Remove runner from team (and from competition) + @param askRemoveRunner ask if runner should be removed from cmp. Otherwise just do it. + */ + void removeRunner(gdioutput &gdi, bool askRemoveRunner, int runnerIx); + // Get entry date of team + string getEntryDate(bool dummy) const; + + // Get the team itself + cTeam getTeam() const {return this;} + pTeam getTeam() {return this;} + + int getRunningTime() const; + + /// Input data for multiday event + void setInputData(const oTeam &t); + + /// Get total status for multiday event + RunnerStatus getTotalStatus() const; + + void remove(); + bool canRemove() const; + + void prepareRemove(); + + bool skip() const {return isRemoved();} + void setTeamNoStart(bool dns); + // If apply is triggered by a runner, don't go further than that runner. + bool apply(bool sync, pRunner source, bool setTmpOnly); + + void quickApply(); + + void evaluate(bool sync); + + bool adjustMultiRunners(bool sync); + + int getRogainingPoints(bool multidayTotal) const; + int getRogainingReduction() const; + int getRogainingOvertime() const; + int getRogainingPointsGross() const; + + void fillSpeakerObject(int leg, int courseControlId, int previousControlCourseId, + bool totalResult, oSpeakerObject &spk) const; + + bool isRunnerUsed(int Id) const; + void setRunner(unsigned i, pRunner r, bool syncRunner); + + pRunner getRunner(unsigned leg) const; + int getNumRunners() const {return Runners.size();} + + void decodeRunners(const string &rns, vector &rid); + void importRunners(const vector &rns); + void importRunners(const vector &rns); + + int getPlace() const {return getLegPlace(-1, false);} + int getTotalPlace() const {return getLegPlace(-1, true);} + + int getNumShortening() const; + // Number of shortenings up to and including a leg + int getNumShortening(int leg) const; + + string getDisplayName() const; + string getDisplayClub() const; + + void setBib(const string &bib, int numericalBib, bool updateStartNo, bool setTmpOnly); + + int getLegStartTime(int leg) const; + string getLegStartTimeS(int leg) const; + string getLegStartTimeCompact(int leg) const; + + string getLegFinishTimeS(int leg) const; + int getLegFinishTime(int leg) const; + + int getTimeAfter(int leg) const; + + //Get total running time after leg + string getLegRunningTimeS(int leg, bool multidayTotal) const; + + int getLegRunningTime(int leg, bool multidayTotal) const; + int getLegPrelRunningTime(int leg) const; + string getLegPrelRunningTimeS(int leg) const; + + RunnerStatus getLegStatus(int leg, bool multidayTotal) const; + const string &getLegStatusS(int leg, bool multidayTotal) const; + + string getLegPlaceS(int leg, bool multidayTotal) const; + string getLegPrintPlaceS(int leg, bool multidayTotal, bool withDot) const; + int getLegPlace(int leg, bool multidayTotal) const; + + static bool compareSNO(const oTeam &a, const oTeam &b); + static bool compareName(const oTeam &a, const oTeam &b) {return a.sName. + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// oEvent.cpp: implementation of the oEvent class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" + +#include +#include "oEvent.h" +#include "gdioutput.h" +#include "oDataContainer.h" + +#include "random.h" +#include "SportIdent.h" +#include "Localizer.h" +#include "intkeymapimpl.hpp" +#include "MeOSFeatures.h" + +#include "meos_util.h" +#include "meos.h" +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +#include +#include +#include + + +void oEvent::fillTeams(gdioutput &gdi, const string &id, int classId) +{ + vector< pair > d; + oe->fillTeams(d, classId); + gdi.addItem(id, d); +} + +const vector< pair > &oEvent::fillTeams(vector< pair > &out, int ClassId) +{ + synchronizeList(oLTeamId); + oTeamList::iterator it; + Teams.sort(oTeam::compareSNO); + + out.clear(); + + string tn; + int maxBib = 0; + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (!it->Removed) { + maxBib = max(it->getBib().length(), maxBib); + } + } + + string rawDash = ""; + for (int i = 0; i < min(maxBib, 2); i++) + rawDash += "-"; + rawDash += " "; + string dashes = getMeOSFeatures().hasFeature(MeOSFeatures::Bib) ? MakeDash(rawDash) : _EmptyString; + + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (!it->Removed) { + const string &bib = it->getBib(); + if (!bib.empty()) { + /*int nb = atoi(bib.c_str()); + if (nb > 0 && nb == it->getStartNo()) { + char bf[24]; + if (maxSno>999) + sprintf_s(bf, "%04d ", nb); + else + sprintf_s(bf, "%03d ", nb); + + tn = bf + it->Name; + } + else*/ + string paddedBib; + for (int i = 0; i < int(maxBib - bib.length()); i++) + paddedBib += "0"; + + tn = paddedBib + bib + " " + it->getName(); + } + else { + tn = dashes + it->getName(); + } + if (it->Class) + out.push_back(make_pair(tn + (" (" + it->getClass() + ")"), it->Id)); + else + out.push_back(make_pair(tn, it->Id)); + } + } + + return out; +} + + +pTeam oEvent::getTeam(int Id) const { + pTeam value; + if (teamById.lookup(Id, value) && value) { + if (value->isRemoved()) + return 0; + assert(value->Id == Id); + return value; + } + return 0; +} + + +int oEvent::getFreeStartNo() const { + oTeamList::const_iterator it; + int sno=0; + + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (it->isRemoved()) + continue; + sno=max(it->getStartNo(), sno); + } + return sno+1; +} + + +pTeam oEvent::getTeamByName(const string &pName) const { + oTeamList::const_iterator it; + + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (!it->isRemoved() && it->sName==pName) + return pTeam(&*it); + } + return 0; +} + +pTeam oEvent::addTeam(const string &pname, int ClubId, int ClassId) +{ + oTeam t(this); + t.sName=pname; + + if (ClubId>0) + t.Club=getClub(ClubId); + + if (ClassId>0) + t.Class=getClass(ClassId); + + bibStartNoToRunnerTeam.clear(); + Teams.push_back(t); + teamById[t.Id] = &Teams.back(); + + oe->updateTabs(); + + Teams.back().StartNo = ++nextFreeStartNo; // Need not be unique + Teams.back().getEntryDate(false);// Store entry time + Teams.back().apply(false, 0, false); + Teams.back().updateChanged(); + return &Teams.back(); +} + +pTeam oEvent::addTeam(const oTeam &t, bool autoAssignStartNo) { + if (t.Id==0) + return 0; + if (getTeam(t.Id)) + return 0; + + bibStartNoToRunnerTeam.clear(); + Teams.push_back(t); + + pTeam pt = &Teams.back(); + teamById[pt->Id] = pt; + + if (pt->StartNo == 0 && autoAssignStartNo) { + pt->StartNo = ++nextFreeStartNo; // Need not be unique + } + else { + nextFreeStartNo = max(nextFreeStartNo, pt->StartNo); + } + //Important: Must not auto sync! + + return pt; +} + +int oEvent::getFreeTeamId() +{ + if (qFreeTeamId > int(Teams.size() + 1000)) { + for (int j = qFreeTeamId - Teams.size(); j > 0; j -= Teams.size()) { + if (getTeam(j) == 0) + return j; + } + } + + qFreeTeamId++; + return qFreeTeamId; +} + + +bool oEvent::writeTeams(xmlparser &xml) +{ + oTeamList::iterator it; + + xml.startTag("TeamList"); + + for (it=Teams.begin(); it != Teams.end(); ++it) + it->write(xml); + + xml.endTag(); + + return true; +} + +pTeam oEvent::findTeam(const string &s, int lastId, stdext::hash_set &filter) const +{ + string trm = trim(s); + int len = trm.length(); + char s_lc[1024]; + strcpy_s(s_lc, trm.c_str()); + CharLowerBuff(s_lc, len); + + int sn = atoi(s.c_str()); + oTeamList::const_iterator it; +/* + if (sn>0) { + for (it=Teams.begin(); it != Teams.end(); ++it) { + if (it->skip()) + continue; + + if (it->StartNo==sn) + return pTeam(&*it); + + for(size_t k=0;kRunners.size();k++) + if (it->Runners[k] && it->Runners[k]->CardNo==sn) + return pTeam(&*it); + } + } +*/ + oTeamList::const_iterator itstart=Teams.begin(); + + + if (lastId) { + for (; itstart != Teams.end(); ++itstart) + if (itstart->Id==lastId) { + ++itstart; + break; + } + } + + pTeam ret = 0; + for (it=itstart; it != Teams.end(); ++it) { + pTeam t = pTeam(&*it); + + if (!t->skip() && t->matchTeam(sn, s_lc)) { + filter.insert(t->Id); + if (ret == 0) + ret = t; + } + } + + for (it=Teams.begin(); it != itstart; ++it) { + pTeam t = pTeam(&*it); + + if (!t->skip() && t->matchTeam(sn, s_lc)) { + filter.insert(t->Id); + if (ret == 0) + ret = t; + } + } + + return ret; +} + +bool oTeam::matchTeam(int number, const char *s_lc) const +{ + if (number) { + if (matchNumber(StartNo, s_lc )) + return true; + + for(size_t k = 0; k < Runners.size(); k++) { + if (Runners[k] && matchNumber(Runners[k]->CardNo, s_lc)) + return true; + } + } + + if (filterMatchString(sName, s_lc)) + return true; + + for(size_t k=0;ktRealName, s_lc)) + return true; + + return false; +} + + + +void oEvent::fillPredefinedCmp(gdioutput &gdi, const string &name) const +{ + bool hasPatrol = getMeOSFeatures().hasFeature(MeOSFeatures::Patrol); + bool hasMulti = getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces); + bool hasRelay = getMeOSFeatures().hasFeature(MeOSFeatures::Relay); + bool hasForked = getMeOSFeatures().hasFeature(MeOSFeatures::ForkedIndividual); + + gdi.clearList(name); + gdi.addItem(name, lang.tl("Endast en bana"), PNoMulti); + gdi.addItem(name, lang.tl("Utan inställningar"), PNoSettings); + if (hasForked) { + gdi.addItem(name, lang.tl("En gafflad sträcka"), PForking); + gdi.addItem(name, lang.tl("Banpool, gemensam start"), PPool); + gdi.addItem(name, lang.tl("Banpool, lottad startlista"), PPoolDrawn); + } + if (hasMulti) + gdi.addItem(name, lang.tl("Prolog + jaktstart"), PHunting); + if (hasPatrol) { + gdi.addItem(name, lang.tl("Patrull, 2 SI-pinnar"), PPatrol); + gdi.addItem(name, lang.tl("Par- eller singelklass"), PPatrolOptional); + gdi.addItem(name, lang.tl("Patrull, 1 SI-pinne"), PPatrolOneSI); + } + if (hasRelay) + gdi.addItem(name, lang.tl("Stafett"), PRelay); + if (hasMulti) + gdi.addItem(name, lang.tl("Tvåmannastafett"), PTwinRelay); + if (hasRelay) + gdi.addItem(name, lang.tl("Extralöparstafett"), PYouthRelay); +} + +void oEvent::setupRelayInfo(PredefinedTypes type, bool &useNLeg, bool &useStart) +{ + useNLeg = false; + useStart = false; + + switch(type) { + case PNoMulti: + break; + + case PNoSettings: + useNLeg = true; + break; + + case PPool: + useStart = true; + break; + + case PForking: + useStart = true; + break; + + case PPoolDrawn: + break; + + case PPatrol: + break; + + case PPatrolOptional: + break; + + case PPatrolOneSI: + break; + + case PRelay: + useStart = true; + useNLeg = true; + break; + + case PTwinRelay: + useStart = true; + useNLeg = true; + break; + + case PYouthRelay: + useStart = true; + useNLeg = true; + break; + + case PHunting: + useStart = true; + break; + + default: + throw std::exception("Bad setup number"); + } +} + +void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const string &start) +{ + // Make sure we are up-to-date + autoSynchronizeLists(false); + + pCourse crs = cls.getCourse(); + int crsId = crs ? crs->getId() : 0; + + nleg=min(nleg, 40); + cls.setNumStages(0); + switch(type) { + case PNoMulti: + cls.setNumStages(0); + cls.setCoursePool(false); + break; + + case PNoSettings: + cls.setNumStages(nleg); + break; + + case PPool: + case PForking: + cls.setNumStages(1); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STTime, false); + cls.setStartData(0, start); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + cls.setCoursePool(type == PPool); + + if (crs) { + cls.addStageCourse(0, crsId); + } + + break; + + case PPoolDrawn: + cls.setNumStages(1); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STDrawn, false); + cls.setStartData(0, "-"); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + cls.setCoursePool(true); + + if (crs) { + cls.addStageCourse(0, crsId); + } + break; + + case PPatrol: + cls.setNumStages(2); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STDrawn, false); + cls.setStartData(0, "-"); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + + cls.setLegType(1, LTParallel); + cls.setStartType(1, STDrawn, false); + cls.setStartData(1, "-"); + cls.setRestartTime(1, "-"); + cls.setRopeTime(1, "-"); + + if (crs) { + cls.addStageCourse(0, crsId); + cls.addStageCourse(1, crsId); + } + cls.setCoursePool(false); + break; + + case PPatrolOptional: + cls.setNumStages(2); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STDrawn, false); + cls.setStartData(0, "-"); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + + cls.setLegType(1, LTParallelOptional); + cls.setStartType(1, STDrawn, false); + cls.setStartData(1, "-"); + cls.setRestartTime(1, "-"); + cls.setRopeTime(1, "-"); + + if (crs) { + cls.addStageCourse(0, crsId); + cls.addStageCourse(1, crsId); + } + cls.setCoursePool(false); + break; + + case PPatrolOneSI: + cls.setNumStages(2); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STDrawn, false); + cls.setStartData(0, "-"); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + + cls.setLegType(1, LTIgnore); + cls.setStartType(1, STDrawn, false); + cls.setStartData(1, start); + cls.setRestartTime(1, "-"); + cls.setRopeTime(1, "-"); + + if (crs) { + cls.addStageCourse(0, crsId); + cls.addStageCourse(1, crsId); + } + + cls.setCoursePool(false); + break; + + case PRelay: + cls.setNumStages(nleg); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STTime, false); + cls.setStartData(0, start); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + + for (int k=1;k=2) + cls.setLegRunner(k, k%2); + } + + cls.setCoursePool(false); + break; + + case PYouthRelay: + nleg=max(nleg, 3); + int last; + cls.setNumStages(nleg+(nleg-2)*2); + cls.setLegType(0, LTNormal); + cls.setStartType(0, STTime, false); + cls.setStartData(0, start); + cls.setRestartTime(0, "-"); + cls.setRopeTime(0, "-"); + + last=nleg+(nleg-2)*2-1; + cls.setLegType(last, LTNormal); + cls.setStartType(last, STChange, false); + cls.setStartData(last, "-"); + cls.setRestartTime(last, "-"); + cls.setRopeTime(last, "-"); + + for (int k=0;kgetNumStages() > 1; + for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { + if (it->skip() || it->getClassId() != cls->getId()) + continue; + if (multi && it->tInTeam == 0) { + oe->autoAddTeam(&*it); + } + + if (!multi && it->tInTeam) { + assert( it->tInTeam->getClassId() == cls->getId()); + removeTeam(it->tInTeam->getId()); + } + + it->synchronizeAll(); + } + + vector tr; + for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { + if (!multi && !it->isRemoved() && it->getClassId() == cls->getId()) { + tr.push_back(it->getId()); + } + } + while(!tr.empty()) { + removeTeam(tr.back()); + tr.pop_back(); + } + } + disableRecalculate = true; + try { + for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { + it->adjustMultiRunners(true); + } + } + catch(...) { + disableRecalculate = false; + throw; + } + disableRecalculate = false; +} + +bool oTeam::adjustMultiRunners(bool sync) +{ + if (!Class) + return false; + + for (size_t k = Class->getNumStages(); kgetNumStages())) { + Runners.resize(Class->getNumStages()); + updateChanged(); + } + + // Create multi runners. + for (size_t i=0;igetLegRunner(i); + + if (lrcreateMultiRunner(true, sync); + int dup=Class->getLegRunnerIndex(i); + Runners[i]=Runners[lr]->getMultiRunner(dup); + } + } + } + + return apply(sync, 0, false); +} + +void oEvent::makeUniqueTeamNames() { + sortTeams(ClassStartTime, 0, true); + for (oClassList::const_iterator cls = Classes.begin(); cls != Classes.end(); ++cls) { + if (cls->isRemoved()) + continue; + map > teams; + for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { + if (it->skip()) + continue; + if (it->Class != &*cls) + continue; + teams[it->sName].push_back(&*it); + } + + for (map >::iterator it = teams.begin(); it != teams.end(); ++it) { + list &t = it->second; + if (t.size() > 1) { + int counter = 1; + for (list::iterator tit = t.begin(); tit != t.end(); ) { + string name = (*tit)->sName + " " + itos(counter); + if (teams.count(name) == 0) { + (*tit)->setName(name, true); + (*tit)->synchronize(); + ++tit; + } + counter++; + } + } + } + } +} + +void oTeam::changeId(int newId) { + pTeam old = oe->teamById[Id]; + if (old == this) + oe->teamById.remove(Id); + + oBase::changeId(newId); + + oe->teamById[newId] = this; +} diff --git a/code/onlineinput.cpp b/code/onlineinput.cpp new file mode 100644 index 0000000..fa7cf93 --- /dev/null +++ b/code/onlineinput.cpp @@ -0,0 +1,386 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" + +#include "onlineinput.h" +#include "meos_util.h" +#include + +#include "gdiconstants.h" +#include "meosException.h" +#include "Download.h" +#include "xmlparser.h" +#include "progress.h" +#include "csvparser.h" + +#include "SportIdent.h" +#include "TabSI.h" + +int AutomaticCB(gdioutput *gdi, int type, void *data); + +static int OnlineCB(gdioutput *gdi, int type, void *data) { + switch (type) { + case GUI_BUTTON: { + //Make a copy + ButtonInfo bu=*static_cast(data); + OnlineInput &ores = dynamic_cast(*AutoMachine::getMachine(bu.getExtraInt())); + return ores.processButton(*gdi, bu); + } + case GUI_LISTBOX:{ + } + } + return 0; +} + +OnlineInput::~OnlineInput() { +} + +int OnlineInput::processButton(gdioutput &gdi, ButtonInfo &bi) { + if (bi.id == "SaveMapping") { + int ctrl = gdi.getTextNo("Code"); + if (ctrl<10) + throw meosException("Ogiltig kontrollkod"); + ListBoxInfo lbi; + if (!gdi.getSelectedItem("Function", lbi)) + throw meosException("Ogiltig funktion"); + specialPunches[ctrl] = (oPunch::SpecialPunch)lbi.data; + fillMappings(gdi); + } + else if (bi.id == "RemoveMapping") { + set sel; + gdi.getSelection("Mappings", sel); + for (set::iterator it = sel.begin(); it != sel.end(); ++it) { + specialPunches.erase(*it); + } + fillMappings(gdi); + } + else if (bi.id == "UseROC") { + useROCProtocol = gdi.isChecked(bi.id); + if (useROCProtocol) { + gdi.setText("URL", "http://roc.olresultat.se/getpunches.asp"); + } + else { + gdi.check("UseUnitId", false); + gdi.setTextTranslate("CmpID_label", "Tävlingens ID-nummer:", true); + useUnitId = false; + } + gdi.setInputStatus("UseUnitId", useROCProtocol); + } + else if (bi.id == "UseUnitId") { + useUnitId = gdi.isChecked(bi.id); + if (useUnitId) + gdi.setTextTranslate("CmpID_label", "Enhetens ID-nummer (MAC):", true); + else + gdi.setTextTranslate("CmpID_label", "Tävlingens ID-nummer:", true); + } + + return 0; +} + +void OnlineInput::fillMappings(gdioutput &gdi) const{ + gdi.clearList("Mappings"); + for (map::const_iterator it = specialPunches.begin(); it != specialPunches.end(); ++it) { + gdi.addItem("Mappings", itos(it->first) + " -> " + oPunch::getType(it->second), it->first); + } +} + + +void OnlineInput::settings(gdioutput &gdi, oEvent &oe, bool created) { + int iv = interval; + if (created) { + iv = 10; + url = oe.getPropertyString("MIPURL", ""); + } + + string time; + if (iv>0) + time = itos(iv); + + settingsTitle(gdi, "Inmatning online"); + startCancelInterval(gdi, "Save", created, IntervalSecond, time); + + gdi.addInput("URL", url, 40, 0, "URL:", "Till exempel X#http://www.input.org/online.php"); + gdi.addCheckbox("UseROC", "Använd ROC-protokoll", OnlineCB, useROCProtocol).setExtra(getId()); + gdi.addCheckbox("UseUnitId", "Använd enhets-id istället för tävlings-id", OnlineCB, useROCProtocol & useUnitId).setExtra(getId()); + gdi.setInputStatus("UseUnitId", useROCProtocol); + gdi.addInput("CmpID", itos(cmpId), 10, 0, "Tävlingens ID-nummer:"); + + gdi.dropLine(1); + + gdi.addString("", boldText, "Kontrollmappning"); + gdi.dropLine(0.5); + gdi.fillRight(); + gdi.addInput("Code", "", 4, 0, "Kod:"); + gdi.addSelection("Function", 80, 200, 0, "Funktion:"); + gdi.addItem("Function", lang.tl("Mål"), oPunch::PunchFinish); + gdi.addItem("Function", lang.tl("Start"), oPunch::PunchStart); + gdi.addItem("Function", lang.tl("Check"), oPunch::PunchCheck); + gdi.dropLine(); + gdi.addButton("SaveMapping", "Lägg till", OnlineCB).setExtra(getId()); + gdi.popX(); + gdi.dropLine(2); + gdi.addListBox("Mappings", 150, 100, 0, "Definierade mappningar:", "", true); + gdi.dropLine(); + gdi.addButton("RemoveMapping", "Ta bort", OnlineCB).setExtra(getId()); + fillMappings(gdi); + + gdi.setCY(gdi.getHeight()); + gdi.popX(); + gdi.addString("", 10, "help:onlineinput"); +} + +void OnlineInput::save(oEvent &oe, gdioutput &gdi) { + int iv=gdi.getTextNo("Interval"); + const string &xurl=gdi.getText("URL"); + + if (!xurl.empty()) + oe.setProperty("MIPURL", xurl); + + cmpId = gdi.getTextNo("CmpID"); + unitId = gdi.getText("CmpID"); + + if (xurl.empty()) { + throw meosException("URL måste anges."); + } + url = xurl; + + process(gdi, &oe, SyncNone); + interval = iv; +} + +void OnlineInput::status(gdioutput &gdi) +{ + gdi.addString("", 1, name); + gdi.fillRight(); + gdi.pushX(); + + gdi.addString("", 0, "URL:"); + gdi.addStringUT(0, url); + gdi.popX(); + gdi.dropLine(1); + + gdi.addString("", 0, "Antal hämtade uppdateringar X (Y kb)#" + + itos(importCounter-1) + "#" + itos(bytesImported/1024)); + gdi.popX(); + gdi.fillDown(); + gdi.dropLine(2); + + for (size_t k = 0; k < info.size(); k++) { + gdi.addString("", 0, info[k]); + } + + gdi.fillRight(); + gdi.dropLine(1); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("OnlineInput", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void OnlineInput::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) { + oe->autoSynchronizeLists(true); + + try { + Download dwl; + dwl.initInternet(); + ProgressWindow pw(0); + vector > key; + string q; + if (useROCProtocol) { + if (!useUnitId) + q = "?unitId=" + itos(cmpId) + "&lastId=" + itos(lastImportedId) + "&date=" + oe->getDate() +"&time=" + oe->getZeroTime(); + else + q = "?unitId=" + unitId + "&lastId=" + itos(lastImportedId) + "&date=" + oe->getDate() +"&time=" + oe->getZeroTime(); + } + else { + pair mk1("competition", itos(cmpId)); + key.push_back(mk1); + pair mk2("lastid", itos(lastImportedId)); + key.push_back(mk2); + } + string result = getTempFile(); + dwl.downloadFile(url + q, result, key); + dwl.downLoadNoThread(); + + if (!useROCProtocol) { + xmlobject res; + xmlparser xml(0); + try { + xml.read(result); + res = xml.getObject("MIPData"); + } + catch(std::exception &) { + throw meosException("Onlineservern svarade felaktigt."); + } + + xmlList entries; + res.getObjects("entry", entries); + processEntries(*oe, entries); + + xmlList updates; + res.getObjects("update", updates); + processUpdates(*oe, updates); + + xmlList cards; + res.getObjects("card", cards); + processCards(gdi, *oe, cards); + + xmlList punches; + res.getObjects("p", punches); + processPunches(*oe, punches); + + lastImportedId = res.getAttrib("lastid").getInt(); + } + else { + csvparser csv; + list< vector > rocData; + csv.parse(result, rocData); + processPunches(*oe, rocData); + } + + struct stat st; + stat(result.c_str(), &st); + bytesImported += st.st_size; + removeTempFile(result); + } + catch(std::exception &ex) { + if (ast == SyncNone) + throw; + else + gdi.addInfoBox("", string("Online Input Error X#")+ex.what(), 5000); + } + importCounter++; +} + +void OnlineInput::processPunches(oEvent &oe, const xmlList &punches) { + for (size_t k = 0; k < punches.size(); k++) { + int code = punches[k].getObjectInt("code"); + string startno; + punches[k].getObjectString("sno", startno); + + if (specialPunches.count(code)) + code = specialPunches[code]; + + pRunner r = 0; + + int card = punches[k].getObjectInt("card"); + int time = punches[k].getObjectInt("time") / 10; + time = oe.getRelativeTime(formatTimeHMS(time)); + + if (startno.length() > 0) + r = oe.getRunnerByBibOrStartNo(startno, false); + else + r = oe.getRunnerByCardNo(card, time); + + string rname; + if (r) { + rname = r->getName(); + card = r->getCardNo(); + } + else { + rname=lang.tl("Okänd"); + } + if (time < 0) { + time = 0; + addInfo("Ogiltig tid"); + } + oe.addFreePunch(time, code, card, true); + + addInfo("Löpare: X, kontroll: Y, kl Z#" + rname + "#" + oPunch::getType(code) + "#" + oe.getAbsTime(time)); + } +} + +void OnlineInput::processPunches(oEvent &oe, list< vector > &rocData) { + for (list< vector >::iterator it = rocData.begin(); it != rocData.end(); ++it) { + vector &line = *it; + if (line.size() == 4) { + int punchId = atoi(line[0].c_str()); + int code = atoi(line[1].c_str()); + int card = atoi(line[2].c_str()); + string timeS = line[3].substr(11); + int time = oe.getRelativeTime(timeS); + + if (specialPunches.count(code)) + code = specialPunches[code]; + + pRunner r = oe.getRunnerByCardNo(card, time); + + string rname; + if (r) { + rname = r->getName(); + card = r->getCardNo(); + } + else { + rname=lang.tl("Okänd"); + } + + if (time < 0) { + time = 0; + addInfo("Ogiltig tid"); + } + oe.addFreePunch(time, code, card, true); + + lastImportedId = max(lastImportedId, punchId); + + addInfo("Löpare: X, kontroll: Y, kl Z#" + rname + "#" + oPunch::getType(code) + "#" + oe.getAbsTime(time)); + } + else + throw meosException("Onlineservern svarade felaktigt."); + } +} + +void OnlineInput::processCards(gdioutput &gdi, oEvent &oe, const xmlList &cards) { + for (size_t k = 0; k < cards.size(); k++) { + SICard sic; + sic.clear(0); + sic.CardNumber = cards[k].getObjectInt("number"); + if (cards[k].getObject("finish")) + sic.FinishPunch.Time = cards[k].getObject("finish").getObjectInt("time") / 10; + if (cards[k].getObject("start")) + sic.StartPunch.Time = cards[k].getObject("start").getObjectInt("time") / 10; + xmlList punches; + cards[k].getObjects("p", punches); + for (size_t j = 0; j < punches.size(); j++) { + sic.Punch[j].Code = punches[j].getObjectInt("code"); + sic.Punch[j].Time = punches[j].getObjectInt("time") / 10; + } + sic.nPunch = punches.size(); + TabSI::getSI(gdi).addCard(sic); + } +} + +void OnlineInput::processUpdates(oEvent &oe, const xmlList &updates) { +} + +void OnlineInput::processEntries(oEvent &oe, const xmlList &entries) { +} + diff --git a/code/onlineinput.h b/code/onlineinput.h new file mode 100644 index 0000000..7ad9370 --- /dev/null +++ b/code/onlineinput.h @@ -0,0 +1,75 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "TabAuto.h" +#include +#include "oPunch.h" + +class InfoCompetition; + +class OnlineInput : + public AutoMachine +{ +protected: + string url; + int cmpId; + string unitId; + int lastImportedId; + int importCounter; + int bytesImported; + DWORD lastSync; + + bool useROCProtocol; + bool useUnitId; + + deque info; + map specialPunches; + + void addInfo(const string &line) { + if (info.size() >= 10) + info.pop_back(); + info.push_front(line); + } + + void fillMappings(gdioutput &gdi) const; + + void processCards(gdioutput &gdi, oEvent &oe, const xmlList &cards); + void processUpdates(oEvent &oe, const xmlList &updates); + void processEntries(oEvent &oe, const xmlList &entries); + + void processPunches(oEvent &oe, const xmlList &punches); + void processPunches(oEvent &oe, list< vector > &rocData); +public: + + int processButton(gdioutput &gdi, ButtonInfo &bi); + + void save(oEvent &oe, gdioutput &gdi); + void settings(gdioutput &gdi, oEvent &oe, bool created); + OnlineInput *clone() const {return new OnlineInput(*this);} + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + OnlineInput() : AutoMachine("Onlineinput"), cmpId(0), importCounter(1), + bytesImported(0), lastSync(0), lastImportedId(0), useROCProtocol(false), useUnitId(false) {} + ~OnlineInput(); + friend class TabAuto; +}; diff --git a/code/onlineresults.cpp b/code/onlineresults.cpp new file mode 100644 index 0000000..9e22607 --- /dev/null +++ b/code/onlineresults.cpp @@ -0,0 +1,516 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include "resource.h" + +#include +#include +#include + +#include "oEvent.h" +#include "gdioutput.h" + +#include "onlineresults.h" +#include "meos_util.h" +#include + +#include "gdiconstants.h" +#include "infoserver.h" +#include "meosException.h" +#include "Download.h" +#include "xmlparser.h" +#include "progress.h" + +int AutomaticCB(gdioutput *gdi, int type, void *data); + +static int OnlineCB(gdioutput *gdi, int type, void *data) { + switch (type) { + case GUI_BUTTON: { + //Make a copy + ButtonInfo bu=*static_cast(data); + OnlineResults &ores = dynamic_cast(*AutoMachine::getMachine(bu.getExtraInt())); + + return ores.processButton(*gdi, bu); + } + case GUI_LISTBOX:{ + } + } + return 0; +} + +OnlineResults::~OnlineResults() { + if (infoServer) + delete infoServer; +} + +int OnlineResults::processButton(gdioutput &gdi, ButtonInfo &bi) { + + if (bi.id == "ToURL") + enableURL(gdi, gdi.isChecked(bi.id)); + else if (bi.id == "ToFile") + enableFile(gdi, gdi.isChecked(bi.id)); + else if (bi.id == "BrowseFolder") { + string res = gdi.getText("FolderName"); + res = gdi.browseForFolder(res, 0); + if (!res.empty()) + gdi.setText("FolderName", res, true); + } + return 0; +} + +void OnlineResults::settings(gdioutput &gdi, oEvent &oe, bool created) { + int iv = interval; + if (created) { + iv = 10; + url = oe.getPropertyString("MOPURL", ""); + file = oe.getPropertyString("MOPFolderName", ""); + oe.getAllClasses(classes); + } + + string time; + if (iv>0) + time = itos(iv); + + settingsTitle(gdi, "Resultat online"); + startCancelInterval(gdi, "Save", created, IntervalSecond, time); + + int basex = gdi.getCX(); + gdi.pushY(); + gdi.fillRight(); + gdi.addListBox("Classes", 200,300,0, "Klasser:","", true); + gdi.pushX(); + vector< pair > d; + gdi.addItem("Classes", oe.fillClasses(d, oEvent::extraNone, oEvent::filterNone)); + gdi.setSelection("Classes", classes); + + gdi.popX(); + + gdi.popY(); + gdi.fillDown(); + + + // gdi.dropLine(); + // gdi.addInput("Interval", time, 10, 0, "Uppdateringsintervall (sekunder):"); + + gdi.addSelection("Format", 200, 200, 0, "Exportformat:"); + gdi.addItem("Format", "MeOS Online Protocol XML", 1); + gdi.addItem("Format", "IOF XML 2.0.3", 2); + gdi.addItem("Format", "IOF XML 3.0", 3); + gdi.selectItemByData("Format", dataType); + + gdi.addCheckbox("Zip", "Packa stora filer (zip)", 0, zipFile); + int cx = gdi.getCX(); + gdi.fillRight(); + + gdi.addCheckbox("ToURL", "Skicka till webben", OnlineCB, sendToURL).setExtra(getId()); + + gdi.addString("", 0, "URL:"); + gdi.pushX(); + gdi.addInput("URL", url, 40, 0, "", "Till exempel X#http://www.results.org/online.php"); + gdi.dropLine(2.5); + gdi.popX(); + gdi.addInput("CmpID", itos(cmpId), 10, 0, "Tävlingens ID-nummer:"); + gdi.addInput("Password", passwd, 15, 0, "Lösenord:").setPassword(true); + + enableURL(gdi, sendToURL); + + gdi.setCX(cx); + gdi.dropLine(5); + gdi.fillRight(); + + gdi.addCheckbox("ToFile", "Spara på disk", OnlineCB, sendToFile).setExtra(getId()); + + gdi.addString("", 0, "Mapp:"); + gdi.pushX(); + gdi.addInput("FolderName", file, 30); + gdi.addButton("BrowseFolder", "Bläddra...", OnlineCB).setExtra(getId()); + gdi.dropLine(2.5); + gdi.popX(); + + gdi.addInput("Prefix", prefix, 10, 0, "Filnamnsprefix:"); + gdi.dropLine(2.8); + gdi.popX(); + + gdi.addInput("ExportScript", exportScript, 32, 0, "Skript att köra efter export:"); + gdi.dropLine(0.8); + gdi.addButton("BrowseScript", "Bläddra...", AutomaticCB); + + gdi.setCY(gdi.getHeight()); + gdi.setCX(basex); + + gdi.fillDown(); + gdi.dropLine(); + gdi.addString("", fontMediumPlus, "Kontroller"); + RECT rc; + rc.left = gdi.getCX(); + rc.right = gdi.getWidth(); + rc.top = gdi.getCY(); + rc.bottom = rc.top + 3; + gdi.addRectangle(rc, colorDarkBlue, false); + gdi.dropLine(); + vector ctrl; + oe.getControls(ctrl, true); + + vector< pair > ctrlP; + for (size_t k = 0; k< ctrl.size(); k++) { + for (int i = 0; i < ctrl[k]->getNumberDuplicates(); i++) { + ctrlP.push_back(make_pair(ctrl[k], oControl::getCourseControlIdFromIdIndex(ctrl[k]->getId(), i))); + } + } + + int width = gdi.scaleLength(130); + int height = int(gdi.getLineHeight()*1.5); + int xp = gdi.getCX(); + int yp = gdi.getCY(); + for (size_t k = 0; k< ctrlP.size(); k++) { + string name = "#" + (ctrlP[k].first->hasName() ? ctrlP[k].first->getName() : ctrlP[k].first->getString()); + if (ctrlP[k].first->getNumberDuplicates() > 1) + name += "-" + itos(oControl::getIdIndexFromCourseControlId(ctrlP[k].second).second + 1); + gdi.addCheckbox(xp + (k % 6)*width, yp + (k / 6)*height, "C"+itos(ctrlP[k].second), + name, 0, ctrlP[k].first->isValidRadio()); + } + gdi.dropLine(); + + rc.top = gdi.getCY(); + rc.bottom = rc.top + 3; + gdi.addRectangle(rc, colorDarkBlue, false); + gdi.dropLine(); + + formatError(gdi); + if (errorLines.empty()) + gdi.addString("", 10, "help:onlineresult"); + + enableFile(gdi, sendToFile); +} + +void OnlineResults::enableURL(gdioutput &gdi, bool state) { + gdi.setInputStatus("URL", state); + gdi.setInputStatus("CmpID", state); + gdi.setInputStatus("Password", state); +} + +void OnlineResults::enableFile(gdioutput &gdi, bool state) { + gdi.setInputStatus("FolderName", state); + gdi.setInputStatus("BrowseFolder", state); + gdi.setInputStatus("Prefix", state); + gdi.setInputStatus("ExportScript", state); + gdi.setInputStatus("BrowseScript", state); +} + +void OnlineResults::save(oEvent &oe, gdioutput &gdi) { + int iv=gdi.getTextNo("Interval"); + string folder=gdi.getText("FolderName"); + const string &xurl=gdi.getText("URL"); + + if (!folder.empty()) + oe.setProperty("MOPFolderName", folder); + + if (!xurl.empty()) + oe.setProperty("MOPURL", xurl); + + sendToURL = gdi.isChecked("ToURL"); + sendToFile = gdi.isChecked("ToFile"); + + cmpId = gdi.getTextNo("CmpID"); + passwd = gdi.getText("Password"); + prefix = gdi.getText("Prefix"); + exportScript = gdi.getText("ExportScript"); + zipFile = gdi.isChecked("Zip"); + + ListBoxInfo lbi; + gdi.getSelectedItem("Format", lbi); + dataType = lbi.data; + + gdi.getSelection("Classes", classes); + if (sendToFile) { + if (folder.empty()) { + throw meosException("Mappnamnet får inte vara tomt."); + } + + if (*folder.rbegin() == '/' || *folder.rbegin() == '\\') + folder = folder.substr(0, folder.size() - 1); + + file = folder; + string exp = getExportFileName(); + if (fileExist(exp.c_str())) + throw meosException(string("Filen finns redan: X#") + exp); + } + + if (sendToURL) { + if (xurl.empty()) { + throw meosException("URL måste anges."); + } + url = xurl; + } + + vector ctrl; + oe.getControls(ctrl, true); + for (size_t k = 0; k< ctrl.size(); k++) { + vector ids; + ctrl[k]->getCourseControls(ids); + for (size_t i = 0; i < ids.size(); i++) { + string id = "C"+itos(ids[i]); + if (gdi.hasField(id)) { + bool st = gdi.isChecked(id); + if (st != ctrl[k]->isValidRadio()) + ctrl[k]->setRadio(st); + } + } + } + + process(gdi, &oe, SyncNone); + + interval = iv; + synchronize = true; + synchronizePunches = true; +} + +void OnlineResults::status(gdioutput &gdi) +{ + gdi.addString("", 1, name); + gdi.fillRight(); + gdi.pushX(); + if (sendToFile) { + gdi.addString("", 0, "Mapp:"); + gdi.addStringUT(0, file); + gdi.popX(); + gdi.dropLine(1); + } + if (sendToURL) { + gdi.addString("", 0, "URL:"); + gdi.addStringUT(0, url); + gdi.popX(); + gdi.dropLine(1); + } + + if (sendToFile || sendToURL) { + gdi.addString("", 0, "Exporterar om: "); + gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign, (GetTickCount()-timeout)/1000); + gdi.addString("", 0, "Antal skickade uppdateringar X (Y kb)#" + + itos(exportCounter-1) + "#" + itos(bytesExported/1024)); + } + gdi.popX(); + + gdi.dropLine(2); + gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId()); + gdi.fillDown(); + gdi.addButton("OnlineResults", "Inställningar...", AutomaticCB).setExtra(getId()); + gdi.popX(); +} + +void OnlineResults::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) { + errorLines.clear(); + DWORD tick = GetTickCount(); + if (lastSync + interval * 1000 > tick) + return; + + if (!sendToFile && !sendToURL) + return; + ProgressWindow pwMain((sendToURL && ast == SyncNone) ? gdi.getHWND() : 0); + pwMain.init(); + + string t; + int xmlSize = 0; + InfoCompetition &ic = getInfoServer(); + xmlbuffer xmlbuff; + if (dataType == 1) { + if (ic.synchronize(*oe, classes)) { + lastSync = tick; // If error, avoid to quick retry + ic.getDiffXML(xmlbuff); + } + } + else { + t = getTempFile(); + if (dataType == 2) + oe->exportIOFSplits(oEvent::IOF20, t.c_str(), false, false, + classes, -1, false, true, true, false); + else if (dataType == 3) + oe->exportIOFSplits(oEvent::IOF30, t.c_str(), false, false, + classes, -1, false, true, true, false); + else + throw meosException("Internal error"); + } + + if (!t.empty() || xmlbuff.size() > 0) { + if (sendToFile) { + + if (xmlbuff.size() > 0) { + t = getTempFile(); + xmlparser xml(gdi.getEncoding() == ANSI ? 0 : &gdi); + if (sendToURL) { + xmlbuffer bcopy = xmlbuff; + bcopy.startXML(xml, t); + bcopy.commit(xml, xmlbuff.size()); + } + else { + xmlbuff.startXML(xml, t); + xmlbuff.commit(xml, xmlbuff.size()); + } + xml.endTag(); + xmlSize = xml.closeOut(); + + } + string fn = getExportFileName(); + + if (!CopyFile(t.c_str(), fn.c_str(), false)) + gdi.addInfoBox("", "Kunde inte skriva resultat till X#" + fn); + else if (!sendToURL) { + ic.commitComplete(); + bytesExported +=xmlSize; + removeTempFile(t); + } + + if (!exportScript.empty()) { + ShellExecute(NULL, NULL, exportScript.c_str(), fn.c_str(), NULL, SW_HIDE); + } + } + + try { + if (sendToURL) { + Download dwl; + dwl.initInternet(); + ProgressWindow pw(0); + vector > key; + pair mk1("competition", itos(cmpId)); + key.push_back(mk1); + pair mk2("pwd", passwd); + key.push_back(mk2); + + bool moreToWrite = true; + string tmp; + const int total = max(xmlbuff.size(), 1u); + + while(moreToWrite) { + + t = getTempFile(); + xmlparser xmlOut(gdi.getEncoding() == ANSI ? 0 : &gdi); + xmlbuff.startXML(xmlOut, t); + moreToWrite = xmlbuff.commit(xmlOut, 250); + xmlOut.endTag(); + xmlSize = xmlOut.closeOut(); + string result = getTempFile(); + + if (zipFile && xmlSize > 1024) { + string zipped = getTempFile(); + zip(zipped.c_str(), 0, vector(1, t)); + removeTempFile(t); + t = zipped; + + struct stat st; + stat(t.c_str(), &st); + bytesExported += st.st_size; + } + else + bytesExported +=xmlSize; + + dwl.postFile(url, t, result, key, pw); + removeTempFile(t); + + pwMain.setProgress(1000-(1000 * xmlbuff.size())/total); + + xmlparser xml(0); + xmlobject res; + try { + xml.read(result); + res = xml.getObject("MOPStatus"); + } + catch(std::exception &) { + ifstream is(result.c_str()); + is.seekg (0, is.end); + int length = is.tellg(); + is.seekg (0, is.beg); + char * buffer = new char [length+1]; + is.read (buffer,length); + is.close(); + removeTempFile(result); + buffer[length] = 0; + OutputDebugString(buffer); + split(buffer, "\n", errorLines); + delete[] buffer; + formatError(gdi); + throw meosException("Onlineservern svarade felaktigt."); + } + removeTempFile(result); + + if (res) + res.getObjectString("status", tmp); + if (tmp == "BADCMP") + throw meosException("Onlineservern svarade: Felaktigt tävlings-id"); + if (tmp == "BADPWD") + throw meosException("Onlineservern svarade: Felaktigt lösenord"); + if (tmp == "NOZIP") + throw meosException("Onlineservern svarade: ZIP stöds ej"); + if (tmp == "ERROR") + throw meosException("Onlineservern svarade: Serverfel"); + + if (tmp != "OK") + break; + } + + if (tmp == "OK") + ic.commitComplete(); + else + throw meosException("Misslyckades med att ladda upp onlineresultat"); + } + } + catch(std::exception &ex) { + if (ast == SyncNone) + throw; + else + gdi.addInfoBox("", string("Online Results Error X#")+ex.what(), 5000); + } + + lastSync = GetTickCount(); + exportCounter++; + } +} + +void OnlineResults::formatError(gdioutput &gdi) { + gdi.restore("ServerError", false); + if (errorLines.empty()) { + gdi.refresh(); + return; + } + gdi.setRestorePoint("ServerError"); + gdi.dropLine(); + gdi.fillDown(); + gdi.addString("", boldText, "Server response X:#" + getLocalTime()).setColor(colorRed); + for (size_t k = 0; k < errorLines.size(); k++) + gdi.addStringUT(0, errorLines[k]); + gdi.scrollToBottom(); + gdi.refresh(); +} + +InfoCompetition &OnlineResults::getInfoServer() const { + if (!infoServer) + infoServer = new InfoCompetition(1); + + return *infoServer; +} + +string OnlineResults::getExportFileName() const { + char bf[260]; + sprintf_s(bf, "%s\\%s%04d.xml", file.c_str(), prefix.c_str(), exportCounter); + return bf; +} \ No newline at end of file diff --git a/code/onlineresults.h b/code/onlineresults.h new file mode 100644 index 0000000..8e2946f --- /dev/null +++ b/code/onlineresults.h @@ -0,0 +1,69 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "TabAuto.h" + +class InfoCompetition; + +class OnlineResults : + public AutoMachine +{ +protected: + string file; + string url; + string passwd; + string prefix; + int cmpId; + set classes; + int dataType; + bool zipFile; + bool sendToURL; + bool sendToFile; + mutable InfoCompetition *infoServer; + string exportScript; + int exportCounter; + void enableURL(gdioutput &gdi, bool state); + void enableFile(gdioutput &gdi, bool state); + + string getExportFileName() const; + int bytesExported; + DWORD lastSync; + + vector errorLines; + void formatError(gdioutput &gdi); + +public: + + int processButton(gdioutput &gdi, ButtonInfo &bi); + InfoCompetition &getInfoServer() const; + + void save(oEvent &oe, gdioutput &gdi); + void settings(gdioutput &gdi, oEvent &oe, bool created); + OnlineResults *clone() const {return new OnlineResults(*this);} + void status(gdioutput &gdi); + void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast); + OnlineResults() : AutoMachine("Onlineresultat") , infoServer(0), dataType(1), zipFile(true), sendToURL(false), sendToFile(false), + cmpId(0), exportCounter(1), bytesExported(0), lastSync(0) {} + ~OnlineResults(); + friend class TabAuto; +}; diff --git a/code/ospeaker.h b/code/ospeaker.h new file mode 100644 index 0000000..208658f --- /dev/null +++ b/code/ospeaker.h @@ -0,0 +1,89 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +class oRunner; +#include "gdifonts.h" +#include "gdioutput.h" + +struct SpeakerString { + string str; + int format; + bool hasTimer; + int timer; + int timeout; + string moveKey; + GDICOLOR color; + SpeakerString() : format(0), hasTimer(false), timer(0), timeout(NOTIMEOUT), color(colorDefault) {} + SpeakerString(int formatIn, const string &in) : str(in), format(formatIn), hasTimer(false), + timer(0), timeout(NOTIMEOUT), color(colorDefault) {} + SpeakerString(int formatIn, int timerIn, int timeoutIn = NOTIMEOUT) : format(formatIn), + hasTimer(true), timer(timerIn), + timeout(timeoutIn), color(colorDefault) {} +}; + +class oSpeakerObject +{ +public: + struct RunningTime { + int time; + int preliminary; + RunningTime() : time(0), preliminary(0) {} + }; + + oRunner *owner; + string bib; + vector names; + vector outgoingnames; + string resultRemark; + string club; + string startTimeS; + + bool useSinceLast; + int place; + int parallelScore; + + // For parallel legs + int runnersFinishedLeg; + int runnersTotalLeg; + + RunnerStatus status; + RunnerStatus finishStatus; + + RunningTime runningTime; + RunningTime runningTimeLeg; + RunningTime runningTimeSinceLast; + + bool isRendered; + int priority; + bool missingStartTime; + + // In seconds. Negative if undefined. + int timeSinceChange; + + oSpeakerObject() : owner(0), place(0), parallelScore(0), status(StatusUnknown), + finishStatus(StatusUnknown), isRendered(false), + priority(0), missingStartTime(false), timeSinceChange(-1), useSinceLast(false), + runnersFinishedLeg(0), runnersTotalLeg(0) {} + +}; + diff --git a/code/parser.cpp b/code/parser.cpp new file mode 100644 index 0000000..e0066b8 --- /dev/null +++ b/code/parser.cpp @@ -0,0 +1,1632 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include +#include +#include +#include "parser.h" +#include "meosException.h" +#include "meos_util.h" +#include +#include +#include "gdioutput.h" +#include "gdifonts.h" +#include "localizer.h" + +static string readWord(const string &expr, size_t &pos) { + bool pureNum = true; + bool firstNum = false; + bool first = true; + string res; + while (pos < expr.size() && isalnum(expr[pos])) { + res.push_back(expr.at(pos)); + if (!isdigit(expr[pos])) + pureNum = false; + else if (first) + firstNum = true; + + first = false; + pos++; + } + + if (firstNum && !pureNum) + throw meosException("Invalid symbol X#" + res); + + return res; +} + +static void matchSE(const string &expr, size_t &pos, char start, char end) { + assert(expr[pos] == start); + int count = 1; + pos++; + while (pos < expr.size() && count>0) { + if (expr[pos] == start) + count++; + else if (expr[pos] == end) + count--; + pos++; + } + if (count != 0) { + string ss, ee; + ss.push_back(start); + ee.push_back(end); + throw meosException("Mismatch of X and Y#" + ss + "#" + ee); + } +} + +static void splitStatements(const string &expr, char separator, const map &se, vector &statements) { + size_t p = 0; + size_t pold = 0; + while (p < expr.size()) { + if (expr[p] == separator) { + string ex2 = trim(expr.substr(pold, p-pold)); + if (!ex2.empty()) + statements.push_back(ex2); + pold = ++p; + } + else if (se.find(expr[p]) != se.end()) { + int cut = 0; + //if (pold == p) + // cut = 1; + + matchSE(expr, p, expr[p], se.find(expr[p])->second); + string ex2 = trim(expr.substr(pold+cut, p-pold-2*cut)); + pold = p; + + //if (ex2.back() == separator) + // ex2.pop_back(); + if (!ex2.empty()) + statements.push_back(ex2); + } + else if (expr[p] == '(') { + matchSE(expr, p, '(', ')'); + } + else + p++; + } + if (p-pold > 0) { + string end = trim(expr.substr(pold, p-pold)); + if (end.length() > 0) + statements.push_back(end); + } +} + +ParseNode *Parser::parseif (const string &expr, size_t &pos) { + eatWhite(expr, pos); + if (expr[pos] != '(') + throw meosException("Expected ( after if,\nX#" + expr); + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + + IfNode *ifn = getif (); + ifn->condition = parseStatement(expr.substr(start, pos - start - 1), false); + eatWhite(expr, pos); + + ifn->iftrue = parseStatement(expr.substr(pos), true); + + return ifn; +} + +ParseNode *Parser::parseReturn(const string &expr, size_t &pos) { + UnaryOperatorNode *un = getUnary(); + un->right = parseStatement(expr.substr(pos), false); + un->op = OpReturn; + return un; +} + +ParseNode *Parser::parseWhile(const string &expr, size_t &pos) { + eatWhite(expr, pos); + if (expr[pos] != '(') + throw meosException("Expected ( after while,\nX#" + expr); + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + + WhileNode *wh = getWhile(); + wh->condition = parseStatement(expr.substr(start, pos - start - 1), false); + eatWhite(expr, pos); + + wh->body = parseStatement(expr.substr(pos), true); + + return wh; +} + +ParseNode *Parser::parseFor(const string &expr, size_t &pos) { + eatWhite(expr, pos); + if (expr[pos] != '(') + throw meosException("Expected ( after while,\nX#" + expr); + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + map se; + vector parts; + splitStatements(expr.substr(start, pos - start - 1), ';', se, parts); + + if (parts.size() != 3) + throw meosException("Syntax error in for(.;.;.),\nX#" + expr); + + ForNode *fn = getFor(); + if (!trim(parts[0]).empty()) + fn->start = parseStatement(parts[0], false); + else + fn->start = getStatement(); + + fn->condition = parseStatement(parts[1], false); + + if (!trim(parts[2]).empty()) + fn->update = parseStatement(parts[2], false); + else + fn->update = getStatement(); + + eatWhite(expr, pos); + + fn->body = parseStatement(expr.substr(pos), true); + return fn; +} + +int Parser::getLevel(Operator op) { + switch (op) { + case OpNone: + return -1; + case OpPlus: + case OpMinus: + return 2; + case OpTimes: + case OpDivide: + case OpMod: + return 3; + + case OpMax: + case OpMin: + case OpInc: + case OpDec: + return 4; + + case OpEquals: + case OpNotEquals: + case OpLess: + case OpMore: + case OpLessEquals: + case OpMoreEquals: + return 1; + + case OpAnd: + case OpOr: + return 0; + + case OpAssign: + return 0; + } + + return -1; +} + +string Parser::parseMethod(const string &expr, size_t &pos) { + pos++; + string sword = readWord(expr, pos); + eatWhite(expr, pos); + if (expr[pos] != '(') + throw meosException("Expected ( after X#" + sword); + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + if (trim(expr.substr(start, pos-start-1)).size() > 0) + throw meosException("No arguments expected for X()#" + sword); + + return sword; +} + +ParseNode *Parser::parseValue(const string &word, const string &expr, size_t &pos) { + eatWhite(expr, pos); + if (expr[pos] == '[' || expr[pos] == '.') { + if (isdigit(word[0])) + throw meosException("Invalid operator in litteral,\nX#" + expr); + + if (expr[pos] == '[') { + size_t start = pos + 1; + matchSE(expr, pos, '[', ']'); + ArrayValueNode *arr = getArrayValue(); + arr->expr = word; + arr->index = parseStatement(expr.substr(start, pos-start-1), false); + + eatWhite(expr, pos); + if (expr[pos] == '[') { + start = pos + 1; + matchSE(expr, pos, '[', ']'); + arr->index2 = arr->index; + arr->index = parseStatement(expr.substr(start, pos-start-1), false); + } + else if (expr[pos] == '.') { + string sword = parseMethod(expr, pos); + if (sword != "size") { + throw meosException("Unknown method X#" + word + "." + sword); + } + UnaryOperatorNode *un = getUnary(); + un->op = OpSizeSub; + un->right = arr; + return un; + } + + return arr; + } + else if (expr[pos] == '.') { + string sword = parseMethod(expr, pos); + UnaryOperatorNode *un = getUnary(); + un->op = OpNone; + + if (sword == "size") { + if (isMatrix(word)) + un->op = OpSizeBase; + else + un->op = OpSize; + } + else if (sword == "sort") { + un->op = OpSortArray; + } + + if (un->op != OpNone) { + ValueNode *vn = getValue(); + vn->value = word; + un->right = vn; + return un; + } + else + throw meosException("Unknown method X#" + word + "." + sword); + } + } + ValueNode *vn = getValue(); + vn->value = word; + return vn; +} + + +ParseNode *Parser::parseFunction(const string &name, const string &expr, size_t &pos) { + Operator op = OpNone; + + if (name == "if" || name == "for" || name == "while" || name == "break" || name == "return") + throw meosException("Unexpected " + name + ",\n#" + expr); + + if (name == "max") + op = OpMax; + else if (name == "min") + op = OpMin; + + if (op == OpNone) + return 0; + + eatWhite(expr, pos); + + if (expr[pos] != '(') + throw meosException("Expected (,\nX#" + expr); + + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + + //splitStatements + map se; + se['('] = ')'; + vector arg; + splitStatements(expr.substr(start, pos-start-1), ',', se, arg); + + if (arg.size() != 2) + throw meosException("Expected 2 arguments, got X,\nY#"+itos(arg.size()) + "#" + expr); + + BinaryOperatorNode *bin = getBinary(); + bin->left = parseStatement(arg[0], false); + bin->right = parseStatement(arg[1], false); + bin->op = op; + + return bin; +} + + +Parser::Operator Parser::parseOperator(const string &expr, size_t &pos, int level) { + size_t npos = pos; + Operator op = parseOperatorAux(expr, npos); + + if (op == OpNone || getLevel(op) != level) + return OpNone; + pos = npos; + return op; +} + +void Parser::eatWhite(const string &expr, size_t &pos) { + while (pos < expr.size() && isspace(expr.at(pos))) { + pos++; + } +} + +Parser::Operator Parser::parseOperatorAux(const string &expr, size_t &pos) { + eatWhite(expr, pos); + + size_t pos2 = pos; + string opWord = readWord(expr, pos2); + if (opWord == "or") { + pos = pos2; + return OpOr; + } + else if (opWord == "and") { + pos = pos2; + return OpAnd; + } + + if (pos < expr.size()) { + char p1 = 0, p2 = 0; + p1 = expr[pos++]; + if (pos < expr.size() && p1 != '(' && p1 != ')' ) { + p2 = expr[pos++]; + if (p2 == 0 || isalnum(p2) || isspace(p2) || (p2 == '-' && p1 != '-') || + p2 == '!' || (p2 == '+' && p1 != '+') || p2=='(') { + pos--; + p2 = 0; + } + } + + if (p1 == '(') + return OpLeftP; + else if (p1 == ')') + return OpRightP; + else if (p1 == '=' && p2 == '=') + return OpEquals; + else if (p1 == '=' && p2 == 0) + return OpAssign; + else if (p1 == '!' && p2 == '=') + return OpNotEquals; + else if (p1 == '<' && p2 == '=') + return OpLessEquals; + else if (p1 == '>' && p2 == '=') + return OpMoreEquals; + else if (p1 == '<' && p2 == 0) + return OpLess; + else if (p1 == '>' && p2 == 0) + return OpMore; + else if (p1 == '+' && p2 == 0) + return OpPlus; + else if (p1 == '-' && p2 == 0) + return OpMinus; + else if (p1 == '*' && p2 == 0) + return OpTimes; + else if (p1 == '/' && p2 == 0) + return OpDivide; + else if (p1 == '%' && p2 == 0) + return OpMod; + else if (p1 == '&' && p2 == '&') + return OpAnd; + else if (p1 == '|' && p2 == '|') + return OpOr; + else if (p1 == '!' && p2 == 0) + return OpNot; + else if (p1 == '+' && p2 == '+') + return OpInc; + else if (p1 == '-' && p2 == '-') + return OpDec; + + string op = expr.substr(0, 10); + throw meosException("Invalid operator X#" + op); + } + return OpNone; +} + +// 3*2 + 4*4 == 5 + +ParseNode *Parser::parseStatement(ParseNode *left, const string &expr, + size_t &pos, int level, bool reverseSign) { + eatWhite(expr, pos); + if (pos == expr.length()) + return left; + Operator op = parseOperator(expr, pos, level); + while (op == OpNone) { + if (level <= levelMax) { + ParseNode *newLeft = parseStatement(left, expr, pos, level + 1, reverseSign); + if (newLeft == left) + return left; + else + left = newLeft; + } + else + return left; + + op = parseOperator(expr, pos, level); + } + + if (op == OpInc || op == OpDec) { + UnaryOperatorNode *un = getUnary(); + un->op = op == OpInc ? OpIncPost : OpDecPost; + un->right = left; + return un; + } + + if (reverseSign) { + if (op == OpMinus) { + op = OpPlus; + } + else if (op == OpPlus) { + op = OpMinus; + reverseSign = false; + } + } + else if (op == OpMinus) { + reverseSign = true; + } + + if (op == OpAssign && !left->isVariable()) { + throw meosException("Invalid assignment X#" + expr); + } + + BinaryOperatorNode *bin = getBinary(); + bin->left = left; + bin->op = op; + + eatWhite(expr, pos); + + if (op == OpAssign) { + bin->right = parseStatement(expr.substr(pos),false); + return bin; + } + /*else if (expr[pos] == '(') { + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + string subExpr = expr.substr(start, pos-start-1); + ParseNode *pn = parseStatement(subExpr, false); + bin->right = parseStatement(pn, expr, pos, level); + + //bin->right = parseStatement(subExpr, false); + return bin; + }*/ + else { + size_t pos2 = pos; + Operator op2 = OpNone; + if (!isalnum(expr[pos])) { + op2 = parseOperatorAux(expr, pos2); + if (op2 == OpMinus || op2 == OpPlus || op2 == OpNot) { + pos = pos2; + } + else if (op2 == OpInc) { + pos = pos2; + op2 = OpIncPre; + } + else if (op2 == OpDec) { + pos = pos2; + op2 = OpDecPre; + } + else if (op2 == OpLeftP) { + op2 = OpNone; + } + else if (op2 != OpNone) { + throw meosException("Syntax error,\nX#" + expr); + } + eatWhite(expr, pos); + } + + if (expr[pos] == '(') { + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + string subExpr = expr.substr(start, pos-start-1); + ParseNode *pn = parseStatement(subExpr, false); + + if (op2 != 0) { + UnaryOperatorNode *un = getUnary(); + un->op = op2; + un->right = pn; + pn = un; + } + + bin->right = parseStatement(pn, expr, pos, level, false); + + //bin->right = parseStatement(subExpr, false); + return bin; + } + else if (isalnum(expr[pos])) { + string word = readWord(expr, pos); + ParseNode *right; + ParseNode *pn = parseFunction(word, expr, pos); + if (pn != 0) { + if (op2 != 0) { + UnaryOperatorNode *un = getUnary(); + un->op = op2; + un->right = pn; + pn = un; + } + right = parseStatement(pn, expr, pos, level, reverseSign); + } + else if (!word.empty()) { + ParseNode *vn = parseValue(word, expr, pos); + //ValueNode *vn = getValue(); + //vn->value = word; + pn = vn; + if (op2 != 0) { + UnaryOperatorNode *un = getUnary(); + un->op = op2; + un->right = pn; + pn = un; + } + right = parseStatement(pn, expr, pos, level, reverseSign); + } + else { + throw meosException("Unexpected ending operator X#" + expr); + } + + bin->right = right; + return bin; + } + } + throw meosException("Syntax error,\nX#" + expr); +} + +ParseNode *Parser::parseStatement(const string &expr, bool primary) { + size_t pos = 0; + eatWhite(expr, pos); + ParseNode *left = 0; + if (expr[pos] == '(') { + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + string subExpr = expr.substr(start, pos-start-1); + left = parseStatement(subExpr, false); + } + else if (expr[pos] == '{') { + if (!primary) + throw meosException("Unexpeccted {,\nX" + expr); + size_t start = pos + 1; + matchSE(expr, pos, '{', '}'); + string subExpr = expr.substr(start, pos-start-1); + return parse(subExpr); + } + else { + size_t pos2 = pos; + Operator op2 = OpNone; + if (!isalnum(expr[pos])) { + op2 = parseOperatorAux(expr, pos2); + if (op2 == OpMinus || op2 == OpPlus || op2 == OpNot) { + pos = pos2; + } + else if (op2 == OpInc) { + pos = pos2; + op2 = OpIncPre; + } + else if (op2 == OpDec) { + pos = pos2; + op2 = OpDecPre; + } + else if (op2 != OpNone) { + throw meosException("Syntax error,\nX#" + expr); + } + primary = false; + } + + eatWhite(expr, pos); + if (op2 != OpNone && expr[pos] == '(') { + size_t start = pos + 1; + matchSE(expr, pos, '(', ')'); + string subExpr = expr.substr(start, pos-start-1); + UnaryOperatorNode *un = getUnary(); + un->op = op2; + un->right = parseStatement(subExpr, false); + left = un; + } + else if (isalnum(expr[pos])) { + string word = readWord(expr, pos); + if (word == "if") { + if (!primary) + throw meosException("Unexpected if\nX#" + expr); + return parseif (expr, pos); + } + else if (word == "return") { + if (!primary) + throw meosException("Unexpected return\nX#" + expr); + return parseReturn(expr, pos); + } + else if (word == "while") { + if (!primary) + throw meosException("Unexpected while\nX#" + expr); + return parseWhile(expr, pos); + } + else if (word == "for") { + if (!primary) + throw meosException("Unexpected for\nX#" + expr); + return parseFor(expr, pos); + } + else if (word == "break") { + if (!primary) + throw meosException("Unexpected break\nX#" + expr); + UnaryOperatorNode *un = getUnary(); + un->op = OpBreak; + return un; + } + + left = parseFunction(word, expr, pos); + + if (left == 0) { + //ValueNode *vn = getValue(); + //vn->value = word; + left = parseValue(word, expr, pos); + } + + if (op2 != OpNone) { + UnaryOperatorNode *un = getUnary(); + un->op = op2; + un->right = left; + left = un; + } + } + else + throw meosException("Syntax error,\nX#" + expr); + } + ParseNode *node = parseStatement(left, expr, pos, 0, false); + + if (node == 0) + throw meosException("Syntax error,\nX#" + expr); + + return node; +} + +ParseNode *Parser::parse(const string &expr) { + vector lines; + split(expr, "\n", lines); + string exprNoComments; + exprNoComments.reserve(expr.size()+4); + for (size_t k = 0; k < lines.size(); k++) { + int ix = lines[k].find("//"); + if (ix != lines[k].npos) + exprNoComments.append(lines[k].substr(0, ix)); + else + exprNoComments.append(lines[k]); + + exprNoComments.append("\n"); + } + + vector spv; + map se; + se['{'] = '}'; + splitStatements(exprNoComments, ';', se, spv); + /*for (size_t k = 0; k < spv.size(); k++) { + int ix = spv[k].find_first_of("//"); + if (ix != spv[k].npos) + spv[k] = trim(spv[k].substr(0, ix)); + }*/ + + if (spv.size() == 1) + return parseStatement(spv[0], true); + else { + StatementNode *sn = getStatement(); + ParseNode *ret = sn; + StatementNode *oldSN = 0; + for (size_t k = 0; k < spv.size(); k++) { + size_t pos = 0; + eatWhite(spv[k], pos); + if (readWord(spv[k], pos) == "else") { + if (oldSN != 0 && typeid(*(oldSN->node))==typeid(IfNode)) { + oldSN->next = 0; + sn = oldSN; + IfNode *ifn = dynamic_cast(sn->node); + while (ifn != 0 && ifn->iffalse) { + ifn = dynamic_cast(ifn->iffalse); + } + if (ifn) { + oldSN = 0; + ifn->iffalse = parseStatement(spv[k].substr(pos), true); + } + else + throw meosException("else without matching if,\nX#" + spv[k]); + } + else + throw meosException("else without matching if,\nX#" + spv[k]); + } + else + sn->node = parseStatement(spv[k], true); + + if (k+1 < spv.size()) + sn->next = getStatement(); + oldSN = sn; + sn = sn->next; + } + return ret; + } +} + +int Parser::evaluate(const string &input) const { + if (input.empty()) + throw meosException("Empty expression"); + + if (isdigit(input[0])) + return atoi(input.c_str()); + + { + map::const_iterator res = symb.find(input); + if (res != symb.end()) { + if (res->second.value.empty()) + throw meosException("Internal error"); + if (res->second.value[0].size() == 1) + return res->second.value[0][0]; + throw meosException("X is an array.#" + input); + } + } + + map >::iterator res = var.find(input); + if (res != var.end()) { + if (res->second.size() == 1) + return res->second[0]; + throw meosException("X is an array.#" + input); + } + throw meosException("Unknown symbol X#" + input); +} + +int Parser::evaluate(const string &input, int index, int index2) const { + if (input.empty()) + throw meosException("Empty expression"); + + if (isdigit(input[0])) + return atoi(input.c_str()); + + map::const_iterator res = symb.find(input); + if (res != symb.end()) { + if (size_t(index2) < res->second.value.size() && + size_t(index) < res->second.value[index2].size()) + return res->second.value[index2][index]; + if (index2 == 0) + throw meosException("Index X in Y is out of range.#" + itos(index) + "#" + input); + else + throw meosException("Index X in Y is out of range.#" + itos(index2) + "," + itos(index) + "#" + input); + } + + map >::const_iterator res2 = var.find(input); + if (res2 != var.end()) { + if (index2 != 0) + throw meosException("Index X in Y is out of range.#" + itos(index2) + "#" + input); + if (size_t(index) < res2->second.size()) + return res2->second[index]; + throw meosException("Index X in Y is out of range.#" + itos(index) + "#" + input); + } + throw meosException("Unknown symbol X#" + input); +} + +int Parser::evaluateSize(const string &input, int index) const { + if (input.empty()) + throw meosException("Empty expression"); + + if (isdigit(input[0])) + throw meosException("Constant expression"); + { + map::const_iterator res = symb.find(input); + + if (res != symb.end()) { + if (index == -1) + return res->second.value.size(); + else { + if (size_t(index) < res->second.value.size()) + return res->second.value[index].size(); + else + throw meosException("Index out of range for X.#" + input); + } + } + } + + map >::const_iterator res = var.find(input); + if (res != var.end()) { + if (index != 0) + throw meosException("Index out of range for X.#" + input); + return res->second.size(); + } + throw meosException("Unknown symbol X#" + input); +} + +void Parser::sortArray(const string &input) const { + map >::iterator res = var.find(input); + if (res != var.end()) { + sort(res->second.begin(), res->second.end()); + return; + } + throw meosException("Unknown symbol X#" + input); +} + +void Parser::storeVariable(const string &input, const vector &value) const { + if (symb.count(input)) + throw meosException("Duplicate symbol X#" + input); + var[input] = value; +} + +void Parser::storeVariable(const string &input, int value) const { + if (symb.count(input)) + throw meosException("Duplicate symbol X#" + input); + vector &iv = var[input]; + iv.resize(1); + iv[0] = value; +} + +void Parser::storeVariable(const string &input, int index, int value) const { + if (symb.count(input)) + throw meosException("Duplicate symbol X#" + input); + if (index < 0 || index>1024) + throw meosException("Index out of range for X.#" + input); + + vector &iv = var[input]; + if (iv.size() <= size_t(index)) + iv.resize(index+1); + iv[index] = value; +} + +Parser::Parser() { + +} + +Parser::~Parser() { + clear(); +} + +void Parser::clear() { + for (size_t k = 0; k < nodes.size(); k++) { + delete nodes[k]; + nodes[k] = 0; + } + nodes.clear(); +} + +Parser::UnaryOperatorNode *Parser::getUnary() { + nodes.push_back(new UnaryOperatorNode()); + return (UnaryOperatorNode *)nodes.back(); +} + +Parser::BinaryOperatorNode *Parser::getBinary() { + nodes.push_back(new BinaryOperatorNode()); + return (BinaryOperatorNode *)nodes.back(); +} + +Parser::ValueNode *Parser::getValue() { + nodes.push_back(new ValueNode()); + return (ValueNode *)nodes.back(); +} + +Parser::ArrayValueNode *Parser::getArrayValue() { + nodes.push_back(new ArrayValueNode()); + return (ArrayValueNode *)nodes.back(); +} + +Parser::StatementNode *Parser::getStatement() { + nodes.push_back(new StatementNode()); + return (StatementNode *)nodes.back(); +} + +Parser::IfNode *Parser::getif () { + nodes.push_back(new IfNode()); + return (IfNode *)nodes.back(); +} + +Parser::WhileNode *Parser::getWhile() { + nodes.push_back(new WhileNode()); + return (WhileNode *)nodes.back(); +} + +Parser::ForNode *Parser::getFor() { + nodes.push_back(new ForNode()); + return (ForNode *)nodes.back(); +} + +ParseNode::~ParseNode() { +} + + +Parser::StatementNode::StatementNode() { + node = 0; + next = 0; +} + +Parser::StatementNode::~StatementNode() { + node = 0; + next = 0; +} + +int Parser::StatementNode::evaluate(const Parser &parser) const { + if (node == 0) + throw meosException("Nullpointer"); + parser.returnMode = false; + parser.breakMode = 0; + const StatementNode *c = this; + int ret = 0; + while(c && !parser.returnMode) { + parser.ignoreValue = false; + int val = c->node->evaluate(parser); + if (!parser.ignoreValue) + ret = val; + if (parser.breakMode>0) { + break; + } + c = c->next; + } + return ret; +} + +Parser::ValueNode::ValueNode() { +} +Parser::ValueNode::~ValueNode() { +} + +int Parser::ValueNode::evaluate(const Parser &parser) const { + return parser.evaluate(value); +} +bool Parser::ValueNode::isVariable() const { + return value.length()>0 && isalpha(value[0]); +} + +Parser::BinaryOperatorNode::BinaryOperatorNode() { + left = 0; + right = 0; +} + +Parser::BinaryOperatorNode::~BinaryOperatorNode() { + left = 0; + right = 0; +} + +int Parser::BinaryOperatorNode::evaluate(const Parser &parser) const { + if (left == 0 || right == 0) + throw meosException("Internal error"); + + switch (op) { + case OpPlus: + return left->evaluate(parser) + right->evaluate(parser); + case OpMinus: + return left->evaluate(parser) - right->evaluate(parser); + case OpTimes: + return left->evaluate(parser) * right->evaluate(parser); + case OpDivide: + return left->evaluate(parser) / right->evaluate(parser); + case OpMod: + return left->evaluate(parser) % right->evaluate(parser); + + case OpEquals: + return left->evaluate(parser) == right->evaluate(parser); + case OpNotEquals: + return left->evaluate(parser) != right->evaluate(parser); + case OpLess: + return left->evaluate(parser) < right->evaluate(parser); + case OpLessEquals: + return left->evaluate(parser) <= right->evaluate(parser); + case OpMore: + return left->evaluate(parser) > right->evaluate(parser); + case OpMoreEquals: + return left->evaluate(parser) >= right->evaluate(parser); + + case OpOr: + return left->evaluate(parser) || right->evaluate(parser); + case OpAnd: + return left->evaluate(parser) && right->evaluate(parser); + + case OpMax: + return max(left->evaluate(parser), right->evaluate(parser)); + case OpMin: + return min(left->evaluate(parser), right->evaluate(parser)); + + case OpAssign: { + ValueNode *vn = dynamic_cast(right); + if (vn != 0) { + if (parser.isMatrix(vn->value)) + throw meosException("Cannot assign matrix X#"+vn->value); + if (parser.isVector(vn->value)) { + left->assignVector(parser, parser.getVector(vn->value, 0)); + parser.ignoreValue = true; + return -1; + } + } + ArrayValueNode *avn = dynamic_cast(right); + if (avn != 0 && parser.isMatrix(avn->expr) && avn->index2 == 0) { + left->assignVector(parser, parser.getVector(avn->expr, avn->index->evaluate(parser))); + parser.ignoreValue = true; + return -1; + } + + int val = right->evaluate(parser); + left->assign(parser, val); + return val; + } + + } + + throw meosException("Internal error, unknown operator"); +} + + +Parser::UnaryOperatorNode::UnaryOperatorNode() { + right = 0; +} + +Parser::UnaryOperatorNode::~UnaryOperatorNode() { + right = 0; +} + +int Parser::UnaryOperatorNode::evaluate(const Parser &parser) const { + if (op == OpBreak) { + parser.ignoreValue = true; + parser.breakMode = 1; + return -1; + } + + if (right == 0) + throw meosException("Internal error"); + + switch (op) { + case OpReturn: { + int val = right->evaluate(parser); + parser.returnMode = true; + return val; + } + case OpMinus: + return -right->evaluate(parser); + case OpNot: { + return right->evaluate(parser) == 0; + } + case OpPlus: + return right->evaluate(parser); + case OpIncPost: { + int val = right->evaluate(parser); + right->assign(parser, val + 1); + return val; + } + case OpDecPost: { + int val = right->evaluate(parser); + right->assign(parser, val-1); + return val; + } + case OpIncPre: { + int val = right->evaluate(parser) + 1; + right->assign(parser, val); + return val; + } + case OpDecPre: { + int val = right->evaluate(parser) - 1; + right->assign(parser, val); + return val; + } + case OpSize: { + ValueNode &vn= dynamic_cast(*right); + return parser.evaluateSize(vn.value, 0); + } + case OpSizeBase: { + ValueNode &vn= dynamic_cast(*right); + return parser.evaluateSize(vn.value, -1); + } + case OpSizeSub: { + ArrayValueNode &vn= dynamic_cast(*right); + return parser.evaluateSize(vn.expr, vn.index->evaluate(parser)); + } + case OpSortArray: { + ValueNode &vn= dynamic_cast(*right); + parser.sortArray(vn.value); + parser.ignoreValue = true; + return -1; + } + } + + throw meosException("Internal error, unknown operator"); +} + +Parser::IfNode::IfNode() { + condition = 0; + iftrue = 0; + iffalse = 0; +} + +Parser::IfNode::~IfNode() { + condition = 0; + iftrue = 0; + iffalse = 0; +} + +int Parser::IfNode::evaluate(const Parser &parser) const { + if (condition->evaluate(parser) != 0) { + return iftrue->evaluate(parser); + } + if (iffalse) + return iffalse->evaluate(parser); + + parser.ignoreValue = true; + return -1; +} + +Parser::WhileNode::WhileNode() { + condition = 0; + body = 0; +} + +Parser::WhileNode::~WhileNode() { + condition = 0; + body = 0; +} + +int Parser::WhileNode::evaluate(const Parser &parser) const { + if (condition == 0 || body == 0) + throw meosException("Internal error in while"); + int maxCount = 1000; + int ret = -1; + bool used = false; + while (condition->evaluate(parser) != 0 && !parser.returnMode && --maxCount > 0) { + ret = body->evaluate(parser); + if (parser.breakMode>0) { + parser.breakMode--; + break; + } + used = true; + } + if (maxCount <= 0) { + throw meosException("Stalled while loop"); + } + + if (!used) + parser.ignoreValue = true; + return ret; +} + + +Parser::ForNode::ForNode() { + condition = 0; + start = 0; + update = 0; + body = 0; +} + +Parser::ForNode::~ForNode() { + condition = 0; + start = 0; + update = 0; + body = 0; +} + +int Parser::ForNode::evaluate(const Parser &parser) const { + if (start == 0 || condition == 0 || update == 0 || body == 0) + throw meosException("Internal error in for"); + int maxCount = 1000; + int ret = -1; + bool used = false; + for (start->evaluate(parser); + condition->evaluate(parser) != 0 && !parser.returnMode && --maxCount > 0; + update->evaluate(parser) ) { + ret = body->evaluate(parser); + used = true; + } + if (maxCount <= 0) { + throw meosException("Stalled for loop"); + } + + if (!used) + parser.ignoreValue = true; + return ret; +} + +Parser::ArrayValueNode::ArrayValueNode() { + index = 0; + index2 = 0; +} +Parser::ArrayValueNode::~ArrayValueNode() { + index = 0; + index2 = 0; +} + +int Parser::ArrayValueNode::evaluate(const Parser &parser) const { + if (index2 == 0) + return parser.evaluate(expr, index->evaluate(parser), 0); + else + return parser.evaluate(expr, index->evaluate(parser), index2->evaluate(parser)); +} + +bool Parser::ArrayValueNode::isVariable() const { + return true; +} + +void ParseNode::assign(const Parser &parser, int value) const { + throw meosException("Illegal assignment"); +} + +void ParseNode::assignVector(const Parser &parser, const vector &value) const { + throw meosException("Illegal assignment"); +} + +void Parser::ValueNode::assign(const Parser &parser, int in_value) const { + parser.storeVariable(value, in_value); +} + +void Parser::ValueNode::assignVector(const Parser &parser, const vector &in_value) const { + parser.storeVariable(value, in_value); +} + + +void Parser::ArrayValueNode::assign(const Parser &parser, int value) const { + int ix2; + if (index2 != 0 && (ix2 = index2->evaluate(parser)) != 0) + throw meosException("Index X in Y is out of range.#" + itos(ix2) + "#" + expr); + parser.storeVariable(expr, index->evaluate(parser), value); +} + +void Parser::ArrayValueNode::assignVector(const Parser &parser, const vector &in_value) const { + if (in_value.size() != 1) + throw meosException("Vector cannot be assigned to X[i]#" + expr); + parser.storeVariable(expr, index->evaluate(parser), in_value[0]); +} + +void Parser::declareSymbol(const char *name, const string &desc, bool isVector, bool isMatrix) { + assert(symb.count(name) == 0 || (symb[name].isVector == isVector && symb[name].isMatrix == isMatrix)); + symb[name].desc = desc; + symb[name].isVector = isVector; + symb[name].isMatrix = isMatrix; +} + +bool Parser::isMatrix(const string &input) const { + map::const_iterator res = symb.find(input); + return res != symb.end() && res->second.isMatrix; +} + +bool Parser::isVector(const string &input) const { + map::const_iterator res = symb.find(input); + if (res != symb.end()) + return !res->second.isMatrix && res->second.value[0].size() != 1; + + map >::const_iterator resv = var.find(input); + return resv != var.end() && resv->second.size() != 1; +} + +const vector &Parser::getVector(const string &symbol, int index) const{ + map::const_iterator res = symb.find(symbol); + if (res != symb.end()) { + if (size_t(index) < res->second.value.size()) + return res->second.value[index]; + else + throw meosException("Index out of range for X.#" + symbol); + } + map >::const_iterator resv = var.find(symbol); + if (resv != var.end()) + return resv->second; + + throw meosException("Unknown symbol X#" + symbol); +} + +void Parser::addSymbol(const char *name, const string &value) { + assert(symb.count(name) && !symb[name].isVector); + symb[name].value.resize(1); + vector &v = symb[name].value[0]; + v.resize(1); + v[0] = atoi(value.c_str()); +} + +void Parser::addSymbol(const char *name, int value) { + assert(symb.count(name) && !symb[name].isVector); + symb[name].value.resize(1); + vector &v = symb[name].value[0]; + v.resize(1); + v[0] = value; +} + +void Parser::addSymbol(const char *name, const vector &value) { + assert(symb.count(name) && symb[name].isVector); + symb[name].value.resize(1); + vector &v = symb[name].value[0]; + v.resize(value.size()); + for (size_t k = 0; k < value.size(); k++) + v[k] = atoi(value[k].c_str()); +} + +void Parser::addSymbol(const char *name, const vector &value) { + assert(symb.count(name) && symb[name].isVector); + symb[name].value.resize(1); + symb[name].value[0] = value; +} + +void Parser::addSymbol(const char *name, vector< vector > &value) { + assert(symb.count(name) && symb[name].isVector); + symb[name].value.swap(value); +} + +void Parser::removeSymbol(const char *name) { + symb[name].value.clear(); +} + +void Parser::clearSymbols() { + symb.clear(); +} + +void Parser::clearVariables() const { + var.clear(); +} + +void Parser::takeVariable(const char*name, vector &val) const { + map >::iterator resv = var.find(name); + if (resv != var.end()) { + vector &res = resv->second; + val.swap(res); + } + else + val.clear(); +} + +void Parser::getSymbols(vector< pair > &symbOut) const { + int iter = 0; + for(map::const_iterator it = symb.begin(); it != symb.end(); ++it) { + if (it->second.isMatrix) + symbOut.push_back(make_pair(it->first + "[][]\t" + lang.tl(it->second.desc), iter++)); + else if (it->second.isVector) + symbOut.push_back(make_pair(it->first + "[]\t" + lang.tl(it->second.desc), iter++)); + else + symbOut.push_back(make_pair(it->first + "\t" + lang.tl(it->second.desc), iter++)); + } +} + +void Parser::getSymbolInfo(int ix, string &name, string &desc) const { + int iter = 0; + for(map::const_iterator it = symb.begin(); it != symb.end(); ++it) { + if (ix == iter++) { + if (it->second.isMatrix) + name = it->first + "[][]"; + else if (it->second.isVector) + name = it->first + "[]"; + else + name = it->first; + desc = it->second.desc; + + return; + } + } + throw meosException("Internal error"); +} + + +static void assertEq(int a, int b) { + if (a != b) { + string s = "Expected X, was Y#" + itos(a) + "#" + itos(b); + throw s; + } +} + +void Parser::test() { + Parser parser; + vector tt; + tt.push_back(1); + tt.push_back(4); + tt.push_back(9); + parser.declareSymbol("tt", "", true); + parser.declareSymbol("tt2", "", true); + parser.declareSymbol("ttt", "", true, true); + parser.declareSymbol("t", "", false); + + vector tt2; + + tt2.push_back(3); + tt2.push_back(4); + tt2.push_back(2); + tt2.push_back(1); + + parser.addSymbol("tt", tt); + parser.addSymbol("tt2", tt2); + parser.addSymbol("t", 3); + vector< vector > ttt; + ttt.push_back(tt); + ttt.push_back(tt); + ttt.back().push_back(55); + parser.addSymbol("ttt", ttt); + + ParseNode *pn; + pn = parser.parse("a*b*e + c*d + f == 5*4 + 3*2; if (foo) {aa; {x;y} } rolf2=nasse; rolf2 "); + + pn = parser.parse("{g=1;}{h=1} {(1)} {{(h++) }} return g+h"); + assertEq(pn->evaluate(parser), 3); + + pn = parser.parse("16-8+4-2+1"); // 16-(8-4+2-1) + // 16-(8-(4-2+1)) + // 16-(8-(4-(2-1)) + assertEq(pn->evaluate(parser), 11); + + pn = parser.parse("16-8-4-2-1)"); + assertEq(pn->evaluate(parser), 1); + + pn = parser.parse("16-8+4-2-1)"); + assertEq(pn->evaluate(parser), 9); + + pn = parser.parse("16-(8+4-2+1)"); + assertEq(pn->evaluate(parser), 5); + + pn = parser.parse("16-2*4*1+2*2*1-2*1"); + assertEq(pn->evaluate(parser), 10); + + pn = parser.parse("a = (1+2) * (3+4);b = a-2*10"); + assertEq(pn->evaluate(parser), 1); + + pn = parser.parse("1 + 2*2"); + assertEq(pn->evaluate(parser), 5); + + pn = parser.parse("1 + (1+1)*2"); + assertEq(pn->evaluate(parser), 5); + + pn = parser.parse("1 * -(1+1)*+(1+1)+10"); + assertEq(pn->evaluate(parser), 6); + + pn = parser.parse("3*5 + (3-1)*3*2 - 5*3"); + assertEq(pn->evaluate(parser), 12); + + pn = parser.parse("{a = 1; {b=2;}} if (t == a+1*b) {a++; if (a>1) {a = a*2}; return a+6;} else a--; +1+1"); + assertEq(pn->evaluate(parser), 10); + + pn = parser.parse("a = 3; if (1+1 == a) return 2; return 5*5*5-20;"); + assertEq(pn->evaluate(parser), 105); + + pn = parser.parse("max(1,2);"); + assertEq(pn->evaluate(parser), 2); + + pn = parser.parse("max(1,2) + min(max(0,1),2)"); + assertEq(pn->evaluate(parser), 3); + + pn = parser.parse("-1*-1*2+-3*3+-max(-1, 2)"); + assertEq(pn->evaluate(parser), -9); + + pn = parser.parse("1+-1+1"); + assertEq(pn->evaluate(parser), 1); + + pn = parser.parse("1+tt[1+1]"); + assertEq(pn->evaluate(parser), 10); + + pn = parser.parse("a[3] = 12; tt.size() + a.size() + a[3]"); + assertEq(pn->evaluate(parser), 19); + + pn = parser.parse("a = 2; k = 1; while(a-- > 0) { k = k*2;} return k;"); + assertEq(pn->evaluate(parser), 4); + + pn = parser.parse("a=1; while(1) {a=a*2; if (a>60) break;} return a;"); + assertEq(pn->evaluate(parser), 64); + + pn = parser.parse("res = 1; for(k = 0; k < 10; ++k) res=res*2"); + assertEq(pn->evaluate(parser), 1024); + + pn = parser.parse("m = 1; n = 1; a = ++m + 4*n++; return a + 100*m + 1000*n"); + assertEq(pn->evaluate(parser), 2206); + + pn = parser.parse("m = 1; n = 1; a = m++ + 4*++n; return a + 100*m + 1000*n"); + assertEq(pn->evaluate(parser), 2209); + + pn = parser.parse("m = 2; n = 2; a = m-- + 4*--n; return a + 100*m + 1000*n"); + assertEq(pn->evaluate(parser), 1106); + + pn = parser.parse("for(m=0; m < 10; m++) arr[m] = m * m; ret = 0; for(m = 0; m < arr.size(); m++) ret = ret + arr[m];"); + assertEq(pn->evaluate(parser), 1+4+9+16+25+36+49+64+81); + + pn = parser.parse("a = 0; if (1!=2) a = a + 1; if (1<2) a=a+2; if (1<=2) a=a+4; if (1>2) a=a+8; if (!(1==2)) a=a+16; if (1>=2) a=a+32; if (1>5 or 1+1 < 5) a=a+64; return a;"); + assertEq(pn->evaluate(parser), 1+2+4+16+64); + + pn = parser.parse("i = 3; return ttt[1][i];"); + assertEq(pn->evaluate(parser), 55); + + pn = parser.parse("return ttt[3][0];"); + try { + pn->evaluate(parser); + assertEq(0,1); + } + catch (const meosException &) { + } + + pn = parser.parse("return ttt[0][5];"); + try { + pn->evaluate(parser); + assertEq(0,1); + } + catch (const meosException &) { + } + + pn = parser.parse("return ttt[4].size();"); + try { + pn->evaluate(parser); + assertEq(0,1); + } + catch (const meosException &) { + } + + pn = parser.parse("ttt.size()"); + assertEq(pn->evaluate(parser), 2); + + pn = parser.parse("sum = 0; for (k = 0; k < ttt.size(); k++) {for (m = 0; m < ttt[k].size(); m++) sum = sum + ttt[k][m];}"); + assertEq(pn->evaluate(parser), 83); + + pn = parser.parse("ma = tt2; ma.sort(); s = 0; for(k = 0; k < ma.size(); k++) {s = s + (k+1)*ma[k];} return s;"); + pn->evaluate(parser); + assertEq(pn->evaluate(parser), 1*1+2*2+3*3+4*4); + + pn = parser.parse("arr = ttt[1]; s = 0; for(k = 0; k < arr.size(); k++) {s = s + arr[k];} return s;"); + pn->evaluate(parser); + assertEq(pn->evaluate(parser), 69); + + pn = parser.parse("k=5; //Test\n//Info\nreturn k+1;//Return 7;"); + pn->evaluate(parser); + assertEq(pn->evaluate(parser), 6); + + pn = parser.parse("if (1>2) return 10; else if (1<2) return 11; else return 5;"); + pn->evaluate(parser); + assertEq(pn->evaluate(parser), 11); + + try { + parser.parse("if (1>2) return 10; else return 11; else return 5;"); + assertEq(0,1); + } + catch (const meosException &) { + } + + try { + parser.parse("return 10; else return 11;"); + assertEq(0,1); + } + catch (const meosException &) { + } + +} + +void Parser::dumpVariables(gdioutput &gdi, int c1, int c2) const { + for (map >::iterator it = var.begin(); it != var.end(); ++it) { + const vector &v = it->second; + string val; + if (v.size() == 1) { + val = itos(v[0]); + } + else { + val = "["; + for (size_t k = 0; k < v.size(); k++) { + if (k > 0) + val += ","; + val += itos(v[k]); + } + val += "]"; + } + int cy = gdi.getCY(); + gdi.addStringUT(cy, c1, monoText, it->first, c2-c1-10); + gdi.addStringUT(cy, c2, monoText, val); + } +} + +void Parser::dumpSymbols(gdioutput &gdi, int c1, int c2) const { + for (map::const_iterator it = symb.begin(); it != symb.end(); ++it) { + const vector< vector > &v = it->second.value; + if (v.empty()) + continue; + + int cy = gdi.getCY(); + gdi.addStringUT(cy, c1, monoText, it->first, c2-c1-10); + + string val; + + if (v.size() == 1) { + if (v[0].size() == 1) { + val = itos(v[0][0]); + } + else { + val = "["; + for (size_t k = 0; k < v[0].size(); k++) { + if (k > 0) + val += ","; + val += itos(v[0][k]); + } + val += "]"; + } + gdi.addStringUT(cy, c2, monoText, val); + } + else { + for (size_t j = 0; j < v.size(); j++) { + val = itos(j) + ": ["; + for (size_t k = 0; k < v[j].size(); k++) { + if (k > 0) + val += ","; + val += itos(v[j][k]); + } + val += "]"; + gdi.addStringUT(cy, c2, monoText, val); + cy = gdi.getCY(); + } + } + } +} diff --git a/code/parser.h b/code/parser.h new file mode 100644 index 0000000..fee8f05 --- /dev/null +++ b/code/parser.h @@ -0,0 +1,301 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include + +using namespace std; + +class Parser; + + +class ParseNode { +public: + virtual bool isVariable() const {return false;} + virtual int evaluate(const Parser &parser) const = 0; + virtual void assign(const Parser &parser, int value) const; + virtual void assignVector(const Parser &parser, const vector &value) const; + + virtual ~ParseNode() = 0; +}; + + +class Parser { + enum Operator { + OpNone, + OpPlus, // 1 + OpMinus, // 1 + OpTimes, // 2 + OpDivide, // 2 + OpMod, // 2 + OpMax, + OpMin, + + OpEquals, + OpNotEquals, + OpLess, + OpMore, + OpLessEquals, + OpMoreEquals, + + OpAnd, + OpOr, + + OpNot, + + OpAssign, + + OpLeftP, + OpRightP, + + OpInc, + OpDec, + OpIncPost, + OpDecPost, + OpIncPre, + OpDecPre, + + OpReturn, + OpSize, + OpSizeBase, + OpSizeSub, + OpBreak, + OpSortArray, + }; + + + static const int levelMax = 3; + static int getLevel(Operator op); + static void eatWhite(const string &expr, size_t &pos); + + ParseNode *parseFunction(const string &name, const string &expr, size_t &pos); + + + static Operator parseOperator(const string &expr, size_t &pos, int level); + static Operator parseOperatorAux(const string &expr, size_t &pos); + + struct Symbol { + string desc; + bool isVector; + bool isMatrix; + vector< vector > value; + }; + + map symb; + mutable map > var; + + mutable int breakMode; + mutable bool returnMode; + mutable bool ignoreValue; + + ParseNode *parseStatement(const string &expr, bool primary); + ParseNode *parseStatement(ParseNode *left, const string &expr, size_t &pos, int level, bool changeSign); + + class StatementNode : public ParseNode { + ParseNode *node; + StatementNode *next; + + StatementNode(const StatementNode &); //Do not use + StatementNode &operator=(const StatementNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + + StatementNode(); + virtual ~StatementNode(); + friend class Parser; + }; + + class ValueNode : public ParseNode { + string value; + ValueNode(const ValueNode &); //Do not use + ValueNode &operator=(const ValueNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + bool isVariable() const; + void assign(const Parser &parser, int value) const; + void assignVector(const Parser &parser, const vector &value) const; + + ValueNode(); + virtual ~ValueNode(); + friend class Parser; + }; + + class ArrayValueNode : public ParseNode { + string expr; + ParseNode *index; + ParseNode *index2; + ArrayValueNode(const ArrayValueNode &); //Do not use + ArrayValueNode &operator=(const ArrayValueNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + void assign(const Parser &parser, int value) const; + void assignVector(const Parser &parser, const vector &value) const; + + bool isVariable() const; + ArrayValueNode(); + virtual ~ArrayValueNode(); + friend class Parser; + }; + + + + class UnaryOperatorNode : public ParseNode { + Operator op; + ParseNode *right; + UnaryOperatorNode(const UnaryOperatorNode &); //Do not use + UnaryOperatorNode &operator=(const UnaryOperatorNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + + UnaryOperatorNode(); + virtual ~UnaryOperatorNode(); + friend class Parser; + }; + + class BinaryOperatorNode : public ParseNode { + Operator op; + ParseNode *left; + ParseNode *right; + BinaryOperatorNode(const BinaryOperatorNode &); //Do not use + BinaryOperatorNode &operator=(const BinaryOperatorNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + + BinaryOperatorNode(); + virtual ~BinaryOperatorNode(); + friend class Parser; + }; + + class IfNode : public ParseNode { + ParseNode *condition; + ParseNode *iftrue; + ParseNode *iffalse; + IfNode(const IfNode &); //Do not use + IfNode &operator=(const IfNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + + IfNode(); + virtual ~IfNode(); + friend class Parser; + }; + + class WhileNode : public ParseNode { + ParseNode *condition; + ParseNode *body; + WhileNode(const WhileNode &); //Do not use + WhileNode &operator=(const WhileNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + + WhileNode(); + virtual ~WhileNode(); + friend class Parser; + }; + + + class ForNode : public ParseNode { + ParseNode *start; + ParseNode *condition; + ParseNode *update; + + ParseNode *body; + ForNode(const ForNode &); //Do not use + ForNode &operator=(const ForNode &); //Do not use + + public: + int evaluate(const Parser &parser) const; + + ForNode(); + virtual ~ForNode(); + friend class Parser; + }; + + + int evaluate(const string &input) const; + int evaluate(const string &input, int index, int index2) const; + int evaluateSize(const string &input, int index) const; + void sortArray(const string &input) const; + + + void storeVariable(const string &input, const vector &value) const; + void storeVariable(const string &input, int value) const; + void storeVariable(const string &input, int index, int value) const; + + UnaryOperatorNode *getUnary(); + BinaryOperatorNode *getBinary(); + ValueNode *getValue(); + ArrayValueNode *getArrayValue(); + StatementNode *getStatement(); + IfNode *getif (); + WhileNode *getWhile(); + ForNode *getFor(); + + ParseNode *parseif (const string &expr, size_t &pos); + ParseNode *parseReturn(const string &expr, size_t &pos); + ParseNode *parseValue(const string &word, const string &expr, size_t &pos); + ParseNode *parseWhile(const string &expr, size_t &pos); + ParseNode *parseFor(const string &expr, size_t &pos); + + string parseMethod(const string &expr, size_t &pos); + + vector nodes; + bool isMatrix(const string &symbol) const; + bool isVector(const string &symbol) const; + + const vector &getVector(const string &symbol, int index) const; +public: + ParseNode *parse(const string &expr); + static void test(); + + Parser(); + ~Parser(); + void clear(); + void addSymbol(const char *name, const string &value); + void addSymbol(const char *name, int value); + void addSymbol(const char *name, const vector &value); + void addSymbol(const char *name, const vector &value); + void addSymbol(const char *name, vector< vector > &value); + void removeSymbol(const char *name); + void declareSymbol(const char *name, const string &desc, bool isVector, bool isMatrix = false); + void clearSymbols(); + void clearVariables() const; + + void takeVariable(const char*name, vector &val) const; + + void getSymbols(vector< pair > &symb) const; + + void getSymbolInfo(int ix, string &name, string &desc) const; + + void dumpVariables(gdioutput &gdi, int c1, int c2) const; + void dumpSymbols(gdioutput &gdi, int c1, int c2) const; +}; diff --git a/code/pdfwriter.cpp b/code/pdfwriter.cpp new file mode 100644 index 0000000..ed6fe13 --- /dev/null +++ b/code/pdfwriter.cpp @@ -0,0 +1,313 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include +#include +#include +#include + +#include "meosexception.h" +#include "gdioutput.h" +#include "gdifonts.h" +#include "gdiimpl.h" +#include "Printer.h" + +#define HPDF_DLL +#include "hpdf.h" + +#include "pdfwriter.h" + +string getMeosCompectVersion(); + +void __stdcall pdfErrorhandler(HPDF_STATUS errorNo, + HPDF_STATUS detailNo, + void *user_data) { + char bf[128]; + sprintf_s(bf, "PDF ERROR: error_no=%04X, detail_no=%u\n", (HPDF_UINT)errorNo, + (HPDF_UINT)detailNo); + throw meosException(bf); +} + +const char* stdText = "Mr. Fantom of 43 Years"; + +bool pdfwriter::getFontData(const HFONT fontHandle, std::vector& data, int &width) { + bool result = false; + HDC hdc = CreateCompatibleDC(NULL); + if (hdc != NULL) { + SelectObject(hdc, fontHandle); + SIZE s; + GetTextExtentPoint32(hdc, stdText, strlen(stdText), &s); + width = s.cx; + const size_t size = GetFontData(hdc, 0, 0, NULL, 0); + if (size > 0) { + char* buffer = new char[size]; + if (GetFontData(hdc, 0, 0, buffer, size) == size) { + data.resize(size); + memcpy(&data[0], buffer, size); + result = true; + } + delete[] buffer; + } + DeleteDC(hdc); + } + return result; +} + +HPDF_Font pdfwriter::getPDFFont(HFONT font, float hFontScale, string &tmp, float &fontScale) { + fontScale = 1.0; + vector data; + int stdSize; + if (getFontData(font, data, stdSize)) { + tmp = getTempFile(); + ofstream out(tmp.c_str(), ios::binary|ios::out|ios::trunc); + out.write(&data[0], data.size()); + out.close(); + const char *detailName = HPDF_LoadTTFontFromFile(pdf, tmp.c_str(), HPDF_TRUE); + HPDF_Font font = HPDF_GetFont (pdf, detailName, "WinAnsiEncoding"); + + HPDF_TextWidth res = HPDF_Font_TextWidth(font, (HPDF_BYTE *)stdText, strlen(stdText)); + if (res.width > 0) + fontScale = float(stdSize) / float(hFontScale * res.width * 0.012f); + else + return 0; + + return font; + } + return 0; +} + +void pdfwriter::selectFont(HPDF_Page page, const PDFFontSet &fs, int format, float scale) { + format &= 0xFF; + if (format==0 || format==10) { + HPDF_Page_SetFontAndSize (page, fs.font, fs.fontScale*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==fontMedium){ + HPDF_Page_SetFontAndSize (page, fs.font, fs.fontScale*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==1){ + HPDF_Page_SetFontAndSize (page, fs.fontBold, fs.fontScaleBold*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==boldLarge){ + HPDF_Page_SetFontAndSize (page, fs.fontBold, fs.fontScaleBold*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==boldHuge){ + HPDF_Page_SetFontAndSize (page, fs.fontBold, fs.fontScaleBold*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==boldSmall){ + HPDF_Page_SetFontAndSize (page, fs.fontBold, fs.fontScaleBold*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==fontLarge){ + HPDF_Page_SetFontAndSize (page, fs.font, fs.fontScale*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==fontMediumPlus){ + HPDF_Page_SetFontAndSize (page, fs.font, fs.fontScale*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==fontSmall){ + HPDF_Page_SetFontAndSize (page, fs.font, fs.fontScale*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==italicSmall){ + HPDF_Page_SetFontAndSize (page, fs.fontItalic, fs.fontScaleItalic*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==italicText){ + HPDF_Page_SetFontAndSize (page, fs.fontItalic, fs.fontScaleItalic*GDIImplFontSet::baseSize(format, scale)); + } + else if (format==italicMediumPlus){ + HPDF_Page_SetFontAndSize (page, fs.fontItalic, fs.fontScaleItalic*GDIImplFontSet::baseSize(format, scale)); + } + else { + HPDF_Page_SetFontAndSize (page, fs.font, fs.fontScale*GDIImplFontSet::baseSize(format, scale)); + } +} + +void pdfwriter::generatePDF(const gdioutput &gdi, + const wstring &file, + const string &pageTitle, + const string &author, + const list &tl) { + + pdf = HPDF_New(pdfErrorhandler, 0); + if (!pdf) + pdfErrorhandler(-1, -1, 0); + + // Set compression mode + HPDF_SetCompressionMode (pdf, HPDF_COMP_ALL); + string creator = "MeOS " + getMeosCompectVersion(); + HPDF_SetInfoAttr(pdf, HPDF_INFO_CREATOR, creator.c_str()); + HPDF_SetInfoAttr(pdf, HPDF_INFO_TITLE, pageTitle.c_str()); + + // Map font name to pdf font sets + map fonts; + + // Create default-font + PDFFontSet &fs = fonts[""]; + fs.font = HPDF_GetFont (pdf, "Helvetica", "WinAnsiEncoding"); + fs.fontBold = HPDF_GetFont (pdf, "Helvetica-Bold", "WinAnsiEncoding"); + fs.fontItalic = HPDF_GetFont (pdf, "Helvetica-Oblique", "WinAnsiEncoding"); + fs.fontScale = 0.9f; + fs.fontScaleBold = 0.9f; + fs.fontScaleItalic = 0.9f; + + // Add a new page object. + HPDF_Page page = HPDF_AddPage (pdf); + + // Set page size + HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT); + + float maxX = 0; + for (list::const_iterator it = tl.begin(); it != tl.end(); ++it) { + if (gdioutput::skipTextRender(it->format)) + continue; + + maxX = max(maxX, (float)it->textRect.right); + } + const float scaleXFactor = 1.2f; + maxX *= scaleXFactor; + float w = HPDF_Page_GetWidth(page); + float h = HPDF_Page_GetHeight(page); + float scale = (w / maxX) * 0.85f; + + vector pages; + PageInfo pageInfo; + pageInfo.topMargin = h * 0.05f; + pageInfo.scaleX = scale * scaleXFactor; + pageInfo.scaleY = scale; + pageInfo.leftMargin = w * 0.07f; + pageInfo.bottomMargin = pageInfo.topMargin * 1.0f; + pageInfo.pageY = h; + pageInfo.printHeader = true; + pageInfo.yMM2PrintC = pageInfo.xMM2PrintC = 1199.551f / 420.f; + pageInfo.xMM2PrintK = 0; + pageInfo.yMM2PrintK = 0; + + list rectangles; + pageInfo.renderPages(tl, rectangles, true, pages); + for (size_t j = 0; j< pages.size(); j++) { + string pinfo = pageInfo.pageInfo(pages[j]); + if (!pinfo.empty()) { + selectFont(page, fs, fontSmall, scale); + HPDF_Page_BeginText (page); + float df = min(w, h) * 0.02f; + float sw = HPDF_Page_TextWidth(page, pinfo.c_str()); + HPDF_Page_TextOut (page, w - sw - df , h - df * 2.5f, pinfo.c_str()); + HPDF_Page_EndText(page); + } + + vector &info = pages[j].text; + + for (size_t k = 0; k < info.size(); k++) { + if (fonts.count(info[k].ti.font) == 0) { + FontInfo fi; + gdi.getFontInfo(info[k].ti, fi); + float fontScale; + string tmpFile; + fonts[info[k].ti.font] = fs; //Default fallback + PDFFontSet &f = fonts[info[k].ti.font]; + + HPDF_Font font = getPDFFont(fi.normal, float(gdi.getScale()), tmpFile, fontScale); + if (!tmpFile.empty()) + tmpFiles.push_back(tmpFile); + if (font) { + f.font = font; + f.fontScale = fontScale; + } + + font = getPDFFont(fi.italic, float(gdi.getScale()), tmpFile, fontScale); + if (!tmpFile.empty()) + tmpFiles.push_back(tmpFile); + if (font) { + f.fontItalic = font; + f.fontScaleItalic = fontScale; + } + + font = getPDFFont(fi.bold, (float)gdi.getScale(), tmpFile, fontScale); + if (!tmpFile.empty()) + tmpFiles.push_back(tmpFile); + if (font) { + f.fontBold = font; + f.fontScaleBold = fontScale; + } + } + + selectFont(page, fonts[info[k].ti.font], info[k].ti.format, scale); + HPDF_Page_BeginText (page); + float r = GetRValue(info[k].ti.color); + float g = GetGValue(info[k].ti.color); + float b = GetBValue(info[k].ti.color); + HPDF_Page_SetRGBFill (page, r/255.0f, g/255.0f, b/255.0f); + if (info[k].ti.format & textRight) { + float w = float(info[k].ti.xlimit) * scale; + float sw = HPDF_Page_TextWidth(page, info[k].ti.text.c_str()); + float space = info[k].ti.xlimit > 0 ? 2 * HPDF_Page_GetCharSpace(page) : 0; + HPDF_Page_TextOut (page, info[k].xp + w - sw - space, h - info[k].yp, + info[k].ti.text.c_str()); + } + else if (info[k].ti.format & textCenter) { + float w = float(info[k].ti.xlimit) * scale; + float sw = HPDF_Page_TextWidth(page, info[k].ti.text.c_str()); + HPDF_Page_TextOut (page, info[k].xp + w - sw/2, h - info[k].yp, + info[k].ti.text.c_str()); + } + else { + HPDF_Page_TextOut (page, info[k].xp, h - info[k].yp, + info[k].ti.text.c_str()); + } + HPDF_Page_EndText (page); + } + if (j+1 < pages.size()) { + // Add a new page object. + page = HPDF_AddPage (pdf); + + // Set page size + HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT); + HPDF_Page_SetFontAndSize (page, fs.font, 16); + } + } + + // Save the document to a file + string tmpRes = getTempFile(); + HPDF_SaveToFile (pdf, tmpRes.c_str()); + DeleteFileW(file.c_str()); + BOOL res = MoveFileW(gdi.toWide(tmpRes).c_str(), file.c_str()); + removeTempFile(tmpRes); + + if (!res) { + throw meosException("Failed to save pdf the specified file."); + } + return; +} + +pdfwriter::pdfwriter() { + pdf = 0; +} + +pdfwriter::~pdfwriter() { + // Clean up + if (pdf) + HPDF_Free(pdf); + while(!tmpFiles.empty()) { + removeTempFile(tmpFiles.back()); + tmpFiles.pop_back(); + } +} diff --git a/code/pdfwriter.h b/code/pdfwriter.h new file mode 100644 index 0000000..7856329 --- /dev/null +++ b/code/pdfwriter.h @@ -0,0 +1,60 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#pragma once + +#ifndef _HPDF_H +typedef void *HPDF_HANDLE; +typedef HPDF_HANDLE HPDF_Doc; +typedef HPDF_HANDLE HPDF_Page; +typedef HPDF_HANDLE HPDF_Font; +#endif + +class pdfwriter { + + struct PDFFontSet { + HPDF_Font font; + float fontScale; + HPDF_Font fontBold; + float fontScaleBold; + HPDF_Font fontItalic; + float fontScaleItalic; + PDFFontSet() : font(0), fontScale(1), fontBold(0), fontScaleBold(1), fontItalic(0), fontScaleItalic(1) {} + }; + + protected: + + bool getFontData(const HFONT fontHandle, std::vector& data, int &width); + HPDF_Font getPDFFont(HFONT font, float hFontScale, string &tmp, float &fontScale); + void selectFont(HPDF_Page page, const PDFFontSet &fs, int format, float scale); + vector tmpFiles; + HPDF_Doc pdf; + public: + pdfwriter(); + ~pdfwriter(); + + void generatePDF(const gdioutput &gdi, + const wstring &file, + const string &pageTitle, + const string &author, + const list &tl); +}; diff --git a/code/prefseditor.cpp b/code/prefseditor.cpp new file mode 100644 index 0000000..f5911e6 --- /dev/null +++ b/code/prefseditor.cpp @@ -0,0 +1,185 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include +#include "prefseditor.h" + +#include "gdioutput.h" +#include "meosexception.h" +#include "gdistructures.h" +#include "meos_util.h" +#include "localizer.h" +#include "oEvent.h" + +PrefsEditor::PrefsEditor(oEvent *oe) : oe(oe) { +} + +PrefsEditor::~PrefsEditor() { +} + +void PrefsEditor::showPrefs(gdioutput &gdi) { + vector< pair > iprefs; + + oe->listProperties(true, iprefs); + map > > orderPrefs; + for (size_t k = 0; k < iprefs.size(); k++) { + char c = toupper(iprefs[k].first[0]); + string key; + key.push_back(c); + orderPrefs[key].push_back(iprefs[k]); + } + + const int bw = gdi.scaleLength(80); + int basePos = gdi.getCX(); + int valuePos = basePos + gdi.scaleLength(160); + int editPos = valuePos + gdi.scaleLength(280); + int descPos = editPos + bw + gdi.scaleLength(10); + + gdi.fillDown(); + for (map > >::const_iterator it = orderPrefs.begin(); + it != orderPrefs.end(); ++it) { + const vector > &prefs = it->second; + gdi.addStringUT(boldLarge, it->first); + for (size_t k = 0; k < prefs.size(); k++) { + int y = gdi.getCY(); + gdi.addStringUT(y, basePos, 0, prefs[k].first, 0, 0, "Consolas;1.1"); + string rawVal = oe->getPropertyString(prefs[k].first.c_str(), ""); + string val = codeValue(rawVal, prefs[k].second); + + gdi.addString("value" + prefs[k].first, y, valuePos, 0, "#" + val, editPos - valuePos, 0, "Consolas;1"). + setColor(selectColor(rawVal, prefs[k].second)).setExtra(prefs[k].second); + + gdi.addButton(editPos, y - gdi.getLineHeight()/4, "Edit_" + prefs[k].first, "Ändra").setHandler(this); + + string dkey = "prefs" + prefs[k].first; + string desc = lang.tl(dkey); + if (desc != dkey) { + gdi.addStringUT(y, descPos, 0, desc).setColor(colorDarkGreen); + } + } + gdi.dropLine(0.5); + } +} + +void PrefsEditor::handle(gdioutput &gdi, BaseInfo &data, GuiEventType type) { + if (type == GUI_BUTTON) { + ButtonInfo bi(dynamic_cast(data)); + + if (bi.id.substr(0, 5) == "Edit_") { + if (gdi.hasData("EditPrefs")) + gdi.restore("BeforeEdit"); + + gdi.setRestorePoint("BeforeEdit"); + gdi.fillDown(); + gdi.dropLine(); + int x = gdi.getCX(); + int y = gdi.getCY(); + gdi.setCX(x + gdi.getLineHeight()); + string pref = bi.id.substr(5); + PropertyType type = (PropertyType)gdi.getBaseInfo(("value" + pref).c_str()).getExtraInt(); + gdi.setData("EditPrefs", type); + gdi.dropLine(); + gdi.addString("", fontMediumPlus, "Ändra X#" + pref); + string dkey = "prefs" + pref; + string desc = lang.tl(dkey); + gdi.dropLine(); + if (desc != dkey) { + gdi.addStringUT(0, desc +":"); + } + string val = oe->getPropertyString(pref.c_str(), ""); + if (type == String) + gdi.addInput("Value", val, 48); + else if (type == Integer) + gdi.addInput("Value", val, 16); + else { + gdi.addSelection("ValueBoolean", 200, 50, 0); + gdi.addItem("ValueBoolean", codeValue("0", Boolean), 0); + gdi.addItem("ValueBoolean", codeValue("1", Boolean), 1); + gdi.selectItemByData("ValueBoolean", val == "0" ? 0 : 1); + } + gdi.dropLine(); + gdi.fillRight(); + gdi.addButton("Save_" + pref, "Ändra").setHandler(this); + gdi.addButton("Cancel", "Avbryt").setHandler(this); + gdi.dropLine(3); + + RECT rc = {x,y, gdi.getWidth(), gdi.getCY()}; + gdi.addRectangle(rc, colorLightCyan); + gdi.scrollToBottom(); + gdi.setCX(x); + gdi.refresh(); + } + else if (bi.id.substr(0, 5) == "Save_") { + string pref = bi.id.substr(5); + string value; + if (gdi.hasField("ValueBoolean")) { + ListBoxInfo lbi; + gdi.getSelectedItem("ValueBoolean", lbi); + value = itos(lbi.data); + } + else + value = gdi.getText("Value"); + + PropertyType type = (PropertyType)int(gdi.getData("EditPrefs")); + oe->setProperty(pref.c_str(), value); + dynamic_cast(gdi.setText("value" + pref, codeValue(value, type)))-> + setColor(selectColor(value, type)); + gdi.restore("BeforeEdit", false); + gdi.refresh(); + } + else if (bi.id == "Cancel") { + gdi.restore("BeforeEdit"); + } + } + + return; +} + +string PrefsEditor::codeValue(const string &val, PropertyType p) const { + if (p == Boolean) { + if (atoi(val.c_str()) != 0) { + return lang.tl("true[boolean]"); + } + else { + return lang.tl("false[boolean]"); + } + } + else if (p == Integer) + return itos(atoi(val.c_str())); + else + return val; +} + +GDICOLOR PrefsEditor::selectColor(const string &val, PropertyType p) const { + if (p == Boolean) { + if (atoi(val.c_str()) != 0) { + return colorDarkGreen; + } + else { + return colorDarkRed; + } + } + if (p == Integer) + return colorDarkBlue; + return colorDefault; +} \ No newline at end of file diff --git a/code/prefseditor.h b/code/prefseditor.h new file mode 100644 index 0000000..25e76d9 --- /dev/null +++ b/code/prefseditor.h @@ -0,0 +1,50 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class gdioutput; +class oEvent; +class BaseInfo; + +#include +enum GDICOLOR; +enum PropertyType; +#include "guihandler.h" + +class PrefsEditor : public GuiHandler { +private: + oEvent *oe; + + int userCB(gdioutput &gdi, int type, const BaseInfo &data); + + string codeValue(const string &in, PropertyType p) const; + GDICOLOR selectColor(const string &val, PropertyType p) const; + +public: + void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type); + + PrefsEditor(oEvent *oe); + virtual ~PrefsEditor(); + + void showPrefs(gdioutput &gdi); +}; diff --git a/code/printer.cpp b/code/printer.cpp new file mode 100644 index 0000000..cc18677 --- /dev/null +++ b/code/printer.cpp @@ -0,0 +1,833 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" + +#include +#include "gdioutput.h" +#include "oEvent.h" +#include "meos_util.h" +#include "Table.h" +#include "gdifonts.h" +#include "Printer.h" +#include "gdiimpl.h" +#include +#include "meosexception.h" + +extern gdioutput *gdi_main; +static bool bPrint; +const double inchmmk=2.54; + +BOOL CALLBACK AbortProc(HDC, int iError) +{ + if (iError==0) + return bPrint; + else + { + bPrint=false; + return false; + } +} + +#define WM_SETPAGE WM_USER+423 + +BOOL CALLBACK AbortPrintJob(HWND hDlg, UINT message, WPARAM wParam, LPARAM) { + return false; +} + +PrinterObject::PrinterObject() { + hDC=0; + hDevMode=0; + hDevNames=0; + + nPagesPrinted=0; + nPagesPrintedTotal=0; + onlyChanged=true; + + memset(&ds, 0, sizeof(ds)); + memset(&DevMode, 0, sizeof(DevMode)); +} + +PrinterObject::PrinterObject(const PrinterObject &po) { + hDC=0; + hDevMode=po.hDevMode; + hDevNames=po.hDevNames; + if (hDevMode) + GlobalLock(hDevMode); + if (hDevNames) + GlobalLock(hDevNames); + nPagesPrinted=0; + nPagesPrintedTotal=0; + onlyChanged=true; + + memcpy(&ds, &po.ds, sizeof(ds)); + memcpy(&DevMode, &po.DevMode, sizeof(DevMode)); +} + +void PrinterObject::operator=(const PrinterObject &po) +{ + hDC = 0;///???po.hDC; + hDevMode=po.hDevMode; + hDevNames=po.hDevNames; + if (hDevMode) + GlobalLock(hDevMode); + if (hDevNames) + GlobalLock(hDevNames); + + nPagesPrinted = po.nPagesPrinted; + nPagesPrintedTotal = po.nPagesPrintedTotal; + onlyChanged = po.onlyChanged; + + memcpy(&ds, &po.ds, sizeof(ds)); + memcpy(&DevMode, &po.DevMode, sizeof(DevMode)); +} + +PrinterObject::~PrinterObject() +{ + if (hDC) + DeleteDC(hDC); + + freePrinter(); +} + +void gdioutput::printPage(PrinterObject &po, const PageInfo &pageInfo, RenderedPage &page) +{ + if (po.hDC) + SelectObject(po.hDC, GetStockObject(DC_BRUSH)); + + for (size_t k = 0; k < page.text.size(); k++) { + // Use transformed coordinates + page.text[k].ti.xp = (int)page.text[k].xp; + page.text[k].ti.yp = (int)page.text[k].yp; + RenderString(page.text[k].ti, po.hDC); + } + + for (size_t k = 0; k < page.rectangles.size(); k++) { + renderRectangle(po.hDC, 0, page.rectangles[k]); + } + + if (pageInfo.printHeader) { + TextInfo t; + t.yp = po.ds.MarginY; + t.xp = po.ds.PageX - po.ds.MarginX; + t.text = pageInfo.pageInfo(page); + t.format=textRight|fontSmall; + RenderString(t, po.hDC); + } +} + +void gdioutput::printSetup(PrinterObject &po) +{ + destroyPrinterDC(po); + + PRINTDLG pd; + memset(&pd, 0, sizeof(pd)); + + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = po.hDevMode; + pd.hDevNames = po.hDevNames; + + pd.Flags = PD_RETURNDC|PD_USEDEVMODECOPIESANDCOLLATE|PD_PRINTSETUP; + pd.hwndOwner = hWndAppMain; + pd.hDC = (HDC) po.hDC; + pd.nFromPage = 1; + pd.nToPage = 1; + pd.nMinPage = 1; + pd.nMaxPage = 1; + pd.nCopies = 1; + pd.hInstance = (HINSTANCE) NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPSTR) NULL; + pd.lpSetupTemplateName = (LPSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + + int iret=PrintDlg(&pd); + + if (iret==false) { + int error = CommDlgExtendedError(); + if (error!=0) { + char sb[127]; + sprintf_s(sb, "Printing Error Code=%d", error); + //MessageBox(hWnd, sb, NULL, MB_OK); + alert(sb); + po.freePrinter(); + po.hDC = 0; + } + return; + } + else { + //Save settings! + po.hDevMode = pd.hDevMode; + po.hDevNames = pd.hDevNames; + po.hDC=pd.hDC; + + DEVNAMES *dn=(LPDEVNAMES)GlobalLock(pd.hDevNames); + if (dn) { + DEVMODE *dm=(LPDEVMODE)GlobalLock(pd.hDevMode); + if (dm) { + po.DevMode=*dm; + po.DevMode.dmSize=sizeof(po.DevMode); + } + po.Driver=(char *)(dn)+dn->wDriverOffset; + po.Device=(char *)(dn)+dn->wDeviceOffset; + //GlobalUnlock(pd.hDevMode); + } + //GlobalUnlock(pd.hDevNames); + } +} + +void gdioutput::print(pEvent oe, Table *t, bool printMeOSHeader, bool noMargin) +{ + PageInfo pageInfo; + pageInfo.printHeader = printMeOSHeader; + pageInfo.noPrintMargin = noMargin; + + setWaitCursor(true); + PRINTDLG pd; + + PrinterObject &po=*po_default; + po.printedPages.clear();//Don't remember + + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = po.hDevMode; + pd.hDevNames = po.hDevNames; + pd.Flags = PD_RETURNDC; + pd.hwndOwner = hWndAppMain; + pd.hDC = (HDC) NULL; + pd.nFromPage = 1; + pd.nToPage = 1; + pd.nMinPage = 1; + pd.nMaxPage = 1; + pd.nCopies = 1; + pd.hInstance = (HINSTANCE) NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPSTR) NULL; + pd.lpSetupTemplateName = (LPSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + + int iret=PrintDlg(&pd); + + if (iret==false) { + int error=CommDlgExtendedError(); + if (error!=0) { + char sb[128]; + sprintf_s(sb, "Printing Error Code=%d", error); + alert(sb); + po.freePrinter(); + po.hDC = 0; + } + return; + } + setWaitCursor(true); + //Save settings! + po.freePrinter(); + + po.hDevMode = pd.hDevMode; + po.hDevNames = pd.hDevNames; + po.hDC = pd.hDC; + + if (t) + t->print(*this, po.hDC, 20, 0); + + DEVNAMES *dn=(LPDEVNAMES)GlobalLock(pd.hDevNames); + if (dn) { + DEVMODE *dm=(LPDEVMODE)GlobalLock(pd.hDevMode); + if (dm) { + po.DevMode=*dm; + po.DevMode.dmSize=sizeof(po.DevMode); + } + po.Driver=(char *)(dn)+dn->wDriverOffset; + po.Device=(char *)(dn)+dn->wDeviceOffset; + //GlobalUnlock(pd.hDevMode); + //GlobalUnlock(pd.hDevNames); + } + + doPrint(po, pageInfo, oe); + + // Delete the printer DC. + DeleteDC(pd.hDC); + po.hDC=0; +} + +void gdioutput::print(PrinterObject &po, pEvent oe, bool printMeOSHeader, bool noMargin) +{ + PageInfo pageInfo; + pageInfo.printHeader = printMeOSHeader; + pageInfo.noPrintMargin = noMargin; + + if (po.hDevMode==0) { + //if (po.Driver.empty()) { + PRINTDLG pd; + + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = 0; + pd.hDevNames = 0; + pd.Flags = PD_RETURNDEFAULT; + pd.hwndOwner = hWndAppMain; + pd.hDC = (HDC) NULL; + pd.nFromPage = 1; + pd.nToPage = 1; + pd.nMinPage = 1; + pd.nMaxPage = 1; + pd.nCopies = 1; + pd.hInstance = (HINSTANCE) NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPSTR) NULL; + pd.lpSetupTemplateName = (LPSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + + int iret=PrintDlg(&pd); + + if (iret==false) { + int error=CommDlgExtendedError(); + if (error!=0) { + char sb[128]; + sprintf_s(sb, "Printing Error Code=%d", error); + alert(sb); + po.hDC = 0; + } + return; + } + po.freePrinter(); + po.hDevMode = pd.hDevMode; + po.hDevNames = pd.hDevNames; + + DEVNAMES *dn=(LPDEVNAMES)GlobalLock(pd.hDevNames); + if (dn) { + DEVMODE *dm=(LPDEVMODE)GlobalLock(pd.hDevMode); + if (dm) { + po.DevMode=*dm; + po.DevMode.dmSize=sizeof(po.DevMode); + } + + po.Driver=(char *)(dn)+dn->wDriverOffset; + po.Device=(char *)(dn)+dn->wDeviceOffset; + po.hDC=CreateDC(po.Driver.c_str(), po.Device.c_str(), NULL, dm); + GlobalUnlock(pd.hDevMode); + } + GlobalUnlock(pd.hDevNames); + } + else if (po.hDC==0) { + po.hDC = CreateDC(po.Driver.c_str(), po.Device.c_str(), NULL, &po.DevMode); + } + doPrint(po, pageInfo, oe); +} + +void gdioutput::destroyPrinterDC(PrinterObject &po) +{ + if (po.hDC) { + // Delete the printer DC. + DeleteDC(po.hDC); + po.hDC=0; + } +} + +bool gdioutput::startDoc(PrinterObject &po) +{ + // Initialize the members of a DOCINFO structure. + DOCINFO di; + int nError; + di.cbSize = sizeof(DOCINFO); + + char sb[256]; + sprintf_s(sb, "MeOS"); + + di.lpszDocName = sb; + di.lpszOutput = (LPTSTR) NULL; + di.lpszDatatype = (LPTSTR) NULL; + di.fwType = 0; // Begin a print job by calling the StartDoc function. + + nError = StartDoc(po.hDC, &di); + + if (nError <= 0) { + nError=GetLastError(); + DeleteDC(po.hDC); + po.hDC=0; + + if (nError == ERROR_CANCELLED) + return false; + + string err = "Printing failed (X: Y) Z#StartDoc#"+ itos(nError) + "#" + getErrorMessage(nError); + throw meosException(err); + //sprintf_s(sb, "Window's StartDoc API returned with error code %d,", nError); + //alert("StartDoc error: " + getErrorMessage(nError)); + //return false; + } + return true; +} + +bool gdioutput::doPrint(PrinterObject &po, PageInfo &pageInfo, pEvent oe) +{ + setWaitCursor(true); + + if (!po.hDC) + return false; + set<__int64> myPages; + + po.nPagesPrinted=0; + PrinterObject::DATASET &ds=po.ds; + + //Do the printing + int xsize = GetDeviceCaps(po.hDC, HORZSIZE); + int ysize = GetDeviceCaps(po.hDC, VERTSIZE); + + int physX = GetDeviceCaps(po.hDC, PHYSICALWIDTH); + int physY = GetDeviceCaps(po.hDC, PHYSICALHEIGHT); + + int physOffsetX = GetDeviceCaps(po.hDC, PHYSICALOFFSETX); + int physOffsetY = GetDeviceCaps(po.hDC, PHYSICALOFFSETY); + + // Retrieve the number of pixels-per-logical-inch in the + // horizontal and vertical directions for the printer upon which + // the bitmap will be printed. + int xtot = GetDeviceCaps(po.hDC, HORZRES); + int ytot = GetDeviceCaps(po.hDC, VERTRES); + + SetMapMode(po.hDC, MM_ISOTROPIC); + + const bool limitSize = xsize > 100; + + int PageXMax=limitSize ? max(512, MaxX) : MaxX; + int PageYMax=(ysize*PageXMax)/xsize; + SetWindowExtEx(po.hDC, int(PageXMax*1.05), int(PageYMax*1.05), 0); + SetViewportExtEx(po.hDC, xtot, ytot, NULL); + // xPrint = ((mm / xsize) * physX - physOff) / xtot * PageXMax*1.05 + // xPrint = mm * (physX * PageXMax * 1.05) / (xsize*xtot) - physOff * (PageXMax * 1.05/xtot) + pageInfo.xMM2PrintC = double(physX * PageXMax * 1.05) / double(xsize*xtot); + pageInfo.xMM2PrintK = double(-physOffsetX) * (PageXMax * 1.05/xtot); + pageInfo.yMM2PrintC = double(physY * PageYMax * 1.05) / double(ysize*ytot); + pageInfo.yMM2PrintK = double(-physOffsetY) * (PageYMax * 1.05/ytot); + + ds.PageX = PageXMax; + ds.PageY = PageYMax; + ds.MarginX = pageInfo.noPrintMargin ? (limitSize ? PageXMax/30: 5) : PageXMax/25; + ds.MarginY = pageInfo.noPrintMargin ? 5 : 20; + ds.Scale=1; + ds.LastPage=false; + + int sOffsetY = OffsetY; + int sOffsetX = OffsetX; + OffsetY = 0; + OffsetX = 0; + + pageInfo.topMargin = float(ds.MarginY * 2); + pageInfo.scaleX = 1.0f; + pageInfo.scaleY = 1.0f; + + pageInfo.leftMargin = float(ds.MarginX); + pageInfo.bottomMargin = float(ds.MarginY); + pageInfo.pageY = float(PageYMax); + + vector pages; + pageInfo.renderPages(TL, Rectangles, false, pages); + + vector toPrint; + for (size_t k = 0; k < pages.size(); k++) { + if (!po.onlyChanged || po.printedPages.count(pages[k].checkSum)==0) { + toPrint.push_back(k); + po.nPagesPrinted++; + po.nPagesPrintedTotal++; + } + myPages.insert(pages[k].checkSum); + } + int nPagesToPrint=toPrint.size(); + + if (nPagesToPrint>0) { + + if (!startDoc(po)) { + return false; + } + + for (size_t k = 0; k < toPrint.size(); k++) { + + int nError = StartPage(po.hDC); + if (nError <= 0) { + nError=GetLastError(); + + EndDoc(po.hDC); + DeleteDC(po.hDC); + po.hDC=0; + po.freePrinter(); + OffsetY = sOffsetY; + OffsetX = sOffsetX; + alert("StartPage error: " + getErrorMessage(nError)); + return false; + } + + printPage(po, pageInfo, pages[toPrint[k]]); + EndPage(po.hDC); + } + + int nError = EndDoc(po.hDC); + OffsetY = sOffsetY; + OffsetX = sOffsetX; + + if (nError <= 0) { + nError=GetLastError(); + DeleteDC(po.hDC); + po.hDC=0; + alert("EndDoc error: " + getErrorMessage(nError)); + return false; + } + } + + po.printedPages.swap(myPages); + return true; +} + +UINT CALLBACK PagePaintHook(HWND, UINT uiMsg, WPARAM wParam, LPARAM lParam) { + return false; +} + +void PageSetup(HWND hWnd, PrinterObject &po) +{ + PrinterObject::DATASET &ds=po.ds; + PAGESETUPDLG pd; + + memset(&pd, 0, sizeof(pd)); + + pd.lStructSize=sizeof(pd); + pd.hwndOwner=hWnd; +// pd.hDevMode=po.hDevMode; +// pd.hDevNames=po.hDevNames; + pd.Flags=PSD_MARGINS|PSD_ENABLEPAGEPAINTHOOK|PSD_INHUNDREDTHSOFMILLIMETERS; + pd.lpfnPagePaintHook=PagePaintHook; + + + pd.rtMargin.left=int(ds.pMgLeft*float(ds.pWidth_mm)+0.5)*100; + pd.rtMargin.right=int(ds.pMgRight*float(ds.pWidth_mm)+0.5)*100; + pd.rtMargin.top=int(ds.pMgTop*float(ds.pHeight_mm)+0.5)*100; + pd.rtMargin.bottom=int(ds.pMgBottom*float(ds.pHeight_mm)+0.5)*100; + + + if (PageSetupDlg(&pd)) + { + RECT rtMargin=pd.rtMargin; + + if (pd.Flags & PSD_INHUNDREDTHSOFMILLIMETERS) + { + rtMargin.top=long(rtMargin.top/inchmmk); + rtMargin.bottom=long(rtMargin.bottom/inchmmk); + rtMargin.right=long(rtMargin.right/inchmmk); + rtMargin.left=long(rtMargin.left/inchmmk); + } + + po.hDevMode=pd.hDevMode; + po.hDevNames=pd.hDevNames; + + + DEVMODE *dm=(LPDEVMODE)GlobalLock(pd.hDevMode); + + if (dm) + {/* + if (dm->dmFields&DM_COLOR) + { + /*if (dm->dmColor==DMCOLOR_MONOCHROME) + ds.bPrintColour=false; + else + ds.bPrintColour=true; + }*/ + } + + DEVNAMES *dn=(LPDEVNAMES)GlobalLock(pd.hDevNames); + + if (dn) + { + char *driver=(char *)(dn)+dn->wDriverOffset; + char *device=(char *)(dn)+dn->wDeviceOffset; + + HDC hDC=CreateDC(driver, device, NULL, dm); + + if (hDC) + { + ds.pWidth_mm=GetDeviceCaps(hDC, HORZSIZE); + ds.pHeight_mm=GetDeviceCaps(hDC, VERTSIZE); + + ds.pMgLeft=inchmmk*rtMargin.left/float(ds.pWidth_mm)/100.; + ds.pMgRight=inchmmk*rtMargin.right/float(ds.pWidth_mm)/100.; + ds.pMgTop=inchmmk*rtMargin.top/float(ds.pHeight_mm)/100.; + ds.pMgBottom=inchmmk*rtMargin.bottom/float(ds.pHeight_mm)/100.; + + DeleteDC(hDC); + } + } + + } +} + +void PrinterObject::freePrinter() { + if (hDevNames) + GlobalUnlock(hDevNames); + hDevNames = 0; + + if (hDevMode) + GlobalUnlock(hDevMode); + hDevMode = 0; +} + + +//Uses format, text, xp and yp +void RenderedPage::calculateCS(const TextInfo &text) +{ + if (gdioutput::skipTextRender(text.format) || + text.text.empty()) + return; + DWORD localCS=0; + DWORD localCS2=0; + for(DWORD i=0; i(obj); + return ti && ti->format == pageNewPage; + } +}; + +void PageInfo::renderPages(const list &tl, + const list &rects, + bool invertHeightY, + vector &pages) { + const PageInfo &pi = *this; + TIList::const_iterator it; + pages.clear(); + if (tl.empty()) + return; + int currentYP = 0; + vector indexedTL; + indexedTL.reserve(tl.size() + rects.size()); + int top = 1000; + float minX = 1000; + currentYP = tl.front().yp; + bool needSort = false; + for (it=tl.begin();it!=tl.end(); ++it) { + const TextInfo &text = *it; + if (text.format == 10) + continue; + + if (currentYP > text.yp) { + needSort = true; + } + minX = min(minX, (float)it->textRect.left); + top = min(top, text.yp); + currentYP = text.yp; + indexedTL.push_back(PrintItemInfo(currentYP, &text)); + } + + for (list::const_iterator rit = rects.begin(); rit != rects.end(); ++rit) { + needSort = true; + top = min(top, rit->getRect().top); + indexedTL.push_back(PrintItemInfo(rit->getRect().top, &*rit)); + } + + if (needSort) + stable_sort(indexedTL.begin(), indexedTL.end()); + + bool addPage = true; + bool wasOrphan = false; + int offsetY = 0; + string infoText; + int extraLimit = 0; + for (size_t k = 0; k < indexedTL.size(); k++) { + const TextInfo *tlp = dynamic_cast(indexedTL[k].obj); + + if (tlp == 0) { + const RectangleInfo *ri = dynamic_cast(indexedTL[k].obj); + assert(ri && !pages.empty()); + if (!ri || pages.empty()) + throw std::exception("Unexpected type"); + + pages.back().rectangles.push_back(*ri); + RectangleInfo &r = pages.back().rectangles.back(); + + ///xxxx + r.rc.left = (r.rc.left - minX) * pi.scaleX + pi.leftMargin; + r.rc.right = (r.rc.right - minX) * pi.scaleX + pi.leftMargin; + + int off = invertHeightY ? (r.rc.bottom - r.rc.top) : 0; + r.rc.top = (r.rc.top + offsetY + off) * pi.scaleY + pi.topMargin; + r.rc.bottom = (r.rc.bottom + offsetY + off) * pi.scaleY + pi.topMargin; + continue; + } + + if (tlp->format == pagePageInfo) { + infoText = tlp->text; + if (!pages.empty() && pages.back().info.empty()) + pages.back().info = infoText; + } + + if (addPage) { + wasOrphan = false; + addPage = false; + pages.push_back(RenderedPage()); + pages.back().nPage = pages.size(); + pages.back().info = infoText; + if (k == 0) + offsetY = 0; + else + offsetY = -tlp->yp + extraLimit; + extraLimit = 0; + } + + if (gdioutput::skipTextRender(tlp->format)) + continue; + + pages.back().text.push_back(PrintTextInfo(*tlp)); + PrintTextInfo &text = pages.back().text.back(); + + text.ti.yp += offsetY; + text.ti.highlight=0; + text.ti.hasCapture=0; + text.ti.active=0; + text.ti.callBack=0; + text.ti.hasTimer=false; + + if (text.ti.absPrintX > 0) { + text.xp = float(text.ti.absPrintX * pi.xMM2PrintC + pi.xMM2PrintK); + text.yp = float(text.ti.absPrintY * pi.yMM2PrintC + pi.yMM2PrintK); + } + else { + text.xp = (text.ti.xp - minX) * pi.scaleX + pi.leftMargin; + int off = invertHeightY ? (text.ti.textRect.bottom - text.ti.textRect.top) : 0; + text.yp = (text.ti.yp + off) * pi.scaleY + pi.topMargin; + } + + pages.back().calculateCS(text.ti); + + if (k + 1 < indexedTL.size() && tlp->yp != indexedTL[k+1].yp) { + size_t j = k + 1; + + // Required new page + if (indexedTL[j].isNewPage()) { + k++; + addPage = true; + extraLimit = indexedTL[j].obj->getExtraInt(); + infoText.clear(); + continue; + } + + map forwardyp; + while ( j < indexedTL.size() && forwardyp.size() < 3) { + if (!indexedTL[j].isNewPage()) { + if (forwardyp.count(indexedTL[j].yp) == 0 || indexedTL[j].isNewPage()) + forwardyp[indexedTL[j].yp] = j; + } + j++; + } + + int ix = 0; + float lastSize = GDIImplFontSet::baseSize(tlp->format, 1.0); + bool nextIsHead = false; + bool firstCanBreak = true; + for (map::iterator it = forwardyp.begin(); it != forwardyp.end(); ++it, ++ix) { + const TextInfo *tlpItSecond = dynamic_cast(indexedTL[it->second].obj); + if (!tlpItSecond) + continue; + + float y = (max(tlpItSecond->textRect.bottom, indexedTL[it->second].yp) + offsetY) * pi.scaleY + pi.topMargin; + float size = GDIImplFontSet::baseSize(tlpItSecond->format, 1.0); + + bool over = y > pi.pageY - pi.bottomMargin; + bool canBreak = tlpItSecond->lineBreakPrioity >= 0; + + if (ix == 0 && lastSize < size) + nextIsHead = true; + + if (ix == 0 && !canBreak) + firstCanBreak = false; // First can break; + + if (ix > 0 && firstCanBreak && canBreak) + firstCanBreak = false; // There is a more suitable break later + + if (over) { + if (addPage && ix == 1 && lastSize < size && !wasOrphan) { + wasOrphan = true; + addPage = false; // Keep this line on this page. Orphan, next is head. + break; + } + if (ix == 0 && forwardyp.size()>1) { // forwardyp.size()>1 -> more than one lines left + if (!canBreak) { + if (!wasOrphan) { + wasOrphan = true; + break; // Skip breaking here. + } + wasOrphan = false; + } + addPage = true; + } + else if (ix > 0 && !canBreak && firstCanBreak) { + addPage = true; // Use this as a suitable break + } + else if (nextIsHead) { + addPage = true; + } + } + + lastSize = size; + } + } + } + nPagesTotal = pages.size(); +} + +string PageInfo::pageInfo(const RenderedPage &page) const { + if (printHeader) { + char bf[256]; + if (nPagesTotal > 1) { + if (!page.info.empty()) + sprintf_s(bf, "MeOS %s, %s, (%d/%d)", getLocalTime().c_str(), + page.info.c_str(), page.nPage, nPagesTotal); + else + sprintf_s(bf, "MeOS %s, (%d/%d)", getLocalTime().c_str(), page.nPage, nPagesTotal); + } + else { + if (!page.info.empty()) + sprintf_s(bf, "MeOS %s, %s", getLocalTime().c_str(), page.info.c_str()); + else + sprintf_s(bf, "MeOS %s", getLocalTime().c_str()); + } + return bf; + } + else return ""; +} diff --git a/code/progress.cpp b/code/progress.cpp new file mode 100644 index 0000000..6a6aeac --- /dev/null +++ b/code/progress.cpp @@ -0,0 +1,229 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include + +#include "oEvent.h" +#include "xmlparser.h" +#include + +#include "gdioutput.h" +#include "commctrl.h" + +#include "localizer.h" +#include "progress.h" + + +void start_progress_thread(void *ptr) +{ + ProgressWindow *pw=(ProgressWindow *)ptr; + pw->process(); +} + +const int p_width = 230; +const int p_height = 12; + +ProgressWindow::ProgressWindow(HWND hWndParent) +{ + lastPrg = 0; + initialized = false; + subStart = 0; + subEnd = 1000; + hWnd = hWndParent; + terminate = false; + running = false; +} + +void ProgressWindow::init() +{ + initialized = true; + progress = 0; + lastProgress = 0; + time = 0; + lastTime = 0; + speed = 0; + RECT rc; + GetClientRect(hWnd, &rc); + hWnd=CreateWindowEx(WS_EX_TOPMOST, "STATIC", "", WS_VISIBLE|WS_CHILD, + (rc.right-p_width)/2, rc.bottom/2, p_width, p_height+1, hWnd, NULL, + (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); + + ShowWindow(hWnd, SW_SHOW); + SetWindowPos(hWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); + SetActiveWindow(hWnd); + UpdateWindow(hWnd); + InitializeCriticalSection(&syncObj); + thread = (HANDLE)_beginthread(start_progress_thread, 0, this); +} + +ProgressWindow::~ProgressWindow() +{ + if (initialized) { + setProgress(1000); + EnterCriticalSection(&syncObj); + terminate = true; + LeaveCriticalSection(&syncObj); + + int maxCount = 100; + while (maxCount-- > 0 && running) { + Sleep(20); + } + EnterCriticalSection(&syncObj); + if (running) + TerminateThread(thread, 0); + LeaveCriticalSection(&syncObj); + +// CloseHandle(thread); + DeleteCriticalSection(&syncObj); + + DestroyWindow(hWnd); + } +} + +void ProgressWindow::process() +{ + running = true; + while (!terminate) { + EnterCriticalSection(&syncObj); + if (!terminate) + draw(GetTickCount()/40); + LeaveCriticalSection(&syncObj); + if (!terminate) + Sleep(33); + } + running = false; +} + +void ProgressWindow::draw(int count) +{ + HDC hDC = GetDC(hWnd); + int prgBase = getProgress(); + int prg = min((prgBase * p_width)/1000, p_width-1); + int center = int(prg*((cos(count*0.1)+1)*0.8) / 2); + + DWORD c=GetSysColor(COLOR_ACTIVECAPTION); + double red=GetRValue(c); + double green=GetGValue(c); + double blue=GetBValue(c); + + double blue1=min(255., blue*1.4); + double green1=min(255., green*1.4); + double red1=min(255., red*1.4); + + int blueD=int(blue/2); + int redD=int(red/2); + int greenD=int(green/2); + + SelectObject(hDC, GetStockObject(DC_PEN)); + SelectObject(hDC, GetStockObject(NULL_BRUSH)); + SetDCPenColor(hDC, RGB(redD,greenD,blueD)); + + Rectangle(hDC, 0, 0, p_width, p_height-1); + SelectObject(hDC, GetStockObject(DC_BRUSH)); + SelectObject(hDC, GetStockObject(NULL_PEN)); + + SetDCBrushColor(hDC, GetSysColor(COLOR_3DHIGHLIGHT)); + + Rectangle(hDC, prg, 1, p_width-1, p_height-2); + + TRIVERTEX vert[4]; + vert [0] .x = 1; + vert [0] .y = 1; + vert [0] .Red = 0xff00&DWORD(red*256); + vert [0] .Green = 0xff00&DWORD(green*256); + vert [0] .Blue = 0xff00&DWORD(blue*256); + vert [0] .Alpha = 0x0000; + + vert [1] .x = center; + vert [1] .y = p_height-2; + vert [1] .Red = 0xff00&DWORD(red1*256); + vert [1] .Green = 0xff00&DWORD(green1*256); + vert [1] .Blue = 0xff00&DWORD(blue1*256); + vert [1] .Alpha = 0x0000; + + vert [2] .x = center; + vert [2] .y = 1; + vert [2] .Red = 0xff00&DWORD(red1*256); + vert [2] .Green = 0xff00&DWORD(green1*256); + vert [2] .Blue = 0xff00&DWORD(blue1*256); + vert [2] .Alpha = 0x0000; + + vert [3] .x = prg; + vert [3] .y = p_height-2; + vert [3] .Red = 0xff00&DWORD(red*256); + vert [3] .Green = 0xff00&DWORD(green*256); + vert [3] .Blue = 0xff00&DWORD(blue*256); + vert [3] .Alpha = 0x0000; + + GRADIENT_RECT gr[2]; + gr[0].UpperLeft=0; + gr[0].LowerRight=1; + gr[1].UpperLeft=2; + gr[1].LowerRight=3; + + GradientFill(hDC,vert, 4, gr, 2, GRADIENT_FILL_RECT_H); + + ReleaseDC(hWnd, hDC); +} + +int ProgressWindow::getProgress() const +{ + DWORD now = GetTickCount(); + int dt = int(now-time); + EnterCriticalSection(&syncObj); + int dp = int(dt * speed); + dp = min(dp, int(progress - lastProgress)); + LeaveCriticalSection(&syncObj); + return min(progress + dp, 1000); +} + +void ProgressWindow::setProgress(int prg) +{ + if (prg <= lastPrg + 1) + return; + lastPrg = prg; + if (!initialized) + return; + EnterCriticalSection(&syncObj); + lastProgress = progress; + lastTime = time; + time = GetTickCount(); + int newProgress = getProgress(); + newProgress = prg > newProgress ? prg : newProgress; + if (lastTime>0) + speed = double(prg - lastProgress) / double(time-lastTime); + progress = max(newProgress, int(progress)); + LeaveCriticalSection(&syncObj); +} + +void ProgressWindow::setSubProgress(int prg) +{ + prg = subStart + prg *(subEnd-subStart) / 1000; + setProgress(prg); +} + +void ProgressWindow::initSubProgress(int start, int end) +{ + subStart = start; + subEnd = end; +} diff --git a/code/progress.h b/code/progress.h new file mode 100644 index 0000000..ba997ec --- /dev/null +++ b/code/progress.h @@ -0,0 +1,54 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class ProgressWindow { + HWND hWnd; + int lastProgress; + DWORD lastTime; + volatile int progress; + DWORD time; + double speed; + + HANDLE thread; + mutable CRITICAL_SECTION syncObj; + volatile bool terminate; + volatile bool running; + + bool initialized; + int lastPrg; + int subStart; + int subEnd; +public: + // Start showing progress + void init(); + + ProgressWindow(HWND hWndParent); + virtual ~ProgressWindow(); + + void process(); + + int getProgress() const; + void setProgress(int prg); + void setSubProgress(int prg); + void initSubProgress(int start, int end); + void draw(int count); +}; diff --git a/code/random.cpp b/code/random.cpp new file mode 100644 index 0000000..6dd0a00 --- /dev/null +++ b/code/random.cpp @@ -0,0 +1,322 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "random.h" + +static int _rbp=0; +static int _rbinterval=1; + +const int PrimeBits=16381; +unsigned short _rbsource[]; + +void InitRanom(int offset, int interval) +{ + if (offset<0) offset=-offset; + if (interval<0) interval=-interval; + + _rbp=offset%PrimeBits; + _rbinterval=interval%PrimeBits; + + if (_rbinterval==0) _rbinterval=1; +} + +bool GetRandomBit() +{ + int p1=_rbp/16; + int p2=_rbp%16; + + int mask=1< &vec) +{ + if (vec.empty()) + return; + + permute(&vec.front(), vec.size()); +} + +void permute(int *array, int size) +{ + int size1=size-1; + + int m=0; + + while(m<=size1) { + if (GetRandomBit()) { + int t=array[size1]; + array[size1]=array[m]; + size1--; + array[m]=t; + } + else m++; + } + + int p1=m; + int p2=size-m; + + if (p1>1) permute(array, p1); + + if (p2>1) permute(&array[p1], p2); +} + +//Truely 16-bit random number +unsigned short _rbsource[1024] = { + 30728, 35457, 26975, 19859, 23519, + 5742, 33642, 14368, 7129, 26291, + 27899, 12534, 29631, 51822, 5116, + 35417, 43931, 10867, 6675, 3520, + 5327, 55783, 6163, 51872, 2022, + 7560, 52062, 25467, 49664, 48585, + 20752, 62332, 26940, 33950, 14160, + 40096, 40812, 34902, 50239, 23210, + 25706, 47651, 47192, 6217, 40301, + 49652, 52899, 28620, 53991, 57852, + 10485, 36089, 16846, 5584, 8677, + 31815, 22339, 24278, 55526, 62684, + 39735, 6753, 5384, 40822, 23192, + 10303, 25428, 51727, 26223, 30049, + 13405, 62013, 63093, 37555, 39870, + 37613, 16503, 33445, 26463, 20228, + 37242, 39552, 51257, 2660, 20339, + 32439, 31637, 60935, 53538, 29452, + 54115, 18739, 49913, 759, 57034, + 24809, 38616, 48361, 65411, 20643, + 919, 35464, 61603, 57907, 21815, + 42812, 10476, 30086, 36103, 5749, + 47644, 32016, 4855, 16566, 52890, + 34894, 36823, 45151, 24524, 42331, + 47215, 29876, 1086, 19682, 44505, + 6953, 48447, 36245, 57337, 49577, + 31192, 61198, 24040, 58801, 6090, + 8809, 34512, 50288, 43905, 52238, + 17551, 64957, 16979, 9085, 16058, + 59048, 19127, 43613, 9212, 21228, + 44774, 49355, 31526, 60870, 60021, + 33378, 1477, 26571, 41926, 22807, + 63555, 50328, 32519, 58060, 8723, + 30810, 23886, 28227, 31135, 5179, + 59446, 1779, 49455, 12293, 27635, + 17108, 27207, 52213, 11773, 48464, + 51180, 34022, 30889, 23256, 4804, + 44202, 38709, 8563, 10425, 8927, + 7202, 62358, 60199, 56370, 10997, + 63435, 45747, 16668, 19149, 47928, + 52858, 14550, 19895, 2221, 24491, + 14678, 1662, 58742, 60776, 37361, + 62283, 35482, 45578, 25345, 27396, + 64403, 10254, 63522, 10742, 16185, + 29178, 2949, 54682, 13276, 56613, + 6709, 49089, 20299, 31633, 65422, + 3376, 52106, 39859, 22744, 59562, + 40792, 28838, 40600, 49722, 26507, + 44161, 60566, 56914, 6553, 44363, + 36017, 30479, 46476, 28601, 45802, + 34504, 25227, 57970, 137, 21241, + 63779, 50860, 59660, 38459, 7041, + 57115, 65314, 59544, 51920, 12941, + 59915, 13229, 44323, 49502, 3986, + 43556, 15283, 55171, 51930, 30124, + 31918, 60884, 52450, 22785, 45804, + 42051, 59293, 22468, 21249, 64383, + 61853, 31326, 59432, 47362, 55949, + 7926, 55496, 51528, 13949, 36770, + 17244, 11081, 41718, 32293, 19623, + 12004, 55951, 19630, 44767, 23274, + 57811, 42013, 53583, 28647, 55799, + 56730, 45717, 3738, 26033, 13187, + 59853, 62262, 42172, 64605, 4250, + 16442, 61124, 9084, 42264, 3296, + 8006, 15245, 34327, 27031, 5858, + 2640, 62110, 40807, 54229, 37204, + 23300, 36879, 41222, 45144, 46438, + 29292, 2871, 43485, 31001, 4079, + 5198, 14977, 35282, 1922, 62253, + 61644, 6911, 40400, 14753, 7053, + 49294, 37683, 16316, 56099, 56827, + 22523, 48722, 12734, 22514, 44588, + 59253, 13579, 45458, 53523, 54413, + 6049, 19933, 1121, 22006, 14235, + 27043, 48798, 56043, 41070, 59482, + 12563, 18473, 17759, 42406, 10542, + 42404, 40131, 31086, 29589, 53042, + 5822, 19427, 59335, 64300, 26468, + 3068, 5974, 29452, 24493, 12050, + 1181, 36582, 40382, 62551, 24868, + 61656, 10073, 2633, 57140, 34621, + 64676, 35919, 56547, 60366, 2179, + 7602, 28768, 21862, 18931, 58015, + 44539, 58886, 31334, 25534, 5831, + 51614, 63768, 41067, 44091, 28948, + 8307, 32583, 10276, 34526, 20340, + 8295, 58427, 63975, 63752, 2230, + 53748, 44164, 53573, 48047, 22021, + 26565, 58103, 36556, 17837, 24933, + 54433, 65420, 7682, 48337, 9110, + 52001, 25769, 16743, 17, 46490, + 54901, 23878, 19348, 22829, 25907, + 28096, 28793, 63691, 54362, 12952, + 58876, 27746, 38542, 29933, 19216, + 32032, 63839, 14429, 17431, 2445, + 45532, 60914, 4649, 22265, 45104, + 9763, 20512, 45049, 25378, 39744, + 10554, 50373, 12992, 8499, 46343, + 16933, 63691, 19219, 28607, 59929, + 7281, 11164, 43687, 12709, 25653, + 45176, 60319, 23950, 20644, 61539, + 61287, 45953, 46149, 33619, 46006, + 65365, 64492, 33842, 36026, 26790, + 16052, 38306, 17781, 35129, 50098, + 52022, 56984, 60295, 29876, 6632, + 47592, 51948, 25687, 25095, 59006, + 35267, 31056, 63081, 6230, 28892, + 48117, 11070, 44274, 38068, 60870, + 3673, 62138, 47151, 217, 55073, + 27930, 48784, 2407, 48362, 8969, + 46317, 63707, 2025, 31577, 42668, + 31790, 43951, 61656, 25632, 48904, + 8734, 2545, 63348, 39723, 21321, + 12448, 11362, 30383, 10485, 42111, + 57866, 6588, 17846, 2188, 59079, + 43620, 241, 27575, 51373, 3111, + 6068, 10372, 64345, 25249, 36913, + 15072, 36880, 22920, 3230, 5081, + 32958, 50358, 7878, 18166, 18909, + 56552, 5527, 43930, 20479, 65480, + 12692, 4868, 39170, 28755, 5191, + 30292, 42759, 26030, 21496, 40897, + 1843, 62971, 61260, 47438, 834, + 17987, 29647, 53149, 62821, 26611, + 28046, 8382, 60773, 7552, 54779, + 54428, 40227, 53776, 57859, 23402, + 35420, 32850, 65448, 40732, 36860, + 25794, 15241, 50379, 4355, 52229, + 46451, 15505, 39115, 46520, 56540, + 11529, 47030, 59898, 35162, 58059, + 53564, 39315, 1535, 25155, 49810, + 8846, 32669, 26626, 53269, 1825, + 64357, 49070, 3600, 33692, 7987, + 61, 24243, 17754, 20137, 39901, + 38795, 28199, 27046, 28004, 33510, + 39150, 48320, 20705, 45764, 40176, + 38714, 1184, 31962, 16213, 51209, + 38278, 24801, 56759, 17018, 60382, + 42066, 47030, 49315, 19948, 31687, + 24178, 59609, 4277, 63742, 39745, + 60057, 39751, 17252, 63402, 39614, + 28135, 12750, 48062, 32869, 42756, + 41237, 44458, 63489, 34621, 24869, + 31908, 65428, 43373, 14052, 19853, + 48763, 14635, 3569, 21064, 51917, + 23082, 54170, 44780, 65368, 1372, + 48083, 42008, 6122, 8996, 34452, + 3303, 54818, 54847, 19141, 6746, + 31631, 36252, 40732, 24195, 32248, + 13508, 43545, 33603, 28745, 41316, + 58808, 24214, 51529, 20705, 2866, + 57107, 51665, 51911, 17662, 28622, + 29578, 50017, 21376, 30333, 2214, + 10489, 48075, 46746, 10809, 1111, + 26559, 29457, 1360, 6469, 10200, + 41521, 34678, 13069, 10882, 366, + 36085, 14816, 9457, 10243, 19000, + 44036, 30160, 22295, 21307, 8242, + 20545, 56386, 27901, 21702, 35236, + 57935, 60688, 6163, 27038, 11634, + 4041, 1011, 61094, 6802, 63312, + 5986, 27700, 13123, 11982, 51424, + 48425, 7091, 52297, 51808, 9253, + 17501, 56772, 18246, 2506, 18773, + 11147, 35416, 47385, 36956, 21263, + 16701, 13794, 52756, 2047, 4534, + 17257, 6853, 19991, 29008, 5273, + 42814, 4589, 56285, 49199, 46228, + 46271, 60096, 53203, 3942, 30218, + 24090, 41675, 51153, 42911, 52293, + 64212, 50287, 41345, 60489, 28006, + 52367, 56447, 43286, 62528, 5916, + 30864, 44523, 58971, 55724, 3494, + 43906, 28694, 21250, 27093, 57804, + 12233, 33150, 2100, 12811, 5052, + 31241, 549, 29819, 59432, 19016, + 48020, 53766, 43348, 13634, 24657, + 17549, 11930, 37716, 18918, 45007, + 21662, 1561, 60785, 57279, 5679, + 26879, 54071, 3220, 6437, 7772, + 64372, 5764, 11973, 1872, 11652, + 29010, 4287, 11284, 7966, 53008, + 44764, 43943, 58067, 6842, 20447, + 49644, 176, 25075, 26989, 54655, + 52950, 47510, 428, 31441, 26850, + 32390, 6361, 41971, 42033, 45355, + 6334, 58392, 44757, 41528, 9593, + 7362, 52409, 16207, 5459, 32215, + 6116, 24159, 37266, 18989, 61404, + 56066, 59647, 51229, 63369, 16396, + 51858, 48111, 49537, 26123, 14758, + 8304, 5843, 20037, 19705, 34137, + 21841, 20916, 48812, 33837, 40442, + 32173, 56091, 15816, 60267, 53482, + 9015, 61795, 41219, 23273, 30874, + 50797, 52328, 50702, 54431, 21615, + 43481, 3443, 47978, 56058, 48777, + 51551, 10601, 21927, 22034, 41042, + 22472, 37855, 64711, 27822, 37580, + 34908, 31200, 55035, 57455, 12870, + 41220, 3053, 16491, 54672, 41618, + 45874, 62483, 10430, 49167, 27787, + 42797, 17295, 57933, 64205, 23999, + 24788, 26660, 23722, 6042 +}; diff --git a/code/random.h b/code/random.h new file mode 100644 index 0000000..b1ee381 --- /dev/null +++ b/code/random.h @@ -0,0 +1,30 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include + +void InitRanom(int offset, int interval); +bool GetRandomBit(); +int GetRandomNumber(int n); + +void permute(vector &vec); +void permute(int *array, int size); diff --git a/code/recorder.cpp b/code/recorder.cpp new file mode 100644 index 0000000..6198367 --- /dev/null +++ b/code/recorder.cpp @@ -0,0 +1,74 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include +#include "recorder.h" +#include "meosexception.h" +#include "meos_util.h" + +Recorder::Recorder() { +#ifdef _DEBUG + isRecording = true; +#else + isRecording = false; +#endif +} + +Recorder::~Recorder() { + +} + +void Recorder::record(const string &cmd) { + if (isRecording) + records.push_back(cmd); +} + +void Recorder::saveRecordings(const string &file) { + ofstream fout(file.c_str(), ios::trunc|ios::out); + fout << "void run() {" << endl; + for (list::iterator it = records.begin(); it != records.end(); ++it) { + if (it->find_first_of("\n") == string::npos) + fout << " " << *it << endl; + else { + vector splt; + split(*it, "\n", splt); + int ls = splt[0].find_last_of('\"'); + if (splt.size() > 1 && ls != string::npos) { + fout << " " << splt[0] << "\"" << endl; + int ind = splt[0].length() + 2 - ls; + for (size_t j = 1; j < splt.size(); j++) { + for (int k = 0; k < ind; k++) + fout << " "; + fout << "\""; + fout << splt[j]; + if (j + 1 == splt.size()) + fout << endl; + else + fout << "\"" << endl; + } + } + } + } + fout << "}" << endl; +} + diff --git a/code/recorder.h b/code/recorder.h new file mode 100644 index 0000000..b8cbe25 --- /dev/null +++ b/code/recorder.h @@ -0,0 +1,47 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class gdioutput; +class oEvent; +class BaseInfo; + +#include + +class Recorder { +private: + list records; + + // True if commands should be recorded + bool isRecording; + +public: + + bool recording() const {return isRecording;} + void saveRecordings(const string &file); + void clearRecordings() {records.clear();} + void record(const string &cmd); + + Recorder(); + ~Recorder(); +}; diff --git a/code/resource.h b/code/resource.h new file mode 100644 index 0000000..b901a63 --- /dev/null +++ b/code/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by meos.rc +// +#define BMP_TEST 15 +#define IDD_MEOS_DIALOG 102 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDI_MEOS 107 +#define IDI_SMALL 108 +#define IDC_MEOS 109 +#define IDR_MAINFRAME 128 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/code/russian.lng b/code/russian.lng new file mode 100644 index 0000000..4a990c3 --- /dev/null +++ b/code/russian.lng @@ -0,0 +1,1890 @@ +encoding = RUSSIAN +(okänd) stämplade vid = (íåèçâåñòíûé) îòìåòèëñÿ íà +(sträckseger) = (ïîáåäèòåëü ýòàïà) +punchNamedTime = (ëèäåð) +(sekunder) = (ñåê.) +[VARNING] ingen/okänd = [ÂÍÈÌÀÍÈÅ] íåò/íåèçâåñòíûé +[Klassens bana] = [Èç ãðóïïû] +[Uppdaterad anmälan] = [Îáíîâë¸ííàÿ çàÿâêà] +tooltip:analyze = Àíàëèç è ïðîñìîòð ââåä¸ííûõ äàííûõ +Alla sträckor/lopp i separata filer = Âñå ýòàïû/çàáåãè â îòäåëüíûå ôàéëû +Vill du klistra in X nya rader i tabellen? = Âû õîòèòå âñòàâèòü X íîâûõ ñòðîê â òàáëèöó? +Vill du lägga till klassen 'X'? = Âû õîòèòå äîáàâèòü ãðóïïó 'X'? +Vill du lägga till banan 'X' (Y)? = Âû õîòèòå äîáàâèòü äèñòàíöèþ 'X' (Y)? +Vill du lägga till laget 'X'? = Âû õîòèòå äîáàâèòü êîìàíäó 'X'? +Vill du lägga till deltagaren 'X'? = Âû õîòèòå äîáàâèòü ó÷àñòíèêà 'X'? +Vill du spara ändringar? = Âû õîòèòå ñîõðàíèòü èçìåíåíèÿ? +Ska X raderas från tävlingen? = Âû õîòèòå óäàëèòü X èç äàííûõ ñîðåâíîâàíèé? +Välj vy = Âûáåðèòå âèä +Välj klasser = Âûáåðèòå ãðóïïû +Välj en vakant plats nedan = Âûáåðèòå ðåçåðâíóþ ïîçèöèþ íèæå +Välj löpare = Âûáåðèòå ó÷àñòíèêà +Klassens bana = Ãðóïïà: äèñòàíöèÿ +TeamRunnerCard = Êîìàíäà: íîìåð ÷èïà ó÷àñòíèêà +StartTimeForClass = Ãðóïïà: âðåìÿ îáùåãî ñòàðòà +elva = 11-ì +Struken = Îòìåí¸í +Trasig = Ëîæíûé ÊÏ +Applicera för specifik sträcka = Ïðèìåíèòü ê ýòàïó +Sätter reptid (X) och omstartstid (Y) för = Óñòàíîâêà âðåìåíè çàêðûòèÿ ôèíèøà (X) è ñòàðòà îñòàâøèõñÿ (Y) äëÿ +Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) = Ñîçäàòü äèñòàíöèþ äëÿ ãðóïïû %s c %d êï èç ÷èïà %d +Skapade en lokal kopia av tävlingen = Ñîçäàòü ëîêàëüíóþ êîïèþ ñîðåâíîâàíèé +Skapa ny klass = Ñîçäàòü íîâóþ ãðóïïó +Skapar ny etapp = Ñîçäàòü íîâóþ ñòàäèþ +Skapar ny tävling = Ñîçäàíèå íîâûõ ñîðåâíîâàíèé +Faktiskt startdjup: X minuter = Ðåàëüíàÿ ïðîäîëæèòåëüíîñòü ñòàðòà: X ìèí. +Radera listan från aktuell tävling = Óäàëèòü ïðîòîêîë èç ñîðåâíîâàíèé +PatrolNameNames = Ó÷àñòíèê (ïàòðóëü): ôàìèëèÿ èìÿ +PatrolClubNameNames = Ó÷àñòíèê (ïàòðóëü): êëóá +Vill du flytta löpare från X till Y och ta bort Z? = Õîòèòå ïåðåíåñòè ó÷àñòíèêîâ èç X â Y, è óäàëèòü Z? +Blockbredd = Øèðèíà áëîêà +help_draw = Æåðåáü¸âêà ïðîâîäèòñÿ â äâà øàãà. Ïåðâûé - âûáåðèòå ãðóïïû äëÿ êîòîðûõ âû õîòèòå ïðîâåñòè æåðåáü¸âêó è çàäàéòå îñíîâíûå íàñòðîéêè. Çàòåì íàæìèòå <Ïðèñâîèòü âðåìåíà>, ïîñëå ÷åãî MeOS ðàñïðåäåëèò ñòàðòîâûå ïîçèöèè ïðîòîêîëå. MeOS ïîçâîëÿåò ãðóïïàì èìåþùèì íåñêîëüêî îäèíàêîâûõ ïåðâûõ ÊÏ íå ñòàðòîâàòü íà îäíîé ìèíóòå, ïðè ýòîì ó÷èòûâàþòñÿ ñòàðòîâûå âðåìåíà óæå ïðîæåðåáü¸âàííûõ ãðóïï.\n\nÐàñïðåäåëåíèå âðåì¸í ïðåäñòàâëÿåòñÿ â âèäå òàáëèöû, â êîòîðîé óêàçàíî ñêîëüêî ÷åëîâåê è èç êàêèõ ãðóïï ñòàðòóåò íà âûáðàííîé ìèíóòå. Äàëåå ìîæíî ïðèñâîèòü ñòàðòîâûå âðåìåíà ó÷àñòíèêàì èëè îáíîâèòü íàñòðîéêè ðàñïðåäåëåíèÿ. +Automatisera = Àâòîìàòèçèðîâàòü +Automatisk lottning = Àâòîìàòè÷åñêàÿ æåðåáü¸âêà +Automatisk utskrift = Àâòîìàòè÷åñêàÿ ïå÷àòü +Automatisk utskrift / export = Àâòîìàòè÷åñêàÿ ïå÷àòü / ýêñïîðò +Välj automatiskt = Àâòîìàòè÷åñêèé âûáîð +Adress = Àäðåñ +Adress och kontakt = Àäðåñ è êîíòàêòû +Konto = Àêêàóíò +Hyrd = Àðåíäà +FilterRentCard = Àðåíäà ÷èïà +Hyrbricksrapport - %s = Àðåíäîâàííûå ÷èïû- %s +Hyrbricka = Àðåíäîâàííûé ÷èï +Återställ säkerhetskopia = Àðõèâ +warn:olddbversion = Áàçà äàííûõ óæå èñïîëüçóåòñÿ áîëåå ïîçäíåé âåðñèåé MEOS. Ðåêîìåíäóåòñÿ îáíîâëåíèå . +Klubbdatabasen = Áàçà êëóáîâ +Löpardatabasen = Áàçà ó÷àñòíèêîâ +Större = Áîëüøå +Stor = Áîëüøîé +Direktanmälan = Áûñòðàÿ çàÿâêà +Snabbinställningar = Áûñòðûå íàñòðîéêè +Eget fönster =  íîâîì îêíå +Destinationskatalog = â ïàïêó +Valuta = Âàëþòà +Skriv första starttid på formen HH:MM:SS = Ââåäèòå âðåìÿ ñòàðòà âèäà ××:ÌÌ:ÑÑ +Ange startintervall för minutstart = Ââåäèòå èíòåðâàë ñòàðòà +Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben = Ââåäèòå ïåðâûå áóêâû íàçâàíèÿ êëóáà è íàæìèòå ñòðåëêó âíèç, ÷òîáû íàéòè êëóá. +Inmatning av mellantider = Ââîä ïðîìåæóòî÷íîãî âðåìåíè +Version X = Âåðñèÿ X +Övre ålder = Âåðõíÿÿ ãðàíèöà âîçðàñòà +Avgift = Âçíîñ +Hög avgift = Âçíîñ +Avrundad tävlingsavgift = Âçíîñ âñåãî (îêðóãëåííûé): +Efteranm. avg. = Âçíîñ çà îïîçäàâøèõ +Ändrade avgift för X deltagare = Âçíîñ èçìåí¸í ó X ó÷àñòíèêîâ +Avgifter = Âçíîñû +Vuxen = Âçðîñëûå +Vuxna = Âçðîñëûå +Vuxenklasser = Âçðîñëûå ãðóïïû +Externt Id = Âíåøíèé ID +Varning: ändringar i X blev överskrivna = Âíèìàíèå: èçìåíåíèÿ â X áóäóò çàïèñàíû +warning:dbproblem = Âíèìàíèå! Ïðîáëåìû ñ ïîäêëþ÷åíèåì ê ÁÄ: 'X'. Ñîåäèíåíèå áûëî àâòîìàòè÷åñêè âîññòàíîâëåíî. Ìîæåòå ïðîäîëæàòü ðàáîòó. +Åldersgränser, reducerad anmälningsavgift = Âîçðàñòíûå îãðàíè÷åíèÿ +Återställ tabeldesignen och visa allt = Âîññòàíîâèòü äèçàéí òàáëèöû +ask:repair = Âîññòàíîâëåíèå áàçû äàííûõ, òîëüêî åñëè âû èñïûòûâàåòå ïðîáëåìû.\n\nImportant:\n-óáåäèòåñü, ÷òî íèêòî íå ïîäêëþ÷åí ê áàçå äàííûõ. \n - Åñëè ñåðâåð ïàäàåò èëè îòêëþ÷àåòñÿ âî âðåìÿ âîññòàíîâëåíèå, íåîáõîäèìî ïåðåçàïóñòèòü åãî è ïîâòîðèòå ïîïûòêó âîññòàíîâëåíèÿ, ïðåæäå ÷åì äåëàòü ÷òî-íèáóäü åùå. Åñëè âû äåëàåòå ëþáûå äðóãèå îïåðàöèè ñ áàçîé äàííûõ âñå äàííûå áóäóò ïîòåðÿíû.\n\nDo âû õîòèòå ïîïðîáîâàòü îïåðàöèþ âîññòàíîâëåíèÿ? +återställd = âîññòàíîâëåíî +Datum = Âðåìÿ +Eventors tider i UTC (koordinerad universell tid) = Âðåìÿ Eventor â UTC (Universal Coordinated Time) +Avgörs kl = Âðåìÿ ãîòîâíîñòè +Ange tiden relativt klassens första start = Âðåìÿ ñòàðòà ïåðâîãî ó÷àñòíèêà +Alla = Âñå +Alla typer = Âñå âèäû +Alla banfiler = Âñå äèñòàíöèè +Alla lopp = Âñå çàáåãè +Alla lag måste ha ett namn = Âñå êîìàíäû äîëæíû èìåòü èìÿ +Alla listor = Âñå ïðîòîêîëû +Alla händelser = Âñå ñîðåâíîâàíèÿ +Alla fakturor = Âñå ñ÷åòà +Alla deltagare måste ha ett namn = Âñå ó÷àñòíèêè äîëæíà áûòü ñ èìåíåì +Ingen löpare saknar bricka = Âñå ó÷àñòíèêè èìåþò SI-÷èï +ALLA( = Âñå( +Klistra in = Âñòàâèòü +Vill du verkligen stänga MeOS? = Âû äåéñòâèòåëüíî õîòèòå çàêðûòü MeOS? +Vill du verkligen radera alla starttider i X? = Âû äåéñòâèòåëüíî õîòèòå î÷èñòèòü ñòàðòîâûå âðåìåíà â X? +Vill du verkligen radera starttider i X klasser? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü ñòàðòîâîå âðåìÿ ó X ãðóïï? +Vill du dumpa aktuellt tävling och skapa en testtävling? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü òåêóùèé ñòàðò è ñîçäàòü òåñòîâûé? +Du kan importera banor och klasser från OCADs exportformat = Âû ìîæåòå èìïîðòèðîâàòü äèñòàíöèè è ãðóïïû èç OCAD èëè Condes (txt, iof-xml) +En klass kan inte slås ihop med sig själv = Âû íå ìîæåòå îáúåäèíèòü ãðóïïû +help:41072 = Âûáåðèòå èç ñïèñêà, ÷òîáû èçìåíèòü èëè óäàëèòü îòìåòêó. Âû ìîæåòå äîáàâèòü íåäîñòàþùèå îòìåòêè èç øàáëîíà äèñòàíöèè. Åñëè âðåìÿ îòñóòñòâóåò, ó÷àñòíèê ïîëó÷àåò ñòàòóñ . Åñëè îòìåòêè íå õâàòàåò, ñòàòóñ – . Íåâîçìîæíî ïðèñâîèòü ñòàòóñ íåïðàâèëüíàÿ îòìåòêà. Åñëè åñòü îòìåòêà, íåîáõîäèìî èçìåíèòü åãî óñòàíîâèòü âðåìÿ âðó÷íóþ. Òîò æå ïðèíöèï ïðèìåíÿåòñÿ äëÿ ñòàðòîâîé îòìåòêè +Välj tävling = Âûáåðèòå ñîðåâíîâàíèÿ +help:restore_backup = Âûáåðèòå ñòàðò è âðåìÿ ñîçäàíèÿ àðõèâà. +Listval = Âûáîð ïðîòîêîëà +Vald bricka = Âûáðàííûå êàðòû +Välj X = Âûáðàòü X +Välj alla = Âûäåëèòü âñ¸ +Välj allt = Âûäåëèòü âñ¸ +Välj alla klasser = Âûäåëèòü âñå ãðóïïû +Justera mot = Âûðàâíèâàíèå ïî +Avsluta = Âûõîä +Födelseår = Ãîä ðîæäåíèÿ +Stad = Ãîðîä +Avgörs X = Ãîòîâíîñòü X +Klass = Ãðóïïà +Klass / klasstyp = Ãðóïïà / Òèï +Klass %d = Ãðóïïà %d +Klassen måste ha ett namn = Ãðóïïà äîëæåí èìåòü íàçâàíèå +ClassName = Ãðóïïà: íàçâàíèå +Klasser = Ãðóïïû +Klasser (IOF, xml) = Ãðóïïû (IOF, xml) +Nästa = Äàëåå +Underlag för tävlingsavgift = Äàííûå ïî âçíîñàì íà ñîðåâíîâàíèè +tolfte = äâåíàäöàòûé +tolva = äâåíàäöàòü +Ungdom = Äåòè +Ungdomsavgift = Äåòè +Ungdomsklasser = Äåòñêèå ãðóïïû +är inte godkänd = äèñêâàëèôèöèðîâàí +Banor = Äèñòàíöèè +Banor (antal kontroller) = Äèñòàíöèè (êîë-âî ÊÏ) +Banor för %s, sträcka %d = Äèñòàíöèè äëÿ %s, ýòàï %d +Banor, IOF (xml) = Äèñòàíöèè, IOF (xml) +Banor, OCAD semikolonseparerat = Äèñòàíöèè, OCAD ôîðìàò +Bana = Äèñòàíöèÿ +Banan används och kan inte tas bort = Äèñòàíöèÿ +Banmall = Äèñòàíöèÿ +Bana %d = Äèñòàíöèÿ %d +Banan måste ha ett namn = Äèñòàíöèÿ äîëæíà áûòü ñ èìåíåì +CourseResult = Äèñòàíöèÿ, ðåçóëüòàò +Längd (m) = Äëèíà (ì) +Ordinarie anmälningsdatum = Äî äàòû: +Lägg till = Äîáàâèòü +Lägg till klasser = Äîáàâèòü / èçìåíèòü ãðóïïó +Lägg till alla = Äîáàâèòü âñå +Lägger till klubbar = Äîáàâèòü êëóá +Lägg till ny = Äîáàâèòü íîâóþ +Lägg till ny etapp = Äîáàâèòü íîâûé ýòàï +Lägg till stämpling = Äîáàâèòü îòìåòêó +Lägger till löpare = Äîáàâèòü ñïîðòñìåíîâ +Lägg till rad = Äîáàâèòü ñòðîêó +Lägg till en ny rad i tabellen (X) = Äîáàâèòü ñòðîêó â òàáëèöå (X) +Välkommen till MeOS = Äîáðî ïîæàëîâàòü â MeOS +Extra = Äîïîëíèòåëüíî +Extra stämplingar = Äîïîëíèòåëüíûå îòìåòêè +Övriga = Äðóãîå +help:ocad13091 = Åñëè ó âàñ åñòü ôàéë äèñòàíöèé (íàïðèìåð, èç OCAD èëè Condes) âû ìîæåòå óêàçàòü èìÿ ôàéëà çäåñü.  ïðîòèâíîì ñëó÷àå, âû ìîæåòå äîáàâèòü äèñòàíöèè ïîçæå. +Kvinna = Æåíùèíû +Kvinnor = Æåíùèíû +Lotta klassen = Æåðåáü¸âêà ãðóïïû +Bold = Æèðíûé +BoldLarge = Æèðíûé, áîëüøîé +BoldSmall = Æèðíûé, ìåëêèé +BoldHuge = Æèðíûé, îãðîìíûé +Listrubrik = Çàãîëîâîê +Tävling från Eventor = Çàãðóçèòü èç Eventor +Ladda upp öppnad tävling på server = Çàãðóçêà ñîðåâíîâàíèé íà ñåðâåð +Stäng = Çàêðûòü +Stäng tävlingen = Çàêðûòü ñîðåâíîâàíèÿ +Kör kontroll inför tävlingen = Çàïóñê ïðîâåðêè ó÷àñòíèêîâ +Anmälda = Çàÿâêè +Anmälningar = Çàÿâêè +Anmälningar (IOF (xml) eller OE-CSV) = Çàÿâêè (IOF (xml) èëè OE-CSV) +Anmälda per distrikt = Çàÿâêè îò òåððèòîðèè +Ändrad = Èçìåíåíî +Ändra lag = Èçìåíèòü êîìàíäó +Ändra klassinställningar = Èçìåíèòü íàñòðîéêè ãðóïïû +Ändra sträckindelning = Èçìåíèòü íàñòðîéêó ýòàïîâ +Ändra grundläggande inställningar och gör en ny fördelning = Èçìåíèòü îñíîâíûå íàñòðîéêè è ñäåëàòü íîâîå ðàñïðåäåëåíèå +Importera = Èìïîðò +Importera IOF (xml) = Èìïîðò IOF (xml) +Importera löpardatabas = Èìïîðò áàçû ó÷àñòíèêîâ +Importera tävlingsdata = Èìïîðò äàííûõ +Importera banor = Èìïîðò äèñòàíöèé +Importera banor/klasser = Èìïîðò äèñòàíöèé/ãðóïï +Importera anmälningar = Èìïîðò çàÿâîê +Importera från OCAD = Èìïîðò èç OCAD +Importera från fil = Èìïîðò èç ôàéëà +Importera stämplingar = Èìïîðò îòìåòîê +Importera tävling = Èìïîðò ñîðåâíîâàíèé +Importera löpare = Èìïîðò ó÷àñòíèêîâ +Importera löpare och klubbar / distriktsregister = Èìïîðò ó÷àñòíèêîâ è êëóáîâ +Importera fil = Èìïîðò ôàéëà +Importera en tävling från fil = Èìïîðòèðîâàòü ñîðåâíîâàíèÿ èç ôàéëà +Klientnamn = Èìÿ êëèåíòà +Användarnamn = Èìÿ ïîëüçîâàòåëÿ +Filnamn = Èìÿ ôàéëà +Filnamn (OCAD banfil) = Èìÿ ôàéëà (OCAD courses) +Filnamn IOF (xml) med klubbar = Èìÿ ôàéëà IOF (xml) ñ êëóáàìè +Filnamn IOF (xml) med löpare = Èìÿ ôàéëà IOF (xml) ñ ó÷àñòíèêàìè +Filnamnet får inte vara tomt = Èìÿ ôàéëà íå äîëæíî áûòü ïóñòûì +Fil: X = Èìÿ ôàéëà: X +Postkod = Èíäåêñ +Intervall = Èíòåðâàë +Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras = Èíòåðâàë (â ñåêóíäàõ). Îñòàâüòå ïîëå ïóñòûì äëÿ àâòîìàòè÷åñêîãî îáíîâëåíèÿ ïîñëå êàæäîãî ñ÷èòûâàíèÿ +Stämplingsintervall (MM:SS) = Èíòåðâàë îòìåòîê (ÌÌ:ÑÑ) +Info = Èíôîðìàöèÿ +Betalningsinformation = Èíôîðìàöèÿ ïî îïëàòå +Använd Eventor = Èñïîëüçîâàòü Eventor +Använd löpardatabasen = Èñïîëüçîâàòü áàçó ñïîðòñìåíîâ +Använd speakerstöd = Èñïîëüçîâàòü êîììåíòàòîðñêèé ìîäóëü +Använd funktioner för fleretappsklass = Èñïîëüçîâàòü ôóíêöèè äëÿ ìíîãîäíåâîê +Använd symbolen X där MeOS ska fylla i typens data = Èñïîëüçóéòå ñèìâîë X, ãäå íåîáõîäèìî ââåñòè äàííûå +Källkatalog = Èñõîäíàÿ ïàïêà +Inläst bricka ställd i kö = Êàðòà áûëà ââåäåíà ïî î÷åðåäè +Resultatkiosk = Êèîñê ðåçóëüòàòîâ +Club = Êëóá +ClubName = Êëóá +KlubbId = Êëóá Id +En klubb kan inte slås ihop med sig själv = Êëóá íå ìîãóò áûòü îáúåäèíåíû +Klubb att ta bort = Êëóá óäàëåí +Klubb: X = Êëóá: X +Klubbar = Êëóáû +Klubbar (IOF, xml) = Êëóáû (IOF, xml) +Klubbar som inte svarat = Êëóáû, êîòîðûå íå îòâåòèëè +Nyckel för Eventor = Êëþ÷ Eventor +Valutakod = Êîä âàëþòû +Antal ignorerade: X = Êîë-âî íå ïðèíÿòûõ: X +Antal = Êîëè÷åñòâî +Antal klasser = Êîëè÷åñòâî ãðóïï +Antal importerade = Êîëè÷åñòâî èìïîðòèðîâàííûõ +Antal kartor = Êîëè÷åñòâî êàðò +Antal besökare X, genomsnittlig bomtid Y, största bomtid Z = Êîëè÷åñòâî ïðîøåäøèõ X, â ñðåäíåì ïîòåðÿ âðåìåíè Y, ìàêñ ïîòåðÿ âðåìåíè Z +Antal löpare = Êîëè÷åñòâî ó÷àñòíèêîâ +Antal löpare på vanligaste banan X = Êîëè÷åñòâî ó÷àñòíèêîâ â íàèáîëåå ÷àñòî èñïîëüçóåìîé äèñòàíöèè X +Antal sträckor = Êîëè÷åñòâî ýòàïîâ +Lag = Êîìàíäà +Laget 'X' saknar klass = Êîìàíäà 'X' íå â ãðóïïå +Lag %d = Êîìàíäà %d +Laget hittades inte = Êîìàíäà íå íàéäåíà +Lag(flera) = Êîìàíäû +Kommentar / version = Êîììåíòàðèé / âåðñèÿ +Speaker = Êîììåíòàòîð +Speakerstöd = Êîììåíòàòîðñêèé ìîäóëü +Datorröst som läser upp förvarningar = Êîìïüþòåðíûé ãîëîñ îáúÿâëÿþùèé áåãóùèõ +Bommade kontroller = Êîíòðîëü îøèáîê +Tidsgräns = Êîíòðîëüíîå âðåìÿ +Kontroll = ÊÏ +Kontroll %s = ÊÏ %s +Kontroll X = ÊÏ X +tar ledningen vid X med tiden Y = ëèäèðóåò â X, ðåçóëüòàò Y +tar ledningen med tiden X = ëèäèðóåò ñ ðåçóëüòàòîì X +Individuell = Ëè÷íûå +Individuella deltagare = Ëè÷íûå ó÷àñòíèêè +Personer = Ëþäè +SmallItalic = Ìåëêèé íàêëîííûé øðèôò +SmallFont = Ìåëêèé øðèôò +Plac. = Ìåñòî +Minsta intervall i klass = Ìèí. èíòåðâàë â ãðóïïå +Minsta startintervall = Ìèí. ñòàðòîâûé èíòåðâàë +Åldersgräns ungdom = Ìîëîæå +Man = Ìóæ÷èíà +Män = Ìóæ÷èíû +Fullskärm = Íà âåñü ýêðàí +Till huvudsidan = Íà ãëàâíóþ +Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad = Íàæìèòå äëÿ ñîõðàíåíèÿ ×èï(à). Interactive readout is activated +Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad = Íàæìèòå äëÿ ñîõðàíåíèÿ ×èï(à). Interactive readout is not activated +Ångra = Íàçàä +Återgå = Íàçàä +Namn = Íàçâàíèå +Klassnamn = Íàçâàíèå ãðóïïû +Lagnamn = Íàçâàíèå êîìàíäû +Kontrollnamn = Íàçâàíèå ÊÏ +Tävlingsnamn = Íàçâàíèå ñîðåâíîâàíèé +Tilldelad = Íàçíà÷åííûé +Klassinställningar = Íàñòðîéêà ãðóïïû +Inställningar = Íàñòðîéêè +Anslutningsinställningar = Íàñòðîéêè ïîäêëþ÷åíèÿ +Tävlingsinställningar = Íàñòðîéêè ñîðåâíîâàíèé +Tävlingsinställningar (IOF, xml) = Íàñòðîéêè ñîðåâíîâàíèé (IOF, xml) +Nationalitet = Íàöèîíàëüíîñòü +Ingen klass vald = Íå âûáðàíà ãðóïïà +Hittar inte hjälpfilen, X = Íå ìîãó íàéòè äîêóìåíòàöèþ, X +Listan kan inte visas = Íå ìîãó ïîêàçàòü ïðîòîêîë +Deltar ej = Íå ïðèíèìàåò ó÷àñòèå +Ingen rogaining = Íå ðîãåéí +Kunde inte ansluta till Eventor = Íå óäàëîñü ïîäêëþ÷èòüñÿ ê Eventor +Ogiltig tid = Íåâåðíîå âðåìÿ +Felaktig nyckel = Íåâåðíûé êëþ÷ +Ogiltigt bricknummer X = Íåâåðíûé íîìåð ÷èïà X +Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y' = íåâåðíûé ôàéë äèñòàíöèé. Äîëæåí áûòü íîìåð X, íàéäåí 'Y' +Bad file format = Íåâåðíûé ôîðìàò ôàéëà +Okänd klass = Íåèçâåñòíàÿ ãðóïïà +Okänd funktion = Íåèçâåñòíûé ðåæèì +Okänd bricka = Íåèçâåñòíûé ÷èï +ask:missingcourse = Íåêîòîðûå ãðóïïû (X) íå èìåþò äèñòàíöèè.\n\n MeOS èñïîëüçóåò äèñòàíöèè ïðè æåðåáüåâêå, ÷òîáû èçáåæàòü ñèòóàöèè êîãäà ó÷àñòíèêè ñ òàêèìè æå ïàðàìåòðàìè ñòàðòîâàëè â òî æå âðåìÿ.\n\nÂû õîòèòå ïðîäîëæèòü â ëþáîì ñëó÷àå? +Operationen stöds ej = Íåïîääåðæèâàåìàÿ îïåðàöèÿ +Felaktigt filformat = Íåïîääåðæèâàåìûé ôîðìàò ôàéëà +Flera banor = Íåñêîëüêî äèñòàíöèé +Flera banor/stafett = Íåñêîëüêî äèñòàíöèé / Ýñòàôåòà +Flera banor / stafett / patrull / banpool = Íåñêîëüêî äèñòàíöèé / Ýñòàôåòà / Ïàòðóëü / Ïî âûáîðó +Inga = íåò +Ingen = íåò +None = Íåò +Ingen klass = Íåò ãðóïï +Ingen bana = Íåò äèñòàíöèé +Klubblös = Íåò êëóáà +Bomfritt lopp / underlag saknas = Íåò îøèáîê / äàííûõ íå õâàòàåò +Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning = Íåò ñâîáîäíûõ ìåñò. Ðåçåðâ ìîæíî ñîçäàòü âî âðåìÿ ñîðòèðîâêè ãðóïïû +Inga deltagare = Íåò ó÷àñòíèêîâ +Undre ålder = Íèæíèé âîçðàñò +Ny klass = Íîâàÿ ãðóïïà +Ny bana = Íîâàÿ äèñòàíöèÿ +Nytt lag = Íîâàÿ êîìàíäà +Nytt fönster = Íîâîå îêíî +Ny tävling = Íîâûå ñîðåâíîâàíèÿ +Ny klubb = Íîâûé êëóá +Ny kontroll = Íîâûé ÊÏ +Ny lista = Íîâûé ïðîòîêîë +Ny deltagare = Íîâûé ó÷àñòíèê +Nr = Íîìåð +Nummerlapp = Íîìåð +Nummerlapp, SI eller Namn = Íîìåð, SI-÷èï, èëè ÔÈÎ +Antal: %d = Íîìåð: %d +Antal: X = Íîìåð: X +Nummerlappar = Íîìåðà +Nummerlappar i X = Íîìåðà äëÿ X +Om MeOS = Î ïðîãðàììå MeOS +Bläddra = Îáçîð +Identifierar X unika inledningar på banorna = Îáíàðóæåíî X óíèêàëüíûõ îòêðûòûõ äèñòàíöèé +Uppdatera = Îáíîâèòü +Uppdatera löpardatabasen = Îáíîâèòü áàçó ñïîðòñìåíîâ +Uppdatera från Eventor = Îáíîâèòü èç Eventor +Ändra inställningar = Îáíîâèòü íàñòðîéêè +Behandlar tävlingsdata = Îáðàáîòêà äàííûõ î ñîðåâíîâàíèÿõ +Behandlar löpardatabasen = Îáðàáîòêà äàííûõ ó÷àñòíèêîâ +Behandlar: X = Îáðàáîòêà: X +Total tävlingsavgift = Îáùàÿ ñóììà çà ñîðåâíîâàíèÿ: +Allmänna resultat = Îáùèå ðåçóëüòàòû +Begränsa antal per klass = Îãðàíè÷åíèå íîìåðîâ â Ãðóïïå +Störst = Îãðîìíûé +Endast en bana = Îäíà äèñòàíöèÿ +Gemensam start = Îäíîâðåìåííûé ñòàðò +Basintervall (min) = Îñíîâíîé èíòåðâàë (min) +Grundinställningar = Îñíîâíûå íàñòðîéêè +Undre gräns (år) = Îò (âîçðàñò, ëåò) +Koppla ifrån = Îòêëþ÷èòüñÿ +Koppla ner databas = Îòêëþ÷èòüñÿ îò áàçû äàííûõ +Öppen = Îòêðûòàÿ +Öppen klass = Îòêðûòàÿ ãðóïïà +Öppnad tävling = Îòêðûòîå ñîðåâíîâàíèå +Öppna klasser, vuxna = Îòêðûòûå ãðóïïû, âçðîñëûå +Öppna klasser, ungdom = Îòêðûòûå ãðóïïû, äåòñêèå +Öppna = Îòêðûòü +Öppna i ett nytt fönster = Îòêðûòü â íîâîì îêíå +Öppna vald tävling = Îòêðûòü âûáðàííûå ñîðåâíîâàíèÿ +Öppna föregående = Îòêðûòü ïðåäûäóùèå +Öppna föregående etapp = Îòêðûòü ïðåäûäóùèé ýòàï +Öppna nästa = Îòêðûòü ñëåäóþùèé +Öppna nästa etapp = Îòêðûòü ñëåäóþùèé ýòàï +Öppna tävling = Îòêðûòü ñîðåâíîâàíèÿ +Öppna fil = Îòêðûòü ôàéë +Öppna från aktuell tävling = Îòêðûòü ýòî ñîðåâíîâàíèå +Avbryt = Îòìåíà +Struken utan återbetalning = Îòìåíåíî, áåç âîçìåùåíèÿ +Struken med återbetalning = Îòìåíåíî, âçíîñ âîçìåù¸í +Avmarkera allt = Îòìåíèòü âûäåëåíèå +Återbud = Îòìåíèòü çàÿâêó +Punches = Îòìåòêè +Stämplingar = Îòìåòêè +Målstämpling saknas = Îòñóòñòâóåò ôèíèøíàÿ îòìåòêà +Tävlingsrapport = Îò÷¸ò +MeOS – Resultatkiosk = Îò÷åò – Ðåçóëüòàòû +Rapport inför = Îò÷åò çà +Hyrbricksrapport = Îò÷åò ïî àðåíäîâàííûì ÷èïàì +Rapporter = Îò÷¸òû +Töm = Î÷èñòèòü +Nollställde avgift för X deltagare = Î÷èñòèòü âçíîñ äëÿ X ó÷àñòíèêîâ +Nollställ databaser = Î÷èñòèòü áàçó äàííûõ +Databasvarning: X = Îøèáêà áàçû äàííûõ: X +Kunde inte ladda upp tävlingen (X) = Îøèáêà çàãðóçêè ó÷àñòíèêîâ (X) +Failed to open 'X' for reading = Îøèáêà îòêðûòèÿ 'X' äëÿ ÷òåíèÿ +FEL, inget svar = Îøèáêà, íåò îòâåòà +Fel: X = Îøèáêà: X +Varning: Banan 'X' finns inte = Îøèáêà: Äèñòàíöèè 'X' íå ñóùåñòâóåò +Varning: Banan 'X' förekommer flera gånger = Îøèáêà: Äèñòàíöèÿ 'X' îïðåäåëåíà íåñêîëüêî ðàç +Varning: Laget 'X' finns inte = Îøèáêà: Êîìàíäû 'X' íå ñóùåñòâóåò +Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Îøèáêà: Îáíàðóæåí ó÷àñòíèê áåç èìåíè. MeOS àâòîìàòè÷åñêè ïðèñâîèë èìÿ 'N.N.' +FEL: Porten kunde inte öppnas = Îøèáêà: ïîðò ìîæåò íå áûòü îòêðûò +Varning: Deltagaren 'X' finns inte = Îøèáêà: Ó÷àñòíèêà 'X' íå ñóùåñòâóåò +Fel: hittar inte filen X = Îøèáêà. Ôàéë íå íàéäåí 'X' +Lösenord = Ïàðîëü +Patrull = Ïàòðóëü +Patrull, 1 SI-pinne = Ïàòðóëü, 1 SI-÷èï +Patrull, 2 SI-pinnar = Ïàòðóëü, 2 SI-÷èïà +Använd första kontrollen som start = Ïåðâàÿ îòìåòêà êà ñòàðò +är först i mål med tiden X = ïåðâûé íà ôèíèøå ñ ðåçóëüòàòîì X +Återställ = Ïåðåâåðíóòü +help:52726 = "Ïåðåä ïîäêëþ÷åíèåì ê ñåðâåðó.\n\nÓñòàíîâêà\nÑêà÷àéòå è óñòàíîâèòå MySQL 5 (Community Edition) ñ ñàéòà www.mysql.com. Ìîæíî èñïîëüçîâàòü íàñòðîéêè ""ïî-óìîë÷àíèþ"". MySQL íåîáõîäèìî óñòàíàâëèâàòü òîëüêî íà êîìïüþòåð èñïîëüçóåìûé â êà÷åñòâå ñåðâåðà. Ïîñëå òîãî êàê MySQL óñòàíîâèòñÿ, çàïóñòèòå MySQL Command Line Client è âûïîëíèòå ñëåäóþùèå êîìàíäû:\n\n> CREATE USER meos;\nGRANT ALL ON *.* TO meos;\n\nÒàêèì îáðàçîì âû ñîçäàëè ïîëüçîâàòåëÿ meos áåç ïàðîëÿ. Ââåäèòå àäðåñ ñåðâåðà â ïîëå íèæå.\n\nÊàê àëüòåðíàòèâà, âû ìîæåòå èñïîëüçîâàòü root äîñòóï ê MySQL. Èìÿ ïîëüçîâàòëåÿ 'root' è ïàðîëü óêàçàííûé ïðè óñòàíîâêå MySQL." +Överför anmälda = Ïåðåäà÷à çàÿâîê +Överför resultat = Ïåðåäà÷à ðåçóëüòàòîâ +Överför resultat till X = Ïåðåäà÷à ðåçóëüòàòîâ â X +Överför resultat till nästa etapp = Ïåðåäà÷à ðåçóëüòàòîâ â ñëåäóþùèé ýòàï +växlar på delad X plats med tiden Y = ïåðåäà÷à ýñòàôåòû X ñ ðåçóëüòàòîì Y +växlar på X plats med tiden Y = ïåðåäà÷à ýñòàôåòû X ñ ðåçóëüòàòîì Y +Döp om = Ïåðåèìåíîâàòü +Flytta vänster = Ïåðåíåñòè âëåâî +Flytta höger = Ïåðåíåñòè âïðàâî +Skriv ut = Ïå÷àòü +Utskrift / export = Ïå÷àòü / Ýêñïîðò +Resultatutskrift / export = Ïå÷àòü / ýêñïîðò ðåçóëüòàòîâ +Skriv ut alla = Ïå÷àòü âñå +Utskriftsintervall (MM:SS) = Ïå÷àòü èíòåðâàëà (MM:SS) +Resultatutskrift = Ïå÷àòü ðåçóëüòàòîâ +Skriv ut sträcktider = Ïå÷àòü ñïëèòîâ +Sträcktidsutskrift = Ïå÷àòü ñïëèòîâ +Sträcktidsutskrift[check] = Ïå÷àòü ñïëèòîâ +Skriver sträcktider om = Ïå÷àòü ÷åðåç +Klassen lottas inte, startstämpling = Ïî ñòàðòîâîé ñòàíöèè +DefaultFont = Ïî óìîë÷àíèþ +Ansluten till = Ïîäêëþ÷åí ê +Databasanslutning = Ïîäêëþ÷åíèå ê ÁÄ +Ansluter till Internet = Ïîäêëþ÷åíèå ê Èíòåðíåòó +Anslutningar = Ïîäêëþ÷åíèé +Anslutna klienter = Ïîäêëþ÷åíî êëèåíòîâ +Aktivera = Ïîäêëþ÷èòü +Anslut = Ïîäêëþ÷èòüñÿ +Anslut till en server = Ïîäêëþ÷èòüñÿ ê ñåðâåðó +Söker efter SI-enheter = Ïîèñê SI-ñòàíöèé +Kön = Ïîë +Långt namn = Ïîëíîå èìÿ +Löpande information om viktiga händelser i tävlingen = Ïîëó÷àòü óâåäîìëåíèÿ î ñîáûòèÿõ íà ñîðåâíîâàíèÿõ +Hjälp = Ïîìîùü +Port = Ïîðò +Port för TCP = Ïîðò äëÿ TCP +Denna etapps nummer = Ïîðÿäêîâûé íîìåð +Tillåt decimaler = ïîñëå çàïÿòîé +Använd sista kontrollen som mål = Ïîñëåäíÿÿ îòìåòêà êàê ôèíèø +Bomtid = Ïîòåðÿ âðåìåíè +Bomtid (max) = Ïîòåðÿ âðåìåíè (ìàêñ.) +Bomtid (median) = Ïîòåðÿ âðåìåíè (ìåäèàí.) +Bomtid (medel) = Ïîòåðÿ âðåìåíè (ñðåä.) +Bomtid: X = Ïîòåðÿ âðåìåíè: X +Postadress = Ïî÷òîâûé àäðåñ +Felst. = ïï.2.6.10 +Tävlingsregler = Ïðàâèëà ñîðåâíîâàíèé +Redigera deltagaren = Ïðàâèòü ó÷àñòíèêà +Ändra = Ïðàâêà +Föregående = Ïðåäûäóùèé +Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar = Ïðèñâîèòü íîìåð íà÷èíàÿ ñ ïåðâîãî, ïóñòûì íå ïðèñâàèâàòü +Knyt löparna till banor från en pool vid målgång = Ïðèâÿæèòå ó÷àñòíèêîâ ê äèñòàíöèÿì ïðè ñ÷èòûâàíèè +Accepterade elektroniska fakturor = Ïðèíèìàòü ýëåêòðîííûå ñ÷åòà +Skrivare = Ïðèíòåð +Check = Ïðîâåðêà +check (X) = ïðîâåðêà (X) +Inspekterar klasser = Ïðîâåðêà ãðóïï +Kontroll inför tävlingen = Ïðîâåðêà ó÷àñòíèêîâ +Fortsätt = Ïðîäîëæèòü +Granska inmatning = Ïðîñìîòð +Listan togs bort från tävlingen = Ïðîòîêîë áûë óäàë¸í èç ñîðåâíîâàíèé +Listor = Ïðîòîêîëû +radio X = ðàäèîÊÏ X +Decimalseparator = Ðàçäåëèòåëü +Textstorlek = Ðàçìåð øðèôòà +Ranking = Ðàíã +Ranking (IOF, xml) = Ðàíã (IOF, xml) +Skriv ut ej accepterade elektroniska = Ðàñïå÷àòàòü åùå íå çàðåãèñòðèðîâàâøèõñÿ +Packar upp löpardatabas = Ðàñøèðåíèå áàçû äàííûõ ó÷àñòíèêîâ +Region = Ðåãèîí +Listredigerare – X = Ðåäàêòîð ïðîòîêîëà – X +Anmälningsläge = Ðåæèì áûñòðîé çàÿâêè +Rapportläge = Ðåæèì îò÷¸òîâ +Reserverade = Ðåçåðâ +Resultat = Ðåçóëüòàò +Klubbresultatlista - %s = Ðåçóëüòàò êëóáà - %s +Etappresultat = Ðåçóëüòàò ñòàäèè +Resultatlistor = Ðåçóëüòàòû +Resultat - %s = Ðåçóëüòàòû - %s +Resultatlista - %s = Ðåçóëüòàòû - %s +Resultat - X = Ðåçóëüòàòû - X +Resultat (STOR) = Ðåçóëüòàòû (áîëüø.) +Resultat för ett visst lopp = Ðåçóëüòàòû äëÿ äàííîãî ýòàïà +Resultat && sträcktider = Ðåçóëüòàòû è ñïëèòû +Individuella slutresultat = Ðåçóëüòàòû ëè÷íûå +Individuella totalresultat = Ðåçóëüòàòû ëè÷íûå ñóììà +Resultat per bana = Ðåçóëüòàòû ïî äèñòàíöèè +Resultat efter sträcka X = Ðåçóëüòàòû ïîñëå X ýòàïà +Resultat efter sträckan = Ðåçóëüòàòû ïîñëå ýòàïà +Rogainingresultat - %s = Ðåçóëüòàòû ðîãåéíà - %s +Stafettresultat, lag = Ðåçóëüòàòû ýñòàôåòû, êîìàíäû +Stafettresultat, delsträckor = Ðåçóëüòàòû ýñòàôåòû, ýòàïû +Stafettresultat, sträcka = Ðåçóëüòàòû ýñòàôåòû, ýòàïû +Stafettresultat, sträcka (STOR) = Ðåçóëüòàòû ýñòàôåòû, ýòàïû (áîëüø.) +Resultat, individuell = Ðåçóëüòàòû, èíäèâèäóàëüíûå +Resultat, generell = Ðåçóëüòàòû, îñíîâíîé +Resultat, patrull = Ðåçóëüòàòû, ïàòðóëü +Omstart = Ðåñòàðò +Rogaining = Ðîãåéí +Manuell inmatning = Ðó÷íîé ââîä +Tidsinmatning = Ðó÷íîé ââîä +Återställ / uppdatera klasstillhörighet = Ñáðîñèòü / îáíîâèòü ãðóïïó ó÷àñòíèêîâ +Nollställ avgifter = Ñáðîñèòü âçíîñ +Återställ löpare med registrering till = Ñáðîñèòü ñòàòóñ â äëÿ ó÷àñòíèêîâ ñ ðåãèñòðàöèåé +Fri anmälningsimport = Ñâîáîäíûé èìïîðò çàÿâîê +Fri starttid = Ñâîáîäíûé ñòàðò +Sammanställning = Ñâîäíàÿ +Sammanställning, klasser = Ñâîäíàÿ, ãðóïïû +Listegenskaper = Ñâîéñòâà ñïèñêà +Kommunikation = Ñâÿçü +Eventor server = Ñåðâåð Eventor +Valutasymbol = Ñèìâîë âàëþòû +Valutasymbol före = Ñèìâîë âàëþòû ïåðåä +Kopiera selektionen till urklipp (X) = Ñêîïèðîâàòü âûáðàííîå â áóôåð (X) +Kopiera länken till urklipp = Ñêîïèðîâàòü ññûëêó â áóôåð +help:baudrate = Ñêîðîñòü ïåðåäà÷è: èñïîëüçóéòå 4800 èëè 38400. +Nästa försök = Ñëåäóþùàÿ ïîïûòêà +Nästa etapp = Ñëåäóþùèé ýòàï ñîðåâíîâàíèé +För många kontroller = Ñëèøêîì ìíîãî ïóíêòîâ +Automater = Ñëóæáû +Klassbyte = Ñìåíèòü ãðóïïó +SOFT-avgift = Ñíèæåííûé âçíîñ +Återansluten mot databasen, tävlingen synkroniserad = Ñîåäèíåíèå ñ DB, ñîðåâíîâàíèÿ ñèíõðîíèçèðîâàíû +Eventorkoppling = Ñîåäèíåíèå ñ Eventor +Generera testtävling = Ñîçäàíèå òåñòîâîãî ñîðåâíîâàíèÿ +Genererad = Ñîçäàíî â +Av MeOS: www.melin.nu/meos = Ñîçäàíî â MeOS: www.melin.nu/meos +Generera = Ñîçäàòü +Duplicera = Ñîçäàòü êîïèþ +Kortnamn = Ñîêðàù. èìÿ +Händelser = Ñîðåâíîâàíèå +Händelser - tidslinje = Ñîðåâíîâàíèå - Õðîíîëîãèÿ +Tävling = Ñîðåâíîâàíèÿ +Tävlingsdata har sparats = Ñîðåâíîâàíèÿ áûëè ñîõðàíåíû +Lagrade säkerhetskopior = Ñîõðàí¸ííûå ñòàðòû +Spara = Ñîõðàíèòü +Spara för webben = Ñîõðàíèòü â HTML +Spara som fil = Ñîõðàíèòü â ôàéë +Spara anmälningar = Ñîõðàíèòü çàÿâêè +Spara som = Ñîõðàíèòü êàê +Spara den här listan som en favoritlista = Ñîõðàíèòü ïðîòîêîë êàê èçáðàííûé +Spara i aktuell tävling = Ñîõðàíèòü ñîðåâíîâàíèÿ +Spara fil = Ñîõðàíèòü ôàéë +Utgått = Ñîø¸ë +Kontroller = Ñïèñîê ÊÏ +Deltagaren 'X' saknar klass = Ñïîðòñìåíó 'X' íå ïðèñâîåíà ãðóïïà +Länk till resultatlistan = Ññûëêà íà ñïèñêå ðåçóëüòàòîâ +Länk till startlistan = Ññûëêà íà ñòàðòîâûé ïðîòîêîë +Grund avg. = Ñòàíä. âçíîñ +Grundavgift = Ñòàíä. âçíîñ +Ordinarie avgift = Ñòàíäàðòíûé +Start = Ñòàðò +Anm. avg. = Ñòàðò. âçíîñ +Anm. avgift = Ñòàðò. âçíîñ +Anmälningsavgift = Ñòàðò. âçíîñ +Manuella avgifter = Ñòàðò. âçíîñ +Startande = Ñòàðòîâàâøèõ +FilterStarted = Ñòàðòîâàëè +Startlista = Ñòàðòîâûé ïðîòîêîë +Åldersgräns äldre = Ñòàðøå +Äldre protokoll = Ñòàðûé ïðîòîêîë +Tävlingsstatistik = Ñòàòèñòèêà ñîðåâíîâàíèé +ask:changedcmpfee = Ñòîèìîñòü ñòàðòîâîãî âçíîñà èçìåíåíà. Âû õîòèòå, ïðèìåíèòü íîâûå ðàçìåð ñòàðòîâîãî âçíîñà íà ñóùåñòâóþùèõ ó÷àñòíèêîâ è ãðóïïû?\n\nÂÍÈÌÀÍÈÅ: Íàçíà÷åííûå âðó÷íóþ ðàçìåðû ñòàðòîâûõ âçíîñîâ áóäóò ïåðåçàïèñàíû. +Land = Ñòðàíà +Nolltid = Ñóäåéñêèé íîëü +FAKTURA = Ñ×¨Ò +Faktura = Ñ÷¸ò +Fakturor = Ñ÷¸ò +Faktura nr = Ñ÷¸ò ¹ +Avläsning/radiotider = Ñ÷èòûâàíèå / Ðàäèî +Tabelläge = Òàáëèöà +Aktuell tid = Òåêóùåå âðåìÿ +CurrentTime = Òåêóùåå âðåìÿ +Geografisk fördelning = Òåððèòîðèè +Testa rösten = Òåñò ãîëîñ +Stämplingstest = Òåñò îòìåòîê +Stämplingstest [!] = Òåñò îòìåòîê [!] +Enhetstyp = Òèï +Klasstyp = Òèï ãðóïïû +Listtyp = Òèï ïðîòîêîëà +FilterOnlyVacant = òîëüêî ðåçåðâ +Formateringsregler = Òðåáîâàíèÿ ôîðìàòèðîâàíèÿ +Zooma in (Ctrl + '+') = Óâåëè÷èòü (Ctrl + '+') +Radera = Óäàëèòü +Ta bort listposten = Óäàëèòü ïðîòîêîë +Radera tävlingen = Óäàëèòü ñîðåâíîâàíèÿ +Gata = Óëèöà +Zooma ut (Ctrl + '-') = Óìåíüøèòü (Ctrl + '-') +help:zero_time = Óñòàíîâèòå ñóäåéñêèé íîëü çà ÷àñ äî ñòàðòà ïåðâîãî ó÷àñòíèêà. +Deltagare = Ó÷àñòíèêè +Löpare = Ó÷àñòíèêè +Löpare utan SI-bricka: %d = Ó÷àñòíèêè áåç SI-÷èïà: %d +Löpare saknar klass eller bana = Ó÷àñòíèêè áåç ãðóïïû è äèñòàíöèè +Löpare utan klass: %d = Ó÷àñòíèêè áåç ãðóïïû: %d +Löpare utan bana: %d = Ó÷àñòíèêè áåç äèñòàíöèè: %d +Löpare utan klubb: %d = Ó÷àñòíèêè áåç êëóáà: %d +Löpare som förekommer i mer än ett lag = Ó÷àñòíèêè â áîëåå ÷åì îäíîé êîìàíäå +Löpare utan starttid: %d = Ó÷àñòíèêè ñ íå ïðèñâîåííûì ñòàðòîâûì âðåìåíåì: %d +Löpare: = Ó÷àñòíèêè: +Fil att exportera till = Ôàéë äëÿ ýêñïîðòà â +Filter = Ôèëüòð +Filtrering = Ôèëüòð +Urval %c%s = Ôèëüòð %c%s +Åldersfilter = Ôèëüòð ïî ãîäó ðîæäåíèÿ +Klart = Ôèíèø +Mål = Ôèíèø +mål = ôèíèø +Klart. X lag importerade = Ôèíèø. X êîìàíä èìïîðòèðîâàíî +Klart. X patruller importerade = Ôèíèø. X ïàòðóëåé èìïîðòèðîâàíî +Måltid = Ôèíèøíîå âðåìÿ +Måltid saknas = Ôèíèøíîå âðåìÿ îòñóòñòâóåò +Måltid: X = Ôèíèøíîå âðåìÿ: X +Formulärläge = Ôîðìà +Format = Ôîðìàò +Funktioner = Ôóíêöèè +ett Mycket Enkelt OrienteringsSystem = õðîíîìåòðàæ äëÿ îðèåíòèðîâàíèÿ +Tidszon = ×àñîâîé ïîÿñ +Klocktid: X = ×àñû: X +Bricka = ×èï +Löparbricka %d = ×èï %d +Bricka %d används redan av %s och kan inte tilldelas = ×èï %d óæå èñïîëüçóåòñÿ %s è íå ìîæåò áûòü ïðèñâîåí +Bricka X = ×èï X +Bricknummret är upptaget (X) = ×èï èñïîëüçóåòñÿ (X) +Brickan redan inläst = ×èï óæå áûë ñ÷èòàí +Brickor = ×èïû +Antalet rader i urklipp får inte plats i selektionen = ×èñëî ñòðîê â áóôåð îáìåíà íå ñîîòâåòñòâóåò âûáðàííîìó +Läser klubbar = ×èòàòü êëóá +Läser löpare = ×èòàòü ñïîðòñìåíîâ +Importerar = ×òåíèå +Importerar OCAD csv-fil = ×òåíèå OCAD CSV +Importerar OE2003 csv-fil = ×òåíèå OE2003 CSV +Importerar OS2003 csv-fil = ×òåíèå OS2003 CSV +Importerar klasser (IOF, xml) = ×òåíèå ãðóïï (IOF, xml) +Importerar tävlingsdata (IOF, xml) = ×òåíèå äàííûõ (IOF, xml) +Importerar banor (IOF, xml) = ×òåíèå äèñòàíöèé (IOF, xml) +Importerar anmälningar (IOF, xml) = ×òåíèå çàÿâîê (IOF, xml) +Importerar klubbar (IOF, xml) = ×òåíèå êëóáîâ (IOF, xml) +Inlästa brickor = ×òåíèå ÷èïà +Latitud = Øèðîòà +Avgiftshöjning (procent) = Øòðàô (%) +Exportera = Ýêñïîðò +Exportera / Säkerhetskopiera = Ýêñïîðò / Ñîõðàíåíèå +Exportera löpardatabas = Ýêñïîðò áàçû ó÷àñòíèêîâ +Exportera alla till HTML = Ýêñïîðò â HTML +Exportera på fil = Ýêñïîðò â ôàéë +Exportera tider i UTC = Ýêñïîðò âðåìåíè â UTC +Exportera datafil = Ýêñïîðò äàííûõ +Exportera tävlingsdata = Ýêñïîðò äàííûõ +Exportera inställningar och löpardatabaser = Ýêñïîðò íàñòðîåê è áàçû äàííûõ +Export av resultat/sträcktider = Ýêñïîðò ðåçóëüòàòîâ / ñïëèòû +Exportera resultat på fil = Ýêñïîðò ðåçóëüòàòîâ â ôàéë +Exportera nu = Ýêñïîðò ñåé÷àñ.... +Exportera sträcktider = Ýêñïîðò ñïëèòîâ +Exportera startlista på fil = Ýêñïîðò ñòàðòîâîãî ïðîòîêîëà â ôàéë +Exportera elektroniska fakturor = Ýêñïîðò ýëåêòðîííûõ ñ÷åòîâ +Elit = Ýëèòà +Elitavgift = Ýëèòà +Elitklasser = Ýëèòíûå ãðóïïû +Med stafettklasser = Ýñòàôåòà +Stafett = Ýñòàôåòà +Stafett - total = Ýñòàôåòà - èòîãîâûé +Stafett - sammanställning = Ýñòàôåòà - ñóììà +Stafett - sträcka = Ýñòàôåòà - ýòàï +Stafett (sammanställning) = Ýñòàôåòà (Ñóììà) +help:12352 = Ýòà îïåðàöèÿ óäàëÿåò êëóá, êîòîðûé âû âûáðàëè (%s, id=%d) è ïåðåíîñèò âñåõ ó÷àñòíèêîâ èç ýòîãî êëóáà â íîâûé êëóá, êîòîðûé âû âûáèðàåòå íèæå. Îïåðàöèÿ íå ìîæåò áûòü îòìåíåíà. +Etapp = Ýòàï +Etapp X = Ýòàï X +Hantera flera etapper = Ýòàïû ñîðåâíîâàíèé +Språk = ßçûê +(lokalt) = (ëîêàëüíî) +(på server) = (íà ñåðâåðå) +(har stämplat) = (îòìå÷åíî) +[Flytta ner] = [Âíèç] +[Bevaka] = [Ïðîñìîòð] +[Återställ] = [Ñáðîñèòü] +%s m = %s ì +%s meter = %s ìåòðîâ +%s, block: %d = %s, Áëîê: %d +tia = 10-ì +tionde = 10-ì +elfte = 11-ì +andra = 2-ì +tvåa = 2-ì +trea = 3-ì +tredje = 3-ì +fjärde = 4-ì +fyra = 4-ì +femma = 5-ì +femte = 5-ì +sexa = 6-ì +sjätte = 6-ì +sjua = 7-ì +sjunde = 7-ì +åtta = 8-ì +åttonde = 8-ì +nia = 9-ì +nionde = 9-ì +API-nyckel = API êëþ÷ +Godkänd API-nyckel = API êëþ÷ ïðèíÿò +c/o = c/o +Utg. = DNF +Ej start = DNS +Disk. = DSQ. +E-post = E-mail +Skriv över existerande bricknummer? = F +Id = Id +Kontrollens ID-nummer = ID ÊÏ +IOF (xml) = IOF (xml) +IOF Resultat (xml) = IOF ðåçóëüòàòû (xml) +IOF Resultat, version 2.0.3 (xml) = IOF ðåçóëüòàòû, âåðñèÿ 2.0.3 (xml) +IOF Resultat, version 3.0 (xml) = IOF ðåçóëüòàòû, âåðñèÿ 3.0 (xml) +IOF Startlista (xml) = IOF ñòàðòîâûé ïðîòîêîë (xml) +IP-adress eller namn på en MySQL-server = IP àäðåñ è èìÿ MySQL ñåðâåðà +localhost = localhost +MeOS = MeOS +help:startmethod = MEOS àâòîìàòè÷åñêè ïðèìåíèò âûáðàííûé ñïîñîá ñòàðòà. Íåçàâèñèìî îò òîãî, ÷òî âû âûáèðàåòå çäåñü, âû âñåãäà ìîæåòå èçìåíèòü ñïîñîá ñòàðòà èëè ïðîâåñòè æåðåáüåâêó ïîçæå. +help:save = MeOS àâòîìàòè÷åñêè ñîõðàíÿåò íàñòðîéêè êîãäà ýòî íåîáõîäèìî +help:assignfee = MeOS áóäåò îáðàáàòûâàòü ñòàðòîâûé âçíîñ äëÿ âàñ àâòîìàòè÷åñêè. Êàæäîé ãðóïïå íàçíà÷åí ñòàðòîâûé âçíîñ. Ïðåäîñòàâèòü çíà÷åíèÿ ïî óìîë÷àíèþ äëÿ ðàçëè÷íûõ ãðóïï ïîä ïàðàìåòðû ó÷àñòíèêîâ, íî âû ìîæåòå òàêæå âðó÷íóþ èçìåíèòü ïàðàìåòðû ãðóïïû ñ ïîìîùüþ áûñòðîé íàñòðîéêè äëÿ class.\n\n Ýòè ñòðàíèöû ïîçâîëÿåò âàì âðó÷íóþ èñïîëüçîâàòü ðàçíûå âîçðàñò è ñðîêè äëÿ ðàçëè÷íûõ ñòàðòîâûõ âçíîñîâ. Íà ñòðàíèöû ó÷àñòíèêà ìîæíî âðó÷íóþ íàñòðîèòü ïëàòà äëÿ îòäåëüíûõ ó÷àñòíèêîâ, ïðè íåîáõîäèìîñòè. +MeOS lokala datakatalog är = MeOS ëîêàëüíàÿ ïàïêà +documentation = meos_doc_eng.html +Inställningar MeOS = MeOS, Íàñòðîéêè +MySQL Server / IP-adress = MySQL ñåðâåð / IP-àäðåñ +SubCounter = ¹ ï.ï. (âòîðè÷íûé) +TotalCounter = ¹ ï.ï. (îñíîâíîé) +SubSubCounter = ¹ ï.ï. (òðåòè÷íûé) +Godkänd = OK +OK = OK +SI på = SI íà +SI X inläst. Brickan är inte knuten till någon löpare (i skogen) = SI-÷èï X áûë ñ÷èòàí. ×èï íå ïðèâÿçàí íè ê îäíîìó ñïîðòñìåíó (íàõîäÿùåìóñÿ â ëåñó) +SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen = SI-÷èï X óæå áûë ñ÷èòàí. Ïîñòàâüòå ãàëêó <Èíòåðàêòèâíàÿ ðàáîòà SI> äëÿ ðåøåíèÿ ïðîáëåìû +SI X är redan inläst. Ska den läsas in igen? = SI-÷èï X óæå ñ÷èòàí. Ñ÷èòàòü åù¸ ðàç? +SportIdent = SportIdent +help:14070 = TCP ïîðò èñïîëüçóåòñÿ äëÿ ïîëó÷åíèÿ îòìåòîê èç äðóãèõ ñèñòåì. Óêàæèòå èñïîëüçóåìûé ïîðò. Ñóäåéñêèé íîëü ïðîòîêîëà áóäåò â 00:00:00. +TCP: Port %d, Nolltid: %s = TCP: Ïîðò %d, Ñóäåéñêèé íîëü: %s +Formaterat webbdokument (html) = Web äîêóìåíò (html) +Webb = Web äîêóìåíò (html) +Webbdokument = Web äîêóìåíò (html) +Webbdokument (html) = Web äîêóìåíò (html) +Hemsida = Web-ñòðàíèöà +Webben (html) = Web-ñòðàíèöà (html) +Codepage = windows-1251 +X (Y deltagare, grupp Z, W) = X (Y ó÷àñòíèêîâ, êîðèäîð Z, W) +X (Saknar e-post) = X (îòñóòñòâóåò e-mail) +X har startat = X âñå ñòàðòîâàëè +X kontroller = X ÊÏ +X meter = X ì. +växlar på X plats, efter Y, på tiden Z = X ìåñòî íà ïåðåäà÷å, ïîñëå Y, ñ ðåçóëüòàòîì Z +X är inget giltigt sträcknummer = X íåâåðíûé íîìåð ýòàïà +X poäng fattas = X î÷êîâ ïîòåðÿíî +X senaste = X ïîñëåäíèõ +X rader kunde inte raderas = X ñòðîêà(è) íå ìîãóò áûòü óäàëåíû +X har redan ett resultat. Vi du fortsätta? = X óæå èìååò ðåçóëüòàò. Âû õîòèòå ïðîäîëæèòü? +X:e = X-ì +info:readout_queue = X: SI-÷èï Y áûë ñ÷èòàí è äîáàâëåí â î÷åðåäü îáðàáîòêè +info:readout_action = X: SI-÷èï Y ñ÷èòàí.\nÍåîáõîäèìî âìåøàòåëüñòâî. +X: Y. Tryck för att spara = X: Y. Íàæìèòå äëÿ ñîõðàíåíèÿ +eventor:question = X\n\nÂû æåëàåòå èñïîëüçîâàòü ïîäêëþ÷åíèå ê Eventor? +xml-data = XML äàííûå +ÅÅÅÅ-MM-DD = YYYY-MM-DD +Automatisk skroll = Àâòîì. ïðîêðóòêà +Rulla upp och ner automatiskt = Àâòîìàòè÷åñêàÿ ïðîêðóòêà +Sök och starta automatiskt = Àâòîïîèñê è çàïóñê +help:471101 = Àêòèâèðóéòå SI ñòàíöèþ âûáðàâ íåîáõîäèìûé COM-ïîðò èëè íàæàâ Àâòîïîèñê è çàïóñê. Äëÿ ïîëó÷åíèÿ ñòàòóñ âûáðàííîãî ïîðòà íàæìèòå Èíôîðìàöèÿ.\n\nÈíòåðàêòèâíîå ñ÷èòûâàíèå ïîçâîëÿåò îïåðàòèâíî ðåøàòü ïðîáëåìû ñ íåâåðíûìè íîìåðàìè ÷èïîâ. Íå èñïîëüçóéòå ýòó îïöèþ â ñëó÷àÿõ, êîãäà ïîäîáíûå ïðîáëåìû ðåøàþòñÿ îòäåëüíî.\n\nÁàçà ó÷àñòíèêîâ èñïîëüçóåòñÿ â ñëó÷àå åñëè âû õîòèòå àâòîìàòè÷åñêè äîáàâëÿòü íîâûõ ó÷àñòíèêîâ â ïðîòîêîë. Ïî ñ÷èòàííûì îòìåòêàì ïðîãðàììà àâòîìàòè÷åñêè îïðåäåëÿåò ãðóïïó ó÷àñòíèêà +Brickhyra = Àð. ÷èïà +Hyravgift = Àðåíäà +Tilldela hyrbrickor = Àðåíäà ÷èïîâ +help:dbage = Áàçà ó÷àñòíèêîâ óñòàðåëà. Çàãðóçèòü íîâóþ áàçó ñ Eventor'a? +Ej lottade = Áåç æåðåáü¸âêè +Ej lottade, efter = Áåç æåðåáü¸âêè â êîíöå +Ej lottade, före = Áåç æåðåáü¸âêè â íà÷àëå +Utan inställningar = Áåç íàñòðîåê +FilterNotVacant = Áåç ðåçåðâà +Utan tidtagning = Áåç ðåçóëüòàòà +Ej tidtagning = Áåç ðåçóëüòàòîâ +Saknad starttid = Áåç ñòàðò. âðåìåíè +FilterNoCard = Áåç ÷èïà +Block = Áëîê +Startblock = Áëîê +Ett startblock spänner över flera starter: X/Y = Áëîê îõâàòûâàåò áîëåå ÷åì îäèí ñòàðò: X / Y +Startblock: %d = Áëîê: %d +Använd stor font = Áîëüøîé øðèôò +LargeFont = Áîëüøîé øðèôò +warning:drawresult =  ãðóïïå óæå èìåþòñÿ ðåçóëüòàòû, ñòàðòîâîå âðåìÿ áóäåò ïåðåçàïèñàíî. Ïðîäîëæèòü? +warning:has_results =  ãðóïïå óæå èìåþòñÿ ðåçóëüòàòû. Èçìåíåíèÿ ïîðÿäêà ýòàïîâ íà â ýòîé ñòàäèè íåâîçìîæíî.\n\nÏðîäîëæèòü? +warning:has_entries =  ãðóïïå óæå èìåþòñÿ ó÷àñòíèêè. Èçìåíåíèÿ ïîðÿäêà ýòàïîâ íà â ýòîé ñòàäèè ìîæåò ïðèâåñòè ê ïîòåðå äàííûõ.\n\nÏðîäîëæèòü? +help:59395 =  ýòîé ôîðìå âû ìîæåòå áûñòðî çàäàòü íàñòðîéêè âñåõ ãðóïï.\n\nÑòàðò - íàçâàíèå ìåñòà ñòàðòà äëÿ ïå÷àòè â ïðîòîêîëàõ.\n\nÁëîê - ÷èñëî îò 1 äî 100, ïîçâîëÿåò ëó÷øå ðàñïðåäåëÿòü ó÷àñòíèêîâ â ïðîòîêîëå. Ãðóïïû â îäíîì áëîêå áóäóò èìåòü òå æå ìèíóòû ñòàðòîâûå ìèíóòû.\n\nÈíäåêñ - ïîðÿäîê ñîðòèðîâêè ãðóïï âî âñåõ ïðîòîêîëàõ.\n\nÒàêæå ìîæíî óêàçàòü äèñòàíöèþ äëÿ ãðóïïû, åñëè ãðóïïå íåîáõîäèìî ïðèñâîèòü íåñêîëüêî äèñòàíöèé, òî âîñïîëüçóéòåñü ñòàíäàðòíîé ôîðìîé.\n\nÁûñòðàÿ çàÿâêà îòêðûâàåò äîñòóï ê áûñòðîé çàÿâêå â ãðóïïó âî âêëàäêå SportIdent +help:29758 =  ýòîé ôîðìå âû ìîæåòå óïðàâëÿòü êëóáàì è ñòàðòîâûìè âçíîñàìè.  ìîæåòå çàäàâàòü ðàçìåð âçíîñà â çàâèñèìîñòè îò ãðóïïû è äàòû çàÿâêè. Äóáëèêàòû êëóáîâ âû ìîæåòå îáúåäèíÿòü èëè óäàëÿòü. +Viktiga händelser = Âàæíûå ñîáûòèÿ +help:eventorkey = Ââåäèòå API êëþ÷ âàøåãî êëóáà â Eventor'e (Øâåöèÿ). Âû ìîæåòå ïîëó÷èòü åãî ó àäìèíèñòðàòîðà âàøåãî êëóáà â Eventor +help:41641 = Ââåäèòå âðåìÿ ñòàðòà ïåðâîãî ó÷àñòíèêà è ñòàðòîâûé èíòåðâàë. Ñëó÷àéíàÿ æåðåáü¸âêà ïîçâîëÿåò ïåðåìåøàòü ñòàðòîâûé ïðîòîêîë â ñëó÷àéíîì ïîðÿäêå. Øâåäñêèé àëãîðèòì èñïîëüçóåò ñïåöèàëüíûå ïðàâèëà äëÿ ðàñïðåäåëåíèå ó÷àñòíèêîâ èç îäíîé êîìàíäû ïî âñåìó ïðîòîêîëó. Ãðóïïîâîé ñòàðò ïîçâîëÿåò çàïóñêàòü ïî íåñêîëüêî ó÷àñòíèêîâ íà îäíîé ìèíóòå (ðàñøèðåííûé ìàññ-ñòàðò).  ïîëå ýòàï âû ìîæåòå óêàçàòü êàêîé ýòàï äîëæåí áûòü ïðîæåðåáü¸âàí, â ñëó÷àå åñëè â ãðóïïå íåñêîëüêî ýòàïîâ. +help:14692 = Ââåäèòå íîìåð ÊÏ, íîìåð ó÷àñòíèêà (èëè íîìåð ÷èïà) è âðåìÿ îòìåòêè (××:ÌÌ:ÑÑ). Âû ìîæåòå îñòàâèòü ïîëå âðåìåíè ïóñòûì, òîãäà áóäåò èñïîëüçîâàíî òåêóùåå âðåìÿ ñ êîìïüþòåðà. Íàæìèòå äëÿ ñîõðàíåíèÿ. +Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar = Ââåäèòå íîìåð ïåðâîãî ó÷àñòíèêà èëè îñòàâüòå ïîëå ïóñòûì äëÿ óäàëåíèÿ íîìåðîâ +Mata in radiotider manuellt = Ââîä ïðîìåæóòî÷íûõ âðó÷íóþ +Skattad avgift = Âçíîñ áåç ÍÄÑ +Sammanställning, ekonomi = Âçíîñû, ñâîäíàÿ òàáëèöà +Normalavgift = Âçðîñëûå +Visualisera startfältet = Âèçóàëèçàöèÿ ñòàðòîâîãî ïðîòîêîëà +Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Âíèìàíèå: Íàéäåíû êîìàíäû áåç íàçâàíèÿ. Îíè íåîáõîäèìû äëÿ ðàáîòû MeOS ïîýòîìó äàííûì êîìàíäàì áóäóò ïðèñâîåíû íàçâàíèÿ 'N.N.' +Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) = Âíèìàíèå: Îðãàíèçàòîð íå óêàçàí (Ñì. íàñòðîéêè ñîðåâíîâàíèé) +Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) = Âíèìàíèå: Ñðîê îïëàòû íå óêàçàí (Ñì. íàñòðîéêè ñîðåâíîâàíèé) +Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Âíèìàíèå: Ñ÷¸ò äëÿ ïåðåâîäà (Ñì. íàñòðîéêè ñîðåâíîâàíèé) +Red. avgift = Âîçâð. âçí. +Reducerad avg = Âîçâð. âçíîñà +Red. avg. efteranm = Âîçâð. îï. âçí. +Sen red. avgift = Âîçâð. îï. âçí. +Reparera vald tävling = Âîññòàíîâèòü âûáðàííûå ñîðåâíîâàíèÿ +Reparerar tävlingsdatabasen = Âîññòàíîâëåíèå áàçû äàííûõ ñîðåâíîâàíèé +Löptid = Âðåìÿ áåãà +Visa alla = Âñå +inforestwarning = Âñå ó÷àñòíèêè âûøëè èç ëåñà. Äàííàÿ èíôîðìàöèÿ ìîæåò áûòü íåêîððåêòíà, âû äîëæíû óáåäèòüñÿ ÷òî â ëåñó íèêòî íå îñòàëñÿ +Samtliga deltagare tilldelades resultat = Âñå ó÷àñòíèêè ñîðåâíîâàíèé èìåþò ðåçóëüòàò +Importerbara = Âñå ôîðìàòû +Totalt kontant = Âñåãî îïëà÷åíî +tooltip:paste = Âñòàâèòü çàÿâêè èç áóôåðà +Klistra in data från urklipp (X) = Âñòàâèòü èç áóôåðà (X) +Sekundär typ = Âòîðè÷íûé òèï +Vill du radera X rader från tabellen? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü X ñòðîê(è) èç òàáëèöû +Vill du radera alla vakanser från tävlingen? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü âñå ðåçåðâíûå ìåñòà? +Vill du verkligen ta bort laget? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü êîìàíäó? +Vill du verkligen radera tävlingen? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü ñîðåâíîâàíèÿ? +Vill du verkligen ta bort löparen? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü ó÷àñòíèêà? +Du måste välja en klass = Âû äîëæíû âûáðàòü ãðóïïó +help:425188 = Âû ìîæåòå àâòîìàòè÷åñêè óêàçàòü íå ñòàðòîâàâøèõ ó÷àñòíèêîâ ñ÷èòàâ ïàìÿòü èç ñòàíöèé (î÷èñòêà/ïðîâåðêà/ñòàðò/ÊÏ) â SI-Config'e. Ñîõðàíèòå ñ÷èòàííûé ôàéë êàê CSV-ôàéë è óêàæèòå åãî íàæàâ èìïîðò îòìåòîê.  ðåçóëüòàòå íàéäåííûå ó÷àñòíèêè ïðîéäóò ðåãèñòðàöèþ. Çàòåì âû ìîæåòå ïðèñâîèòü ñòàòóñ DNS ó÷àñòíèêàì áåç ðåãèñòðàöèè. Òàêæå âû ìîæåòå ñáðîñèòü ñòàòóñ ó ñòàðòîâàâøèõ ó÷àñòíèê íàæàâ êíîïêó ñáðîñ. +help:importcourse = Âû ìîæåòå èìïîðòèðîâàòü äèñòàíöèè è ãðóïïû èç OCAD'a èëè Condes'a. +help:import_entry_data = Âû ìîæåòå èìïîðòèðîâàòü ó÷àñòíèêîâ, ãðóïïû, êëóáû è çàÿâêè èç ðÿäà ðàçëè÷íûõ òåêñòîâûõ è XML ôîðìàòîâ. Íåò íåîáõîäèìîñòè ïðåäîñòàâëÿòü âñå ôàéëû íèæå. Ê ïðèìåðó ôàéë OE-CSV ñ çàÿâêàìè ñîäåðæèò êëóáû è ãðóïïû, òàê ÷òî â ýòîì ñëó÷àå ýòè ïîëÿ äîëæíî áûòü îñòàâëåíû ïóñòûìè.\n\nÅñëè æå ó÷àñòíèê èìïîðòèðóåòñÿ íåñêîëüêî ðàç, âû íå ïîëó÷èòå íåñêîëüêî êîïèé ó÷àñòíèêà. Âìåñòî ýòîãî ïðîãðàììà îáíîâëÿåò ñóùåñòâóþùóþ çàÿâêó. +help:fullscreen = Âû ìîæåòå íàñòðîèòü ñêîðîñòü ïðîêðóòêè íàæèìàÿ Ctrl+M (óâåëè÷èòü) è Ctrl+N (óìåíüøèòü). Äëÿ âûõîäà èç ïîëíîýêðàííîãî ðåæèìà íàæìèòå ESC +help:146122 = Âû ìîæåòå ðàñøèðèòü áàçó MeOS äîáàâèâ ó÷àñòíèêîâ, êëóáû è ãðóïïû èìïîðòèðîâàâ ôàéëû â ôîðìàòå MeOS èëè IOF (xml).\n\nÏðîäîëæèòü? +help:30750 = Âû ìîæåòå ñàìîñòîÿòåëüíî ñîçäàâàòü ïðîòîêîëû èëè îò÷¸òû íåîáõîäèìîãî âàì âèäà. Îíè ìîãóò áûòü îòîáðàæåíû íà ýêðàíå, ðàñïå÷àòàíû è ñîõðàíåíû â HTML ôîðìàòå. Ïðîòîêîëû àâòîìàòè÷åñêè îáíîâëÿþòñÿ ïîñëå ôèíèøà ó÷àñòíèêà. Àâòîìàòè÷åñêàÿ ïå÷àòü ïðîòîêîëà ìîæåò áûòü íàñòðîåíà âî âêëàäêå Ñëóæáû. Äëÿ ýêñïîðòà ïðîòîêîëîâ è ñïëèòîâ ïåðåéäèòå âî âêëàäêó Ñîðåâíîâàíèÿ +fritt att använda och du är välkommen att distribuera det under vissa villkor = Âû ìîæåòå ñâîáîäíî èñïîëüçîâàòü è ðàñïðîñòðàíÿòü ïðîãðàììó â ñîîòâåòñòâèè ñ GNU GPL v3 +help:29191 = Âû ìîæåòå óêàçàòü ïàïêó äëÿ õðàíåíèÿ íàñòðîåê, à òàêæå áàç ó÷àñòíèêîâ è êëóáîâ. Ëîêàëüíûå íàñòðîéêè áóäóò ïåðåïèñàíû. MeOS ìîæåò áûòü ïåðåçàïóùåí ïîñëå óñòàíîâêè.\n\nÊíîïêà ïîçâîëÿåò âàì ñîõðàíèòü íàñòðîéêè îòäåëüíî äëÿ ïîñëåäóþùåãî âîññòàíîâëåíèÿ +help:15491 = Âû ìîæåòå ýêñïîðòèðîâàòü íàñòðîéêè è áàçû äëÿ îòêðûòèÿ íà äðóãîì êîìïüþòåðå +help:50431 = "Âû ïîäêëþ÷åíû ê ñåðâåðó. Äëÿ îòêðûòèÿ ïðîòîêîëà íà ñåðâåðå âûáåðèòå åãî â ñïèñêå è íàæìèòå ""Îòêðûòü"". Äëÿ äîáàâëåíèå ñîðåâíîâàíèé íà ñåðâåð îòêðîéòå åãî ëîêàëüíî è íàæìèòå ""Çàãðóçèòü íà ñåðâåð"". Ïîñëå îòêðûòèÿ ñîðåâíîâàíèé íà ñåðâåðå âû ìîæåòå óâèäåòü âñåõ ïîäêëþ÷åííûõ MeOS êëèåíòîâ." +ask:overwriteconfirm = Âû õîòèòå ïåðåçàïèñàòü ñîðåâíîâàíèÿ. Óáåäèòåñü ÷òî áîëüøå íèêòî ê íèì íå ïîäêëþ÷åí.\n\nÏðîäîëæèòü ïåðåçàïèñü? +Välj klass = Âûáåðèòå ãðóïïó +help:12138 = Âûáåðèòå ãðóïïó äëÿ îáúåäèíåíèÿ ñ âûáðàííîé. Åñëè äëÿ âûáðàííûõ ãðóïï áûëà ïðîâåäåíà æåðåáü¸âêà, òî å¸ íåîáõîäèìî âûïîëíèòü åù¸ ðàç. +Välj klass och starttid nedan = Âûáåðèòå ãðóïïó è ñòàðòîâîå âðåìÿ +help:speaker_setup = Âûáåðèòå ãðóïïû è äèñòàíöèè äëÿ ïðîñìîòðà +Välj vilka klasser och kontroller som bevakas = Âûáåðèòå ãðóïïû è ÊÏ äëÿ ïðîñìîòðà +Välj den etapp som föregår denna tävling = Âûáåðèòå ïðåäûäóùóþ ñòàäèþ +Välj skrivare = Âûáåðèòå ïðèíòåð +Välj lista = Âûáåðèòå ïðîòîêîë +Välj den etapp som kommer efter denna tävling = Âûáåðèòå ñëåäóþùóþ ñòàäèþ +Välj kolumner för tabellen X = Âûáåðèòå ñòîëáöû äëÿ òàáëèöû X +Välj kolumner = Âûáåðèòå ñòîëáöû +Välj kolumner att visa = Âûáåðèòå ñòîëáöû äëÿ îòîáðàæåíèÿ +Välj vilka kolumner du vill visa = Âûáåðèòå ñòîëáöû äëÿ îòîáðàæåíèÿ +Bevakningsprioritering = Âûáåðèòå ó÷àñòíèêà äëÿ ïðîñìîòðà +help:speakerprio = Âûáåðèòå ó÷àñòíèêîâ/êîìàíäû çà êîòîðûìè âû õîòèòå íàáëþäàòü ñî ñòàðòà è äî òåõ ïîð ïîêà îíè ïðåòåíäóþò íà ëèäåðñòâî (îäíà ãàëêà).Îòìåòüòå îáå ãàëêè äëÿ ïðîñìîòðà ó÷àñòíèêà íåçàâèñèìî îò ðåçóëüòàòà. +Välj lopp = Âûáåðèòå ýòàï +Multipel = Âûáîð +Välj vilka klasser och kontroller du vill bevaka = Âûáîð ãðóïï è ÊÏ äëÿ ïðîñìîòðà +help:12290 = Âûáðàííûå ñîðåâíîâàíèÿ ñîçäàíû â äðóãîé âåðñèè MeOS è íå ìîãóò áûòü çàãðóæåíà ñ ñåðâåðà. Ïîïðîáóéòå îòêðûòü èñïîëüçóÿ èìïîðò ñîðåâíîâàíèé +Välj klasser där alla löpare saknar starttid = Âûáðàòü ãðóïïû â êîòîðûõ ñòàðò. âðåìÿ íå áûëî ïðèñâîåíî +Välj klasser där någon löpare saknar starttid = Âûáðàòü ãðóïïû â êîòîðûõ ñòàðò. âðåìÿ ïðèñâîåíî íå âñåì +Klubbstartlista = Âûïèñêà èç ñòàðòîâîãî +Utfört = Âûïîëíåíî +Klart: alla klasser lottade = Âûïîëíåíî: âñå ãðóïïû ïðîñîðòèðîâàíû +Stämplingsautomat = Ãåíåðàòîð îòìåòîê +Förvarningsröst = Ãîëîñîâûå ïðåäóïðåæäåíèÿ +Klart: inga klasser behövde lottas = Ãîòîâî: íåò ãðóïï òðåáóþùèõ æåðåáü¸âêè +Klassen 'X' har jaktstart/växling på första sträckan = Ãðóïïà 'X' èìååò ïåðñüþò/ïåðåäà÷ó íà ïåðâîì ýòàïå +Klass att slå ihop = Ãðóïïà äëÿ îáúåäèíåíèÿ +Klassen används och kan inte tas bort = Ãðóïïà èñïîëüçóåòñÿ è íå ìîæåò áûòü óäàëåíà +ClassLength = Ãðóïïà: äëèíà äèñòàíöèè +ClassResultFraction = Ãðóïïà: êîëè÷åñòâî ôèíèøåé +Klungstart = Ãðóïïîâîé ñòàðò +Klasser där nyanmälningar ska överföras = Ãðóïïû, êîòîðûå áûëè äîáàâëåíû íîâûå çàÿâêè +Anm. datum = Äàòà çàÿâêè +Sträckans banor = Äèñòàíöèè ýòàïà +CourseLength = Äèñòàíöèÿ: äëèíà +CourseClimb = Äèñòàíöèÿ: íàáîð âûñîòû +CourseName = Äèñòàíöèÿ: íàçâàíèå +Minst MySQL X krävs. Du använder version Y = Äëÿ MeOS òðåáóåòñÿ MySQL âåðñèè X è âûøå. Èñïîëüçóåìàÿ âåðñèÿ Y +help:relaysetup = Äëÿ âûáîðà ôîðìàòà ïðîâåäåíèÿ ñîðåâíîâàíèé èñïîëüçóéòå ñîâåòû óêàçàííûå íèæå. Ïîñëå âûáîðà ôîðìàòà âû ìîæåòå çàäàòü íàñòðîéêè äëÿ êàæäîãî ýòàïà, â ñîîòâåòñòâèè ñ íóæíûìè âàì òðåáîâàíèÿìè.\n\nÍåñêîëüêî çàìå÷àíèé:\n- Ýñòàôåòà èñïîëüçóåòñÿ äëÿ ðàçëè÷íûõ âèäîâ ýñòàôåò.\n- Äâóõýòàïíàÿ ýñòàôåòà çíà÷èò ÷òî â êîìàíäå äâà ó÷àñòíèêà è îíè ïåðåäàþò ýñòàôåòó äðóã äðóãó.\n- Ýñòàôåòà-ñîó÷àñòíèê ïîçâîëÿåò íàõîäèòñÿ íà îäíîì ýòàïå íåñêîëüêèì ó÷àñòíèêàì.\n- Ðåæèì ïàòðóëü ïîçâîëÿåò áåæàòü ó÷àñòíèêàì ñ îäíèì èëè äâóìè ÷èïàìè.\n- Ïðîëîã + ïåðñüþò ýòî èíäèâèäóàëüíàÿ ãîíêà, íî ïðîâîäèòñÿ â äâà çàáåãà.\n- Ïóë äèñòàíöèé ïîçâîëÿåò ïðèñâîèòü íåñêîëüêî äèñòàíöèé íà ýòàï è â äàëüíåéøåì ïðîãðàììà àâòîìàòè÷åñêè âûáåðåò íåîáõîäèìóþ îñíîâûâàÿñü íà îòìåòêàõ ñ÷èòàííûõ èç ÷èïà. +För att ändra måltiden måste löparens målstämplingstid ändras = Äëÿ èçìåíåíèÿ ôèíèøíîãî âðåìåíè äîëæíà áûòü èçìåíåíà îòìåòêà ôèíèøà â ÷èïå +help:89064 = Äëÿ êàæäîãî ÊÏ âû ìîæåòå óêàçàòü íåñêîëüêî øèôðîâ.  äèñòàíöèè âû óêàçûâàåòå ÊÏ ïî åãî ID. ×àùå âñåãî âàì íå ïðèä¸òñÿ äîáàâëÿòü ÊÏ, ïîñêîëüêó MeOS àâòîìàòè÷åñêè äåëàåò âñ¸ çà âàñ.\n\nÁîëåå îäíîãî øèôðà äëÿ ÊÏ óêàçûâàåòñÿ â ñëó÷àå åñëè íàäî çàìåíèòü êàêîé-ëèáî ïóíêò èëè èëè ñîçäàòü ïðîñòåéøåå ðàññåèâàíèå. Ñòàòóñ - OK ïîêàçûâàåò ÷òî ÊÏ íåîáõîäèìî äëÿ ïîñåùåíèÿ â äèñòàíöèè. Ñòàòóñ - âûáîð ïîêàçûâàåò ÷òî âñå ÊÏ ñ äàííûì ñòàòóñîì äîëæíû ìîãóò áûòü ïîñåùåíû â ïðîèçâîëüíîì ïîðÿäêå. Ñòàòóñ - ëîæíûé ïîêàçûâàåò ÷òî ÊÏ èãíîðèðóåòñÿ â ñ÷èòàííûõ ÷èïàõ.\n\n Åñëè ó ÊÏ óêàçàíî îïðåäåë¸ííîå íàçâàíèå, òî îíî ìîæåò áûòü ðàñïå÷àòàíî â ðåçóëüòàòàõ ñ ðåçóëüòàòîì íà äàííîì ÊÏ.\n\nÏîïðàâêà âðåìåíè ïîçâîëÿåò êîððåêòèðîâàòü âðåìÿ îòìåòêè íà ÊÏ. Ôîðìàò +/-ÌÌ:ÑÑ èëè +/-××:ÌÌ:ÑÑ.\n\nÌèí. âðåìÿ ýòàïà ïîêàçûâàåò íàèëó÷øèé ðåçóëüòàò íà äàííîì ïåðåãîíå, è â ñëó÷àå åñëè ó÷àñòíèê ïðîáåæàë ëó÷øå, òî íà äàííîì ïåðåãîíå ïðèñâàèâàåòñÿ óêàçàííîå â ïîëå âðåìÿ. Äàííàÿ ôóíêöèÿ èñïîëüçóåòñÿ â ñëó÷àå åñëè ó÷àñòíèêàì òðåáóåòñÿ îáåæàòü êàêîé-ëèáî îïàñíûé ó÷àñòîê èëè ïðî÷åå ïðåïÿòñòâèå. +info:multieventnetwork = Äëÿ îáðàáîòêè áîëåå îäíîãî ýòàïà âû äîëæíû ðàáîòàòü ëîêàëüíî. Ñîõðàíèòå êîïèþ, îòêðîéòå î ëîêàëüíî è ïåðåäàâàéòå ðåçóëüòàòû íà ñëåäóþùèé ýòàï. Çàòåì çàãðóçèòå ñëåäóþùèé ýòàï íà ñåðâåð. +Övre gräns (år) = Äî (âîçðàñò, ëåò) +Till kontroll = Äî ÊÏ +tooltip:builddata = Äîáàâèòü ó÷àñòíèêîâ, êëóáû è ãðóïïû èç ñóùåñòâóþùåé áàçó ñîðåâíîâàíèé +Longitud = Äîëãîòà +Förhöjd avgift = Äîïîëíèòåëüíûé âçíîñ +Tillgängliga automater = Äîñòóïíûå ñëóæáû +help:21576 = Åñëè âàì íàäî èñïðàâèòü îøèáêó, êëèêíèòå íà èìÿ ó÷àñòíèêà äëÿ èçìåíåíèÿ çàÿâêè. Èñïîëüçóéòå ñòðàíèöó Ó÷àñòíèêè äëÿ óäàëåíèÿ çàÿâêè. Äëÿ òîãî ÷òîáû ãðóïïà ïîÿâèëàñü â âûïàäàþùåì ñïèñêå íåîáõîäèìî âêëþ÷èòü äëÿ íå¸ ðåæèì áûñòðîé çàÿâêè. +eventor:help = Åñëè âû èñïîëüçóåòå MeOS â Øâåöèè, òî ðåêîìåíäóåì èñïîëüçîâàòü ïîäêëþ÷åíèå ê Eventor. +Lottad = Æåðåáü¸âêà +Lotta = Æåðåáü¸âêà +Utför lottning = Æåðåáü¸âêà +Lotta / starttider = Æåðåáü¸âêà / Ñòàðò. âðåìåíà +Lotta om hela klassen = Æåðåáü¸âêà ãðóïïû +Lotta klassen X = Æåðåáü¸âêà ãðóïïû 'X' +Lotta flera klasser = Æåðåáü¸âêà íåñêîëüêèõ ãðóïï +Lottar efteranmälda = Æåðåáüåâêà îïîçä. çàÿâîê +Lottar: X = Æåðåáüåâêà ïîðÿäêà ñòàðòà: X +Lottad startlista = Æåðåáü¸âêà ñòàðòîâîãî ïðîòîêîëà +Lotta löpare som saknar starttid = Æåðåáü¸âêà ó÷àñòíèêîâ áåç ñòàðò. âðåìåíè +lopp = çàáåã +Lopp %d = Çàáåã %d +Lopp %s = Çàáåã %s +Lopp X = Çàáåã X +Avgjorda klasser (prisutdelningslista) = Çàâåðø¸ííûå ãðóïïû (Íàãðàäíîé ïðîòîêîë) +Avgjorda placeringar - %s = Çàâåðø¸ííûå ðåçóëüòàòû - %s +klar = çàâåðøåíî +Klart. X deltagare importerade = Çàâåðøåíî. X ó÷àñòíèêîâ èìïîðòèðîâàíî +Klart. Antal importerade: X = Çàâåðøåíî. Êîëè÷åñòâî çàãðóæåííûõ çàÿâîê: X +Rubrik = Çàãîëîâîê +Egen listrubrik = Çàãîëîâîê ïðîòîêîëà +Välj löpare att prioritera bevakning för = Çàäàéòå ïðèîðèòåòû ó÷àñòíèêàì +Välj löpare för sträcka X = Çàäàéòå ó÷àñòíèêà äëÿ ýòàïà X +Knyt löpare till sträckan = Çàäàòü ó÷àñòíèêà íà ýòàï +Repdragningstid = Çàêð. ôèí. +Rep = Çàêð. ôèíèøà +Repdragningstiden måste ligga före omstartstiden = Çàêðûòèå ôèíèøà äîëæíî áûòü äî ñòàðòà íåñòàðòîâàâøèõ +Tillsätt vakans = Çàïîëíåíèå ðåçåðâíûõ ìåñò +Kom ihåg listan = Çàïîìíèòü ïðîòîêîë +Hämtar löpardatabasen = Çàïðîñ áàçû ó÷àñòíèêîâ +Hämtar klasser = Çàïðîñ ãðóïï +Hämtar anmälda = Çàïðîñ çàÿâîê +Hämtar klubbar = Çàïðîñ êëóáîâ +Hämtar tävling = Çàïðîñ ñîðåâíîâàíèé +Hämta löpardatabasen = Çàïðîñèòü áàçó ó÷àñòíèêîâ +Hämta data från Eventor = Çàïðîñèòü äàííûå ñ Eventor +Hämta (efter)anmälningar från Eventor = Çàïðîñèòü çàÿâêè ñ Eventor +Hämta tävlingsdata = Çàïðîñèòü èíôîðìàöèþ î ñîðåâíîâàíèÿ +Hämta tävlingsdata för X = Çàïðîñèòü èíôîðìàöèþ î ñîðåâíîâàíèÿ äëÿ X +Hämta efteranmälningar = Çàïðîñèòü îïîçäàâøèå çàÿâêè +Omstart i stafettklasser = Çàïóñê íåñòàðòîâàâøèõ +Skript att köra efter export = Çàïóñê ñêðèïòà ïîñëå ýêñïîðòà +Starta en guide som hjälper dig göra klassinställningar = Çàïóñòèòå ðóêîâîäñòâî, êîòîðîå ïîçâîëÿåò âàì íàñòðîèòü ãðóïïû +Starta automaten = Çàïóñòèòü ñëóæáó +Startade automater = Çàïóùåííûå ñëóæáû +Anmäl = Çàÿâèòü +Övre datumgräns = Çàÿâêà äî (äàòà) +Undre datumgräns = Çàÿâêà îò (äàòà) +Anmäl X = Çàÿâêà ó÷àñòíèêà X +Ljudfiler, baskatalog = Çâóêîâîé ôàéë, Ïàïêà +help:25041 = Çäåñü âû îïðåäåëÿåòå âàøè äèñòàíöèè. Çàòåì ïðèâÿçûâàåòå ê îäíîé èëè íåñêîëüêèì ãðóïïàì (èëè ó÷àñòíèêàì). Êðîìå òîãî, ìîæíî èìïîðòèðîâàòü äèñòàíöèè ñ OCAD, Condes, èëè äðóãîãî ïðîãðàììíîãî îáåñïå÷åíèÿ. Åñëè âû óêàæèòå êîëè÷åñòâî êàðò, MEOS áóäåò îòñëåæèâàòü êîë-âî äîñòóïíûõ êàðò. +Bygg databaser = Èç ñóùåñòâóþùåé áàçû +warn:changedtimezero = Èçìåíåíèå ñóäåéñêîãî íóëÿ äëÿ ñîðåâíîâàíèé ñ ðåçóëüòàòàìè íå ðåêîìåíäóåòñÿ.\n\nÏðîäîëæèòü? +Redigera listpost = Èçìåíèòü ïðîòîêîë +help:33940 = Èìïîðò çàÿâîê â ñâîáîäíîé ôîðìå. Óêàæèòå èìÿ, êëóá, ãðóïïó è ÷èï (òàê æå ìîæíî óêàçàòü ñòàðòîâîå âðåìÿ), ðàçäåë¸ííûå çàïÿòûìè. Îäèí ó÷àñòíèê äîëæåí çàíèìàòü îäíó ñòðîêó. +tooltip:import = Èìïîðò çàÿâîê èç ôàéëà. +Sträcktidsfil = Èìÿ ôàéëà +Index = Èíäåêñ +Sortering = Èíäåêñ +Tabellverktyg = Èíñòðóìåíòû òàáëèöû +Interaktiv inläsning = Èíòåðàêòèâíàÿ ðàáîòà SI +help:7620 = Èíòåðâàë (â ñåêóíäàõ). Îñòàâüòå ïîëå ïóñòûì äëÿ îáíîâëåíèÿ ïîñëå êàæäîãî ôèíèøà. +Intervallet måste anges på formen MM:SS = Èíòåðâàë äîëæåí áûòü âèäà ÌÌ:ÑÑ +Använd banpool = Èñïîëüçîâàòü ïóë äèñòàíöèé +Listredigerare = Èñïðàâëåíèå ïðîòîêîëîâ +Total = Èòîã +Slutresultat = Èòîãîâûå ðåçóëüòàòû +Totalresultat = Èòîãîâûå ðåçóëüòàòû +Totalresultat - X = Èòîãîâûå ðåçóëüòàòû - X +Att betala = Ê îïëàòå +Totalt faktureras = Ê îïëàòå +Att betala: X = Ê îïëàòå: X +kartor = êàðò(à/û) +ClubRunner = Êëóá / ó÷àñòíèê +ask:kiosk = Êîãäà âû çàïóñêàåòå êèîñê ðåçóëüòàòîâ , MEOS ïåðåõîäèò â ðåæèì, ãäå ìîæíî òîëüêî ïîêàçàòü ðåçóëüòàò è îò÷åòû. Íèêàêèå äðóãèå îïåðàöèè íå äîïóñêàþòñÿ, ïîêà ïðîãðàììà íå áóäåò ïåðåçàïóùåíà. Åñëè åñòü àêòèâíàÿ SI ñòàíöèÿ, ïîäêëþ÷åííàÿ ê êîìïüþòåðó, MEOS àâòîìàòè÷åñêè ïîêàæåò ðåçóëüòàòû äëÿ ïîñëåäíåãî ñ÷èòàííîãî ÷èïà.\n\n  ñëó÷àå íàëè÷èÿ îòêðûòîãî äîñòóïà ê êèîñêó âû äîëæíû çàùèòèòü áàçó äàííûõ ïàðîëåì.\n\nÂû õîòèòå çàïóñòèòü êèîñê ðåçóëüòàòîâ? +Distriktskod = Êîä ðàéîíà +Antal vakanser = Êîë-âî ðåçåðâíûõ ìåñò +Antal startande per block = êîë-âî ñòàðòîâ â áëîêå +Begränsning, antal visade per klass = Êîëè÷åñòâî âûâîäèìûõ çàÿâîê â ãðóïïå +Antal misslyckade: X = Êîëè÷åñòâî îøèáî÷íûõ çàÿâîê: X +Antal startande per intervall (inklusive redan lottade) = Êîëè÷åñòâî ñòàðòóþùèõ ïîìèíóòíî (âêëþ÷àÿ óæå îòæåðåáü¸âàííûõ) +help:7618 = Êîëè÷åñòâî ó÷àñòíèêîâ â êîìàíäå îïðåäåëÿåòñÿ íà âêëàäêå Ãðóïïû +Team = Êîìàíäà +TeamPlaceDiff = Êîìàíäà: Team's place difference (this stages) +TeamTotalTimeDiff = Êîìàíäà: Team's summed time after difference (this stage) +Klubb = Êîìàíäà: êëóá +TeamClub = Êîìàíäà: êëóá +TeamPlace = Êîìàíäà: ìåñòî +TeamName = Êîìàíäà: íàçâàíèå +TeamBib = Êîìàíäà: íîìåð +TeamTimeAfter = Êîìàíäà: îòñòàâàíèå +TeamLegTimeAfter = Êîìàíäà: îòñòàâàíèå íà ýòàïå +TeamRogainingPoint = Êîìàíäà: î÷êè ðîãåéíà +TeamTime = Êîìàíäà: ðåçóëüòàò +TeamTimeStatus = Êîìàíäà: ðåçóëüòàò / ñòàòóñ +TeamTotalTimeStatus = Êîìàíäà: ðåçóëüòàò / ñòàòóñ (âñå ñòàäèè) +TeamLegTimeStatus = Êîìàíäà: ðåçóëüòàò / ñòàòóñ íà ýòàïå +TeamFee = Êîìàíäà: ñòàðò. âçíîñ +TeamStart = Êîìàíäà: ñòàðò. âðåìÿ +TeamStartNo = Êîìàíäà: ñòàðò. íîìåð +TeamStatus = Êîìàíäà: ñòàòóñ +TeamTotalTime = Êîìàíäà: ñóììà âðåìåí (âñå ñòàäèè) +TeamTotalPlace = Êîìàíäà: ñóììà ìåñò (âñå ñòàäèè) +TeamTotalTimeAfter = Êîìàíäà: ñóììà îòñòàâàíèÿ (âñå ñòàäèè) +tooltip:voice = Êîìïüþòåð âîñïðîèçâîäèò ãîëîñîâûå óâåäîìëåíèÿ +Maxtid = Êîíòðîëüíîå âðåìÿ +Kopia X = Êîïèðîâàòü X +Kopia (X) = Êîïèÿ (X) +kontroll = ÊÏ +kontroll X (Y) = ÊÏ X (Y) +Kontrollen används och kan inte tas bort = ÊÏ èñïîëüçóåòñÿ è íå ìîæåò áûòü óäàëåíî +är först vid växeln med tiden X = ëèäåð íà ïåðåäà÷å ñ ðåçóëüòàòîì X +Poänggräns = Ëèìèò î÷êîâ +se license.txt som levereras med programmet = Ëèöåíçèÿ íàõîäèòñÿ â ôàéëå license.txt, â ïàïêå ñ ïðîãðàììîé +Felaktig kontroll = Ëîæíûé ÊÏ +TRASIG( = Ëîæíûé ÊÏ( +Lokalt = Ëîêàëüíî +Största intervall i klass = Ìàêñ. èíòåðâàë íà ãðóïïó +Max antal gemensamma kontroller = Ìàêñ. êîë-âî îáùèõ ÊÏ +Max parallellt startande = Ìàêñ. êîë-âî îäíîâðåìåííûõ ñòàðòîâ +Maxtid efter = Ìàêñ. îòñòàâàíèå +Maximal tid efter ledaren för att delta i jaktstart = Ìàêñ. ïðîèãðûø ëèäåðó äëÿ îòáîðà â ïåðñüþò +Max. vakanser (per klass) = Ìàêñ. ðåçåðâà (íà ãðóïïó) +Skalfaktor = Ìàñøòàá +Relativ skalfaktor för typsnittets storlek i procent = Ìàñøòàá îòíîñèòåëüíî ðàçìåðà øðèôòà (ïðîöåíòû) +Plats = Ìåñòî +Placering in = Ìåñòî â ïîñë. ñòàäèè +Prel. placering = Ìåñòî íà ýòàïå +Metod = Ìåòîä +Reduktionsmetod = Ìåòîä ñîêðàùåíèÿ +Startmetod = Ìåòîä ñòàðòà +Minitid = Ìèí. âðåìÿ +Minsta sträcktid = Ìèí. âðåìÿ ýòàïà +Min. vakanser (per klass) = Ìèí. ðåçåðâà (íà ãðóïïó) +Kortast teoretiska startdjup utan krockar är X minuter = Ìèíèìàëüíîå òåîðåòè÷åñêîå âðåìÿ ñòàðòà X ìèíóò +Tidsskalning = Ìíîæ. âðåìåíè +till = íà +För muspekaren över en markering för att få mer information = Íàâåäèòå êóðñîð íà ìàðêåð ÷òîáû ïîëó÷èòü äîïîëíèòåëüíóþ èíôîðìàöèþ +Prisutdelningslista = Íàãðàäíîé ïðîòîêîë +Listnamn = Íàçâàíèå ïðîòîêîëà +Tävlingens namn: X = Íàçâàíèå ñîðåâíîâàíèé: X +Största gruppen med samma inledning har X platser = Íàèáîëüøåå êîëè÷åñòâî ó÷àñòíèêîâ íà äèñòàíöèè X +Sök deltagare = Íàéòè ó÷àñòíèêà +Italic = Íàêëîííûé +ItalicMediumPlus = Íàêëîííûé, áîëüøå +Egna listor = Íàñòðàèâàåìûå ïðîòîêîëû +Skrivarinställningar för sträcktider = Íàñòðîéêà ïðèíòåðà +Egenskaper = Íàñòðîéêè +Programinställningar = Íàñòðîéêè ïðîãðàììû +Don't know how to align with 'X' = Íå çíàþ êàê âûðîâíÿòü ïî ïîëþ 'X' +Not implemented = Íå ðåàëèçîâàíî +Ingen matchar 'X' = Íå ñîâïàäåíèé ñ 'X' +Skippar lottning = Íå ó÷èòûâàòü ïîðÿäîê æåðåáü¸âêè +Ej elektronisk = íå ýëåêòðîííûé/ðó÷íîé +Ogiltig föregående/efterföljande etapp = Íåâåðíàÿ ñëåäóþùàÿ / ïðåäûäóùàÿ ñòàäèÿ +Ogiltig repdragningstid = Íåâåðíîå âðåìÿ çàêðûòèÿ ôèíèøà +Ogiltig omstartstid = Íåâåðíîå âðåìÿ ñòàðòà îñòàâøèõñÿ ó÷àñòíèêîâ +Ogiltig första starttid. Måste vara efter nolltid = Íåâåðíîå ñòàðò. âðåìÿ ïåðâîãî ó÷àñòíèêà. Äîëæíî áûòü áîëüøå ñóäåéñêîãî íóëÿ. +Ogiltig starttid i 'X' på sträcka Y = Íåâåðíîå ñòàðò. âðåìÿ ó 'X' íà ýòàïå Y +Ogiltig starttid: X = Íåâåðíîå ñòàðò. âðåìÿ: X +Felaktig sträcka = Íåâåðíûé íîìåð ýòàïà +Ogiltigt filformat = Íåâåðíûé ôîðìàò ôàéëà. +Okänd klubb med id X = Íåèçâåñòíûé êëóá ñ id X +Valbar = Íåîáÿçàòåëüíûé +Oväntad kontroll 'X' i bana Y = Íåîæèäàííûé ÊÏ 'X' â äèñòàíöèè Y +Oparad = íåïàðíûé +Ingen / okänd = Íåò / Íåèçâåñòåí +Ingen deltagare matchar sökkriteriet = Íåò ó÷àñòíèêîâ ñîîòâåòñòâóþùèõ êðèòåðèþ ïîèñêà +Kvar-i-skogen = Íåôèíèø. ó÷àñòíèêè +Hantera kvar-i-skogen = Íåôèíèøèðîâàâøèå ó÷àñòíèêè +help:5422 = Íè îäíà SI ñòàíöèÿ íå íàéäåíà. +Start nr = Íîìåð +Stämpelkod(er) = Íîìåð(à) ÊÏ +Stämpelkoder = Íîìåðà ÊÏ +Normal = Íîðìàëüíûé +NormalFont = Íîðìàëüíûé òåêñò +Om MeOS – ett Mycket Enkelt OrienteringsSystem = Î ïðîãðàììå MeOS – a Much Easier Orienteering System +Utbyt tävlingsdata med Eventor = Îáìåí äàííûìè ñîðåâíîâàíèé ñ Eventor +Uppdatera alla värden i tabellen (X) = Îáíîâèòü âñå äàííûå â òàáëèöå (X) +Uppdatera alla klubbar = Îáíîâèòü âñå êëóáû +Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret = Îáíîâèòü êëóá èñïîëüçóÿ áàçó ó÷àñòíèêîâ. +Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret = Îáíîâèòü êëóáû è ó÷àñòíèêè èñïîëüçóÿ áàçó ó÷àñòíèêîâ. +Uppdatera klubbar && löpare = Îáíîâèòü êëóáû è ó÷àñòíèêîâ +Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret = Îáíîâèòü êëóáû èñïîëüçóÿ áàçó ó÷àñòíèêîâ. +Uppdatera fördelning = Îáíîâèòü ðàñïðåäåëåíèå +Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan = Îáíîâèòü ðàñïðåäåëåíèå ñòàðòîâûõ âðåì¸í ñ ó÷¸òîì íàñòðîåê ââåä¸ííûõ âðó÷íóþ. +Uppdatera alla värden i tabellen = Îáíîâèòü òàáëèöó +Radera starttider = Îáíóëèòü ñòàðò. âðåìåíà +Slå ihop = Îáúåäèíèòü +Slå ihop klass: X = Îáúåäèíèòü ãðóïïó: X +Slå ihop klasser = Îáúåäèíèòü ãðóïïû +Slå ihop klubb = Îáúåäèíèòü êëóáû +Slå ihop klass: X (denna klass behålls) = Îáúåäèíèòü ñ ãðóïïîé X +Begränsa per klass = Îãðàíè÷åíèå ïî ãðóïïàì +En gafflad sträcka = Îäèí ðàçäâîåííûé ýòàï +VALFRI( = ÎäèíÈç( +Inkommande = Îæèäàåìûå +Förväntad andel efteranmälda = Îæèäàåìûé ïðîöåíò îïîçä. çàÿâîê +väntas till X om någon minut, och kan i så fall ta en Y plats = îæèäàåòñÿ íà X â òå÷åíèè ìèíóòû, è ìîæåò ïðåòåíäîâàòü Y ìåñòî +väntas till X om någon minut, och kan i så fall ta ledningen = îæèäàåòñÿ íà X â òå÷åíèè ìèíóòû, è ìîæåò ïðåòåíäîâàòü ëèäåðñòâî +Operationen misslyckades = Îïåðàöèÿ íå óñïåøíà +Försöket misslyckades = Îïåðàöèÿ ïðîâàëåíà +Betalat = Îïëà÷åíî +Faktureras = Îïëà÷åíî +Kontant = Îïëà÷åíî +Kontant betalning = Îïëà÷åíî +Förvarning på (SI-kod): alla stämplingar = Îïîâåùåíèå (SI îòìåòêè): Âñå îòìåòêè +Sen avgift = Îïîçä. âçí. +Efteranmälda (före ordinarie) = Îïîçä. çàÿâêè (âïåðåäè) +Efteranmälda (efter ordinarie) = Îïîçä. çàÿâêè (ïîñëå âñåõ) +Efteranmälda före ordinarie = Îïîçä. çàÿâêè âïåðåäè +Efteranmälningar = Îïîçäàâøèå çàÿâêè +help:splitexport = Îïðåäåëèòå â êàêîì ôîðìàòå âû õîòèòå ñîõðàíèòü: èòîãîâûå ðåçóëüòàòû èëè ðåçóëüòàòû êàæäîãî çàáåãà. Åñëè âû âûáåðèòå âñå çàáåãè, òî ñîçäàííûå ôàéëû áóäóò ïðîíóìåðîâàíû. +Optimerar startfördelning = Îïòèìèçàöèÿ ðàñïðåäåëåíèÿ ñòàðò. âðåìåíè +Publicera resultat = Îïóáëèêîâàòü ðåçóëüòàòû +Publicera startlista = Îïóáëèêîâàòü ñòàðò. ïðîòîêîë +Publicera startlistan på Eventor = Îïóáëèêîâàòü ñòàðò. ïðîòîêîë â Eventor +Arrangör = Îðãàíèçàòîð +Organisation = Îðãàíèçàöèÿ +Huvudlista = Îñíîâíîé ïðîòîêîë +Stoppa automaten = Îñòàíîâèòü ñëóæáó +help:9615 = Îòâåò íå ïîëó÷åí. Ïåðåêëþ÷èòü ïîðò â ïàññèâíûé ðåæèì? +Sätt som oparad = Îòâÿçàòü +Kopplar ifrån SportIdent på = Îòêëþ÷åíèå SI îò +ej aktiv = îòêëþ÷åíî +Ej accepterade elektroniska fakturor = Îòìåí¸ííûå ýëåêòðîííûå ñ÷åòà +Välj ingen = Îòìåíèòü âñ¸ +Välj inget = Îòìåíèòü âñ¸ +stämplade vid = îòìåòèëñÿ íà +stämplar vid X som Y, på tiden Z = îòìåòèëñÿ íà X ñ Y ðåç-òîì (Z) +Status OK = Îòìåòêà OK +Stämplar om = Îòìåòêà ÷åðåç +Efter = Îòñò. +Tid efter: X = Îòñòàâàíèå: X +"Tid efter: X; har tagit in Y" = "Îòñòàâàíèå: X; îòûãðàíî Y" +"Tid efter: X; har tappat Y" = "Îòñòàâàíèå: X; ïîòåðÿíî Y" +Minsta intabbning = Îòñòóï +saknas = îòñóòñòâ. â ÷èïå +Poäng = Î÷êè +Rogaining-poäng = Î÷êè (ðîãåéí) +Poäng in = Î÷êè â ïîñë. ñòàäèè +Failed to generate card = Îøèáêà ïðè ãåíåðàöèè ÷èïà +Parallell = Ïàðàëëåëüíûé +Tillämpa parstart = Ïàðíûé ñòàðò +Par- eller singelklass = Ïàòðóëü èëè îäèíî÷íûé +Första kontrollen = Ïåðâûé ÊÏ +är först vid X med tiden Y = ïåðâûé íà X ñ ðåçóëüòàòîì Y +Första sträckan kan inte vara parallell = Ïåðâûé ýòàï íå ìîæåò áûòü ïàðàëëåëüíûì +Omvänd jaktstart = Ïåðåâ¸ðíóòûé ïåðñüþò +"Överför nya deltagare i ej valda klasser med status ""deltar ej""" = "Ïåðåâåñòè íîâûõ ó÷àñòíèêîâ â ãðóïïû ñî ñòàòóñîì ""íå ïðèíèìàåò ó÷àñòèÿ""" +Växling = Ïåðåäà÷à +växeln = ïåðåäà÷å +Tidsintervall (MM:SS) = Ïåðèîä îáíîâëåíèÿ (ÌÌ:ÑÑ) +Jaktstart = Ïåðñüþò +Skriv endast ut ändade sidor = Ïå÷àòàòü òîëüêî èçìåí¸ííûå ïðîòîêîëû +tooltip:resultprint = Ïå÷àòü è ýêñïîðò ïðîòîêîëîâ +Skriv ut eller exportera listan automatiskt = Ïå÷àòü èëè ýêñïîðò ïðîòîêîëà àâòîìàòè÷åñêè +Skriv ut rapporten = Ïå÷àòü îò÷¸òà +Skriv ut dem utan e-post = Ïå÷àòü ïðîïóùåííûõ e-mail +Skriv ut listan = Ïå÷àòü ïðîòîêîëà +Skriv ut fakturan = Ïå÷àòü ñ÷¸òà +Skriv ut tabellen = Ïå÷àòü òàáëèöû +Skriv ut tabellen (X) = Ïå÷àòü òàáëèöû (X) +SortNameOnly = ïî èìåíè +ClassTotalResult = ïî èòîã. ðåç-òó â ãðóïïå +ClassPoints = ïî êîë-âó ÊÏ â ãðóïïå +ClassCourseResult = ïî ðåçóëüòàòàì ãðóïïû / äèñòàíöèè +ClassResult = ïî ðåçóëüòàòó ãðóïïû +StartTime = ïî ñòàðò. âðåìåíè +ClassStartTime = ïî ñòàðòó ãðóïïû +ClassStartTimeClub = ïî ñòàðòó ãðóïïû è êëóáà +FinishTime = ïî ôèíèøó +ClassFinishTime = ïî ôèíèøó ãðóïïû +ClassTeamLeg = ïî ýòàïàì +Justera blockvis = Ïîáëî÷íîå âûðàâíèâàíèå +SI-dubbletter: %d = Ïîâòîðíûõ SI-÷èïîâ: %d +Förbered lottning = Ïîäãîòîâêà æåðåáü¸âêè +Vi stöder MeOS = Ïîääåðæèâàþò MeOS +Underrubrik = Ïîäçàãîëîâîê +Startar SI på = Ïîäêëþ÷åíèå ê SI íà +Underlista = Ïîäñòðîêà +Bekräfta att deltagaren har lämnat återbud = Ïîäòâåðäèòå îòìåíó äàííîé çàÿâêè +Bekräfta att %s byter klass till %s = Ïîäòâåðäèòå ïåðåíîñ %s â ãðóïïó %s +Verkställ = Ïîäòâåðäèòü +Vänligen återlämna hyrbrickan = Ïîæàëóéñòà âåðíèòå ÷èï +Vänligen betala senast = Ïîæàëóéñòà îïëàòèòå íå ïîçäíåå +Sök = Ïîèñê +Sök (X) = Ïîèñê (X) +Sök på namn, bricka eller startnummer = Ïîèñê ïî èìåíè, ÷èïó èëè íîìåðó +Tävlingen innehåller inga resultat = Ïîêà åù¸ íåò íè îäíîãî ðåçóëüòàòà +Visa = Ïîêàçàòü +Topplista, N bästa = Ïîêàçàòü N ëó÷øèõ +Visa klubbdatabasen = Ïîêàçàòü áàçó êëóáîâ +Visa löpardatabasen = Ïîêàçàòü áàçó ó÷àñòíèêîâ +Visa och hantera löpardatabasen = Ïîêàçàòü áàçó ó÷àñòíèêîâ +Visa valda deltagare = Ïîêàçàòü âûáðàííûõ ó÷àñòíèêîâ +Visa avancerade funktioner = Ïîêàçàòü äîïîëíèòåëüíûå íàñòðîéêè +Visa tillgängliga säkerhetskopior = Ïîêàçàòü äîñòóïíûå áåêàïû +Visa mellantider = Ïîêàçàòü ñïëèòû +Visa startlistan = Ïîêàçàòü ñòàðòîâûé ïðîòîêîë +Visa en tabell över alla stämplingar = Ïîêàçàòü òàáëèöó ñ îòìåòêàìè +Visar de X bästa = Ïîêàçûâàòü ïåðâûõ X +Visa senast inlästa deltagare = Ïîêàçûâàòü ïîñëåäíåãî ñ÷èòàâøåãîñÿ +Mellantider visas för namngivna kontroller = Ïîêàçûâàòü ïðîìåæ. ðåç-òû äëÿ ÊÏ ñ íàçâàíèÿìè +skicka stämplar = ïîëó÷åíèå îòìåòîê +Hämta svar om elektroniska fakturor = Ïîëó÷èòü äàííûå î îïëà÷åííûõ ñ÷åòàõ +Tidsjustering = Ïîïðàâêà âðåìåíè +Global sorteringsordning = Ïîðÿäîê ñîðòèðîâêè +sortering: X, antal rader: Y = ïîðÿäîê ñîðòèðîâêè: X, êîë-âî ñòðîê: Y +Först-i-mål, gemensam = Ïîðÿäîê ôèíèøà, îáùèé +Först-i-mål, klassvis = Ïîðÿäîê ôèíèøà, ïî ãðóïïàì +Vakanser / klassbyte = Ïîñëåäíèå èçìåíåíèÿ +Sista ordinarie anmälningsdatum = Ïîñëåäíèé ñðîê ïîäà÷è çàÿâîê +Sista start (nu tilldelad) = Ïîñëåäíèé ñòàðò (íàçíà÷åí ñåé÷àñ) +Sista sträckan = Ïîñëåäíèé ýòàï +Sista start (nu tilldelad): X = Ïîñëåäíÿÿ ñòàðòîâàÿ ìèíóòà (óæå ïðèñâîåííàÿ): X +Prel. bomtid = Ïîòåðè íà ýòàïå +Redigera lista = Ïðàâêà ôîðì +Föregående etapp = Ïðåäûäóùèé ýòàï ñîðåâíîâàíèé +Prioritering = Ïðèîðèòåòû +Tilldela endast avgift till deltagare utan avgift = Ïðèñâàèâàòü âçíîñ òîëüêî ó÷àñòíèêàì áåç âçíîñà +Tilldelning av hyrbrickor = Ïðèñâîåíèå àðåíäîâàííûõ ÷èïîâ +Sträcktilldelning, stafett = Ïðèñâîåíèå ýòàïîâ, ýñòàôåòà +Para ihop = Ïðèñâîèòü +Tilldela = Ïðèñâîèòü +Tilldela avgifter = Ïðèñâîèòü âçíîñû +Fördela starttider = Ïðèñâîèòü âðåìåíà +Låt klassen ha mer än en bana eller sträcka = Ïðèñâîèòü ãðóïïå áîëåå 1 ýòàïà / äèñòàíöèè +Tilldela nummerlappar = Ïðèñâîèòü íîìåðà +Para ihop bricka X med en deltagare = Ïðèñâîèòü ÷èï X ó÷àñòíèêó +Det här programmet levereras utan någon som helst garanti. Programmet är = Ïðîãðàììà ðàñïðîñòðàíÿåòñÿ ïî ïðèíöèïó as-is. +Prolog + jaktstart = Ïðîëîã + ïåðñüþò +Klass saknad = Ïðîïóñê ãðóïïû +Hoppar över stafettklass: X = Ïðîïóñê ýñòàôåòíîé ãðóïïû: X +Stämplingar saknas: X = Ïðîïóùåíû ÊÏ: X +Förhandsgranskning, import = Ïðîñìîòð èìïîðòà +Bevakar händelser i X = Ïðîñìîòð ñîáûòèé â X +Lista = Ïðîòîêîë +Visa listan i fullskärm = Ïðîòîêîë íà âåñü ýêðàí +Lista av typ 'X' = Ïðîòîêîë ïî òèïàì 'X' +Lista med mellantider = Ïðîòîêîë ñî ñïëèòàìè +Lista med sträcktider = Ïðîòîêîë ñî ñïëèòàìè +Listor och sammanställningar = Ïðîòîêîëû è îò÷¸òû +Publicerar resultat = Ïóáëèêàöèÿ ðåçóëüòàòîâ +Publicera resultat och sträcktider på Eventor och WinSplits online = Ïóáëèêàöèÿ ðåçóëüòàòîâ è ñïëèòîâ íà Eventor è WinSplits îíëàéí +Publicerar startlistan = Ïóáëèêàöèÿ ñòàðò. ïðîòîêîëà +Banpool, gemensam start = Ïóë äèñòàíö., îáù. ñòàðò +Banpool, lottad startlista = Ïóë äèñòàíö., ðàçä. ñòàðò +Banpool = Ïóë äèñòàíöèé +help:26963 = Ïóë äèñòàíöèÿ èñïîëüçóåòñÿ äëÿ îïðåäåëåíèÿ íåñêîëüêèõ äèñòàíöèé íà ýòàï. Äèñàòíöèÿ ïðèñâàèâàåòñÿ ó÷àñòíèêó íà ôèíèøå ïî ñîäåðæèìîìó ÷èïà. [S] ïîñëå íàçâàíèÿ ãðóïïû óêàçûâàåò ÷òî âñåì ó÷àñòíèêàì èç ãðóïïû ïðèñâîåíî ñòàðòîâîå âðåìÿ.. +help:runnerdatabase = Ïóòåì èìïîðòà ó÷àñòíèêà â áàçó äàííûõ, MEOS àâòîìàòè÷åñêè ðàñïîçíàåò íåèçâåñòíûå ó÷àñòíèêîâ (ïî íîìåðó êàðòû), è íàçíà÷àåò àäðåñà è íîìåðà òåëåôîíîâ +Radiotider, kontroll = ÐàäèîÊÏ +Dela klassen = Ðàçáèòü ãðóïïó +Dela klass: X = Ðàçáèòü ãðóïïó: X +Dela klubbvis = Ðàçáèòü ïî êëóáó +Dela efter ranking = Ðàçáèòü ïî ðàíãó +Dela = Ðàçäåëèòü +Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? = Ðàçìåð âûáðàííîãî è áóôåðà îáìåíà íå ñîîòâåòñòâóåò. Âñòàâèòü â ëþáîì ñëó÷àå? +Tillåt direktanmälan = Ðàçðåøèòü áûñòðóþ çàÿâêó +Tillåt valutauttryck med decimaler = Ðàçðåøèòü äåíåæíûå âûðàæåíèÿ ñ äåñÿòè÷íûìè +Tillåt samma bana inom basintervall = Ðàçðåøèòü ñòàðò îäèíàêîâûõ äèñòàíöèé íà îäíîé ìèíóòå +Sidbrytning mellan klasser = Ðàçðûâ ñòðàíèöû +Sidbrytning mellan klasser / klubbar = Ðàçðûâ ñòðàíèöû ìåæäó ãðóïïàìè / êëóáàìè +Vak. ranking = Ðàíã ðåçåðâ. ìåñò +Skriv ut nu = Ðàñïå÷àòàòü ñåé÷àñ +Bantilldelning = Ðàñïðåäåëåíèå äèñòàíöèé +Bantilldelningslista - %s = Ðàñïðåäåëåíèå äèñòàíöèé - %s +Bantilldelning, individuell = Ðàñïðåäåëåíèå äèñòàíöèé, ëè÷íûé +Bantilldelning, stafett = Ðàñïðåäåëåíèå äèñòàíöèé, ýñòàôåòà +Utökat protokoll = Ðàñøèðåííûé ïðîòîêîë +Listpost = Ðåäàêòèðîâàíèå ïðîòîêîëà +Tid = Ðåç-ò +Tid in = Ðåç-ò â ïîñë. ñòàäèè +Vakant = Ðåçåðâ +Vakanser och efteranmälda = Ðåçåðâ è îïîçäàâøèå ó÷àñòíèêè +Det går endast att sätta in vakanser på sträcka 1 = Ðåçåðâ ìîæíî äîáàâèòü òîëüêî â ïåðâûé ýòàï +Andel vakanser = Ðåçåðâ. ìåñòà +Vakanser = Ðåçåðâ. ìåñòà +Tillsatte vakans = Ðåçåðâíîå ìåñòî çàïîëíåíî +Vakanser stöds ej i stafett = Ðåçåðâíûå ìåñòà íå ïîääåðæèâàþòñÿ â ýñòàôåòàõ +Totaltid = Ðåçóëüòàò +Resultat efter klass och bana - X = Ðåçóëüòàò ãðóïïû è äèñòàíöèè - X +Resultat lopp X - Y = Ðåçóëüòàò çàáåãà X - Y +Tid: X, nuvarande placering Y/Z = Ðåçóëüòàò: X, òåêóùåå ìåñòî Y/Z +Resultatlista – inställningar = Ðåçóëüòàòû – íàñòðîéêè +Resultat banvis per klass = Ðåçóëüòàòû äèñòàíöèè â ãðóïïå +Individuell resultatlista, alla lopp = Ðåçóëüòàòû ëè÷íûå, âñå ýòàïû +Individuell resultatlista, sammanställning av flera lopp = Ðåçóëüòàòû ëè÷íûå, ñóììà +Individuell resultatlista, visst lopp (STOR) = Ðåçóëüòàòû ëè÷íûå, ýòàï (áîëüø.) +Klubbresultat = Ðåçóëüòàòû íà êëóá +Klubbresultatlista = Ðåçóëüòàòû íà êëóá +Resultat per bana - X = Ðåçóëüòàòû ïî äèñòàíöèè - X +Rogaining, individuell = Ðåçóëüòàòû ðîãåéíà, ëè÷íûå +Individuell resultatlista, visst lopp = Ðåçóëüòàòû ýòàïà +Avgörande händelser = Ðåøàþùèå ñîáûòèÿ +Manuell lottning = Ðó÷íàÿ æåðåáü¸âêà +Jag sköter lottning själv = Ðó÷íàÿ æåðåáü¸âêà +Med sträcktidsanalys = Ñ àíàëèçîì ñïëèòîâ +Från kontroll = Ñ ÊÏ +FilterResult = Ñ ðåçóëüòàòîì +FilterHasCard = Ñ ÷èïîì +Hämtar information om = Ñáîð èíôîðìàöèè î +Fria starttider = Ñâîáîäíûé ñòàðò +Server = Ñåðâåð +serverbackup = ñåðâåð ñîõðàíÿåò äàííûå +Server: [X] Y = Ñåðâåð: [X] Y +Simulera inläsning av stämplar = Ñèìóëÿöèÿ ñ÷èòûâàíèÿ +Synkronisera med Eventor = Ñèíõðîíèçàöèÿ ñ Eventor +väntas till X om någon minut = ñêîðî ïîÿâèòñÿ íà X +Skript = Ñêðèïò +Följande deltagare är nyanmälda = Ñëåäóþùèå ó÷àñòíèêè áûëè çàÿâëåíû +Följande deltagare överfördes ej = Ñëåäóþùèå ó÷àñòíèêè áûëè ïðîèãíîðèðîâàíû +Följande deltagare har tilldelats en vakant plats = Ñëåäóþùèå ó÷àñòíèêè çàíÿëè ðåçåðâíûå ìåñòà +Följande deltagare deltar ej = Ñëåäóþùèå ó÷àñòíèêè íå ïðèíèìàþò ó÷àñòèå +Följande deltagare är anmälda till nästa etapp men inte denna = Ñëåäþùèå ó÷àñòíèêè çàðåãèñòðèðîâàíû â ñëåäóþùåé ñòàäèè, íî íå â ýòîé +help:10000 = Ñëóæáû â MeOS ïîçâîëÿþò àâòîìàòèçèðîâàòü íåêîòîðûå äåéñòâèÿ â ñëó÷àå îáíîâëåíèÿ äàííûõ â ïðîòîêîëå +Seedad lottning = Ñëó÷àéíàÿ æåðåáü¸âêà +Lottning = Ñëó÷àéíàÿ æåðåáü¸âêà +Lyssna = Ñëóøàòü +Skapad av = Ñîçäàíî â +Skapar saknad klass = Ñîçäàòü ãðóïïó èç ÷èïà +Skapa generell lista = Ñîçäàòü èòîãîâûé ïðîòîêîë +help:duplicate = Ñîçäàòü ëîêàëüíóþ êîïèþ ñîðåâíîâàíèé +Skapa en ny, tom, tävling = Ñîçäàòü íîâûå ñîðåâíîâàíèÿ +Skapa en ny tävling med data från Eventor = Ñîçäàòü íîâûå ñîðåâíîâàíèÿ çàãðóçèâ äàííûå ñ Eventor'a +Skapa listan = Ñîçäàòü ïðîòîêîë +Skapa fakturor = Ñîçäàòü ñ÷åòà +COM-Port = ÑÎÌ-ïîðò +ask:overwrite_server = Ñîðåâíîâàíèÿ óæå ñóùåñòâóþò íà ñåðâåðå. Îáíîâèòü ñîðåâíîâàíèÿ íà ñåðâåðå? +CmpDate = Ñîðåâíîâàíèÿ: äàòà +CmpName = Ñîðåâíîâàíèÿ: íàçâàíèå +Sortering: %s, antal rader: %d = Ñîðòèðîâêà: %s, êîë-âî ñòðîê: %d +Medlöpare = Ñîó÷àñòíèê +Sparade listval = Ñîõðàí¸ííûå ïðîòîêîëû +backup = ñîõðàíèòü +Spara sträcktider till en fil för automatisk synkronisering med WinSplits = Ñîõðàíèòü ñïëèòû äëÿ àâòîìàòè÷åñêîé ñèíõðîíèçàöèè ñ WinSplits +Säkerhetskopiera = Ñîõðàíèòü/ Ñîõðàíèòü êàê +help:14343 = Ñïèñîê ñ÷èòàííûõ ÷èïîâ. Äëÿ ïðèñâîåíèÿ äðóãîãî ÷èïà äðóãîìó ó÷àñòíèêó êëèêíèòå äâàæäû ïî íîìåðó ÷èïà +tooltip:inforest = Ñïèñîê ó÷àñòíèêîâ â ëåñó è íåñòàðòîâàâøèõ +Sträcktider = Ñïëèòû +Sträcktider (WinSplits) = Ñïëèòû (WinSplits) +Sträcktider / WinSplits = Ñïëèòû / WinSplits +Sträcktider/WinSplits = Ñïëèòû / WinSplits +MediumFont = Ñðåäíèé øðèôò +Sista betalningsdatum = Ñðîê îïëàòû +går upp i delad ledning vid X med tiden Y = ñòàë ëèäåðîì â X ñ ðåçóëüòàòîì Y +går upp i delad ledning med tiden X = ñòàíîâèòüñÿ ëèäåðîì ñ ðåçóëüòàòîì X +ClassStartName = Ñòàðò +Starta = Ñòàðò +Startnamn = Ñòàðò +starten (X) = ñòàðò (X) +Starttid (HH:MM:SS) = Ñòàðò (××:ÌÌ:ÑÑ) +Starttid = Ñòàðò â +Första omstartstid = Ñòàðò îñòàâø. +Omstartstid = Ñòàðò îñòàâø. +Första start = Ñòàðò ïåðâîãî +Första ordinarie starttid = Ñòàðò ïåðâîãî ó÷àñòíèêà +Första starttid = Ñòàðò ïåðâîãî ó÷àñòíèêà +Första (ordinarie) start = Ñòàðò ïåðâûõ ó÷àñòíèêîâ +Starttid: X = Ñòàðò: X +Ekonomisk sammanställning = Ñòàðò. âçíîñû, ñâîäíûé +Startintervall = Ñòàðò. èíòåðâàë +Startintervall (min) = Ñòàðò. èíòåðâàë (ìèí.) +har startat = ñòàðòîâàë +Starttiden är upptagen = Ñòàðòîâîå âðåìÿ íåäîñòóïíî +Startlistor = Ñòàðòîâûå ïðîòîêîëû +ask:changedclassfee = Ñòàðòîâûé âçíîñ áûë èçìåíåí â íåêîòîðûõ ãðóïïàõ. Âû õîòèòå, ïðèìåíèòü íîâûå ðàçìåðû ñòàðòîâîãî âçíîñà íà ñóùåñòâóþùèõ ó÷àñòíèêîâ â ýòèõ ãðóïïàõ?\n\nÂÍÈÌÀÍÈÅ: Íàçíà÷åííûå âðó÷íóþ ðàçìåðû ñòàðòîâûõ âçíîñîâ áóäóò ïåðåçàïèñàíû +Startnummer = Ñòàðòîâûé íîìåð +Startlista - %s = Ñòàðòîâûé ïðîòîêîë - %s +Startlista - X = Ñòàðòîâûé ïðîòîêîë - X +Startlista %%s - sträcka %d = Ñòàðòîâûé ïðîòîêîë %%s - Ýòàï %d +Startlista ett visst lopp = Ñòàðòîâûé ïðîòîêîë çàáåãà +Startlista lopp X - Y = Ñòàðòîâûé ïðîòîêîë çàáåãà X - Y +Klubbstartlista - %s = Ñòàðòîâûé ïðîòîêîë êëóáà - %s +Startlista, stafett (lag) = Ñòàðòîâûé ïðîòîêîë, ýñòàôåòà (êîìàíäû) +Startlista, stafett (sträcka) = Ñòàðòîâûé ïðîòîêîë, ýñòàôåòà (ýòàïû) +Individuell startlista, visst lopp = Ñòàðòîâûé ïðîòîêîë, ýòàï +Startlista, individuell = Ñòàðòîâûé, ëè÷íûé +Startlista, patrull = Ñòàðòîâûé, ïàòðóëü +Status = Ñòàòóñ +Status in = Ñòàòóñ ââîäà +Status matchar inte deltagarnas status = Ñòàòóñ íå ñîâïàäàåò ñî ñòàòóñîì ó÷àñòíèêà. +Status matchar inte data i löparbrickan = Ñòàòóñ íå ñîîòâåòñòâóåò äàííûì â ÷èïå +String = Ñòðîêà +Strukturerat webbdokument (html) = Ñòðóêòóðèðîâàííàÿ web-ñòðàíèöà (html) +Strukturerat exportformat = Ñòðóêòóðèðîâàííûõ ôîðìàò ýêñïîðòà +Totalt = Ñóììà +Summera = Ñóììàðíûé +help:computer_voice = Ñ÷èòàííûå îòìåòêè ïðîâåðÿþòñÿ è ïðîèãðûâàåòñÿ ôàéë , ãäå N ñòàðòîâûé íîìåð. Ôàéëû íàõîäÿòñÿ â ñëåäóþùåé ïàïêå. Åñëè ó÷àñòíèê / êîìàíäà ïðèíàäëåæèò èìååò íàöèîíàëüíîñòè NAT, MEOS ñíà÷àëà ïûòàåòñÿ âîñïðîèçâåñòè ôàéë , êîòîðûé äîëæåí ñîäåðæàòü íîìåð â ñîîòâåòñòâóþùåì ÿçûêîâîé âåðñèè. +Egen text = Òåêñò +Text = Òåêñò +Text: X = Òåêñò: X +Textfiler = Òåêñòîâûé ôàéë +Nuvarande innehavare: X = Òåêóùèé âëàäåëåö: X +Telefon = Òåëåôîí +Test = Òåñò +Test av stämplingsinläsningar = Òåñò îòìåòêè +Typ = Òèï +Typ av lista = Òèï ïðîòîêîëà +Typ av delning = Òèï ðàçäåëåíèÿ +Starttyp = Òèï ñòàðòà +Typ av export = Òèï ýêñïîðòà +Sträcktyp = Òèï ýòàïà +Träning = Òðåíèðîâêà +Följande deltagare har bytt klass = Ó ñëåäóþùèõ ó÷àñòíèêîâ èçìåíèëàñü ãðóïïà +Tävlingen måste ha ett namn = Ó ñîðåâíîâàíèé äîëæíî áûòü íàçâàíèå +Ta bort = Óäàëèòü +Ta bort / slå ihop = Óäàëèòü / Îáúåäèíèòü +Ta bort markerad = Óäàëèòü âûáðàííîå +Ta bort valda rader från tabellen (X) = Óäàëèòü âûáðàííûå ñòðîêè èç òàáëèöû (X) +Ta bort stämpling = Óäàëèòü îòìåòêó +Radera vakanser = Óäàëèòü ðåçåðâ +ask:firstasstart = Óæå èìåþòñÿ ó÷àñòíèêè ñ ðåçóëüòàòîì ýòîé äèñòàíöèè. Åñëè âû õîòèòå èñïîëüçîâàòü ïåðâóþ îòìåòêó êàê ñòàðò, òî ñòàðòîâûå âðåìåíà áóäóò ïåðåïèñàíû.\n\nÏðîäîëæèòü? +help:9373 = Óêàæèòå 1 èëè áîëüøå íîìåðîâ ÊÏ äëÿ ýòîãî ïóíêòà.\nÍàïðèìåð: 31, 32, 33. +help_autodraw = Óêàæèòå âðåìÿ ñòàðòà ïåðâîãî ó÷àñòíèêà, ñòàðòîâûé èíòåðâàë è êîëè÷åñòâî ðåçåðâíûõ ìåñò. Òàê æå âû ìîæåòå âûáðàòü ìåòîä ñîðòèðîâêè è ìåñòî â ïðîòîêîëå ó÷àñòíèêîâ ñ îïîçäàâøåé çàÿâêîé (â íà÷àëå èëè êîíöå ïðîòîêîëà). Âðåìÿ ñòàðò ïåðâîãî ó÷àñòíèêà äîëæíî áûòü áîëüøå ñóäåéñêîãî íóëÿ ñîðåâíîâàíèé.\n\nÅñëè âû êëèêíèòå <Àâòîìàòè÷åñêàÿ ñîðòèðîâêà>, MeOS ïðîâåðèò âñå ãðóïïû è åñëè â ãðóïïå íåò æåðåáü¸âêè, òî îíà áóäåò ïðîâåäåíà.\n\nMeOS ïîçâîëÿåò íå çàïóñêàòü íà îäíîé ìèíóòå ó÷àñòíèêîâ ó êîòîðûõ ñîâïàäàþò íåñêîëüêî ïåðâûõ ïóíêòîâ, à òàêæå îñòàâëÿòü îïðåäåë¸ííîå êîëè÷åñòâî ðåçåðâíûõ ìåñò â ïðîòîêîëå. Äëÿ áîëåå òî÷íîãî ðàñïðåäåëåíèÿ ñòàðòîâîãî ïðîòîêîëà íàæìèòå <Ðó÷íàÿ æåðåáü¸âêà> +help:12662 = Óêàæèòå ïîðÿäîê ïðîõîæäåíèÿ äèñòàíöèè, äîáàâèâ ïîñëåäîâàòåëüíîñòü íîìåðîâ ÊÏ. Ïðèìåð: 31, 50, 36, 50, 37, 100. +Ànge om kontrollen fungerar och hur den ska användas = Óêàæèòå ñïîñîá èñïîëüçîâàíèÿ ÊÏ +Hantera brickor = Óïðàâëåíèå ÷èïàìè +Hantera klubbar och ekonomi = Óïðàâëåíèå êëóáàìè è âçíîñàìè +Hantera jaktstart = Óïðàâëåíèå ïåðñüþòîì +Hantera löparbrickor = Óïðàâëåíèå ÷èïàìè ó÷àñòíèêîâ +Motion = Óïðàæíåíèÿ +help:31661 = Óñòàíîâèòå âðåìÿ çàêðûòèÿ ñòàðòà. Ïîñëå çàêðûòèÿ ñòàðòà ïåðåäà÷à ýñòàôåòû çàêðûâàåòñÿ è íåñòàðòîâàâøèì ó÷àñòíèêàì ìîæíî ïðèñâîèòü íîâîå âðåìÿ ñòàðòà.  ñëó÷àå åñëè íàäî ïðèñâîèòü ðàçëè÷íûå âðåìåíà ðàçëè÷íûì ýòàïàì, òî ïîëüçóéòåñü ñòàíäàðòíûì îêíîì íàñòðîéêè ãðóïï +Sätt okända löpare utan registrering till = Óñòàíîâèòü ñòàòóñ äëÿ ó÷àñòíèêîâ áåç ðåãèñòðàöèè +Installera = Óñòàíîâêà +handskakning = óñòàíîâëåíà +Runner = Ó÷àñòíèê +Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = Ó÷àñòíèê 'X' â ïàòðóëüíîé ãðóïïå 'Y', íî áåç ïàðòí¸ðà. Ðåçóëüòàòû ýòîé ãðóïïû ìîãóò áûòü íåâåðíûìè +Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = Ó÷àñòíèê 'X' â ýñòàôåòíîé ãðóïïå 'Y', íî áåç êîìàíäû. Ðåçóëüòàòû ýòîé ãðóïïû ìîãóò áûòü íåâåðíûìè +Deltagare %d = Ó÷àñòíèê %d +TeamRunner = Ó÷àñòíèê êîìàíäû +Löparen hittades inte = Ó÷àñòíèê íå íàéäåí +RunnerCard = Ó÷àñòíèê: SI-÷èï +RunnerTimePlaceFixed = Ó÷àñòíèê: Time when Competitor's place is set +RunnerUMMasterPoint = Ó÷àñòíèê: Uppsala möte, master points +Löpare: X, kontroll: Y, kl Z = Ó÷àñòíèê: X, ÊÏ: Y, Ðåçóëüòàò: Z +RunnerFee = Ó÷àñòíèê: âçíîñ +RunnerAge = Ó÷àñòíèê: âîçðàñò +RunnerBirthYear = Ó÷àñòíèê: ãîä ðîæä. +RunnerCourse = Ó÷àñòíèê: äèñòàíöèÿ +RunnerPlaceDiff = Ó÷àñòíèê: èçìåíåíèå ìåñòà +RunnerTimeAfterDiff = Ó÷àñòíèê: èçìåíåíèå îòñòàâàíèÿ +RunnerGivenName = Ó÷àñòíèê: èìÿ +RunnerTotalPlace = Ó÷àñòíèê: èòîã. ìåñòî +RunnerTotalTimeAfter = Ó÷àñòíèê: èòîã. îòñòàâàíèå +RunnerTotalTime = Ó÷àñòíèê: èòîã. ðåçóëüòàò +RunnerTotalTimeStatus = Ó÷àñòíèê: èòîã. ðåçóëüòàò / ñòàòóñ +RunnerClub = Ó÷àñòíèê: êëóá +RunnerPlace = Ó÷àñòíèê: ìåñòî +RunnerClassCoursePlace = Ó÷àñòíèê: ìåñòî íà äèñò. +RunnerBib = Ó÷àñòíèê: íîìåð +RunnerLegNumberAlpha = Ó÷àñòíèê: íîìåð ýòàïà +RunnerClassCourseTimeAfter = Ó÷àñòíèê: îòñò. íà äèñò. +RunnerTimeAfter = Ó÷àñòíèê: îòñòàâàíèå +RunnerTempTimeAfter = Ó÷àñòíèê: îòñòàâàíèå íà âûáð. ÊÏ +RunnerRogainingPoint = Ó÷àñòíèê: î÷êè ðîãåéíà +RunnerSex = Ó÷àñòíèê: ïîë +RunnerCompleteName = Ó÷àñòíèê: ïîëíîå èìÿ +RunnerTimeLost = Ó÷àñòíèê: ïîòåðè âðåìåíè +RunnerRank = Ó÷àñòíèê: ðàíã +RunnerTempTimeStatus = Ó÷àñòíèê: ðåç-ò / ñòàòóñ íà âûáð. ÊÏ +RunnerTime = Ó÷àñòíèê: ðåçóëüòàò +RunnerTimeStatus = Ó÷àñòíèê: ðåçóëüòàò / ñòàòóñ +RunnerTimePerKM = Ó÷àñòíèê: ñêîðîñòü ìèí/êì +PunchNamedTime = Ó÷àñòíèê: ñïëèò ñ íàçâ. +PunchTime = Ó÷àñòíèê: ñïëèòû +RogainingPunch = Ó÷àñòíèê: ñïëèòû ðîãåéíà +RunnerStart = Ó÷àñòíèê: ñòàðò. âðåìÿ +RunnerStartNo = Ó÷àñòíèê: ñòàðò. íîìåð +RunnerNationality = Ó÷àñòíèê: ñòðàíà +RunnerPhone = Ó÷àñòíèê: òåëåôîí +RunnerFamilyName = Ó÷àñòíèê: ôàìèëèÿ +RunnerName = Ó÷àñòíèê: ôàìèëèÿ èìÿ +RunnerFinish = Ó÷àñòíèê: ôèíèø +Löpare, Status Okänd, med registrering (kvar-i-skogen) = Ó÷àñòíèêè ñ íåèçâåñòíûì ñòàòóñîì è ðåãèñòðàöèåé (â ëåñó) +Löpare, Ej Start, med registrering (kvar-i-skogen!?) = Ó÷àñòíèêè ñ ðåãèñòðàöèåé è ñòàòóñîì DNS (â ëåñó èëè ñîøëè!?) +Löpare, Status Okänd, som saknar registrering = Ó÷àñòíèêè ñ íåèçâåñòíûì ñòàòóñîì è áåç ðåãèñòðàöèè +Semikolonseparerad (csv) = Ôàéë CSV (csv) +Urval = Ôèëüòð +målet (X) = ôèíèø (X) +målet = ôèíèøå +går i mål på X plats med tiden Y = ôèíèøèðîâàë X ñ ðåçóëüòàòîì Y +går i mål på X plats, efter Y, på tiden Z = ôèíèøèðîâàë X, çà Y, ñ ðåçóëüòàòîì Z +OE Semikolonseparerad (csv) = Ôîðìàò OE-csv (csv) +Val av export = Ôîðìàò ýêñïîðòà +Fördefinierade tävlingsformer = Ôîðìàòû ñîðåâíîâàíèé +Vill du skapa en ny klass? = Õîòèòå ñîçäàòü íîâóþ ãðóïïó? +Tidslinje – X = Õðîíîëîãèÿ – X +SI X inläst. Brickan tillhör Y som saknar klass = ×èï X áûë ñ÷èòàí. ×èï ïðèíàäëåæèò Y, ãðóïïà íå ïðèñâîåíà +ask:addpunches = ×èï íå áûë ñ÷èòàí ó ýòîãî ó÷àñòíèêà. Õîòèòå äîáàâèòü îòìåòêè âðó÷íóþ? +Läs brickor = ×òåíèå ÷èïîâ +MediumPlus = ×óòü áîëüøå ñðåäíåãî +Minutstartlista = Øàõìàòêà +SOFT-lottning = Øâåäñêèé àëãîðèòì +Typsnitt = Øðèôòû +Poängavdrag (per minut) = Øòðàô (çà ìèíóòó) +Tidsavdrag: X poäng = Øòðàô: X î÷êîâ +Poängavdrag per påbörjad minut = Øòðàôîâàòü çà íåïîëíóþ ìèíóòó +Avancerat = Ýêñïåðò +Elektronisk = Ýëåêòðîííàÿ +Elektronisk godkänd = Ýëåêòðîííàÿ âêëþ÷åíà +Tvåmannastafett = Ýñòàôåòà äëÿ äâîèõ +Extralöparstafett = Ýñòàôåòà ñ ñî-ó÷àñòíèêîì +Stafettklasser = Ýñòàôåòíûå ãðóïïû +help:winsplits_auto = Ýòà ñëóæáà ñîõðàíÿåò ñïëèòû â ôîðìàòå IOF (xml). Åñëè âû îòêðîåòå ïîëó÷åííûé ôàéë â WinSplits, òî ñïëèòû òàì áóäóò ñàìîñòîÿòåëüíî îáíîâëÿòüñÿ +Str. = Ýòàï +Sträcka = Ýòàï +Str. %d = Ýòàï %d +Sträcka %d = Ýòàï %d +sträcka X = Ýòàï X +Sträcka X = Ýòàï X +Sträcka att lotta = Ýòàï äëÿ æåðåáü¸âêè +help:simulate = Ýòîò ñåðâèñ ïîçâîëÿåò èìèòèðîâàòü ñ÷èòûâàíèå SI-÷èïîâ. Âðåìÿ è îòìåòêè ñîçäàþòñÿ äëÿ âñåõ ó÷àñòíèêîâ. Òàêæå ìîãóò áûòü ñìîäåëèðîâàíû îòìåòêè ðàäèî-ÊÏ.\n\n ÂÍÈÌÀÍÈÅ: Èñïîëüçóéòå äëÿ òåñòèðîâàíèÿ. + +(ledare) = (ëèäåð) +Antal hämtade uppdateringar X (Y kb) = Êîë-âî ïîëó÷åííûõ îáíîâëåíèé X (Y êá) +Antal skickade uppdateringar X (Y kb) = Êîë-âî îáíîâëåíèé X (Y êá) +Använd ROC-protokoll = Èñïîëüçîâàòü ROC ïðîòîêîë +Bana med slingor = Äèñòàíöèÿ ñ "áàáî÷êîé" +Egna textrader = Äîïîëíèòåëüíûå òåêñòîâûå ïîëÿ +Ekonomi = Óïðàâëåíèå ôèíàíñàìè +Centrera = Ïî öåíòðó +Hantera egna listor = Îòêðûòü øàáëîí +Första fakturanummer = Íîìåð ïåðâîãî ñ÷¸òà +Hantera klubbar = Óïðàâëåíèå êëóáàìè +Färg = Öâåò +Höger = Ïî ïðàâîìó êðàþ +Avmarkera 'X' för att hantera alla bricktildelningar samtidigt = Ñíèìèòå ãàëêó 'X' äëÿ óïðàâëåíèÿ àðåíäîâàííûìè ÷èïàìè íà ýòîé âêëàäêå +Radera alla klubbar = Óäàëèòü âñå êëóáû +Fakturanummer = Íîìåð ñ÷¸òà +PunchControlCode = Ñïëèò: Íîìåð ÊÏ +PunchControlNumber = Ñïëèò: Íîìåð îòìåòêè +PunchControlPlace = Ñïëèò: Ìåñòî (ïåðåãîí) +PunchControlPlaceAcc = Ñïëèò: Ìåñòî (èòîã) +PunchLostTime = Ñïëèò: Ïîòåðè íà ÊÏ +Inställningar sträcktidsutskrift = Íàñòðîéêà ïå÷àòè ñïëèòîâ +Formatering = Íàñòðîéêè îòîáðàæåíèÿ +Avgifter och valuta ställer du in under = Âçíîñû è íàñòðîéêè âàëþòû ìîæíî èçìåíèòü â ðàçäåëå +Exportera alla till PDF = Ýêñïîðò âñåõ â PDF +Exportformat = Ôîðìàò ýêñïîðòà +Online Results Error X = On-Line ðåçóëüòàòû. Îøèáêà X +Onlineinput = Óäàë¸ííûé ââîä +Onlineresultat = On-Line ðåçóëüòàòû +Ogiltig kontrollkod = Íåâåðíûé íîìåð ÊÏ +Online Input Error X = Óäàë¸ííûé ââîä. Îøèáêà X +Nummerlapp, lopp-id eller namn = Íîìåð, Id ñòàðòà èëè èìÿ +Filnamnsprefix = Ïðåôèêñ èìåíè ôàéëà +Spara på disk = Ñîõðàíèòü íà äèñê +Spara som PDF = Ñîõðàíèòü â PDF +Stämpling = Îòìåòêà +Textjustering = Âûðàâíèâàíèå +Tidsintervall (sekunder) = Ïåðèîä îáíîâëåíèé (ñåêóíäû) +Tävlingens ID-nummer = ID íîìåð ñîðåâíîâàíèé +URL = URL +URL måste anges = Íåâåðíî óêàçàí URL +Vänster = Ïî ëåâîìó êðàþ +min/km = ìèí/êì +Inmatning online = Óäàë¸ííûé ââîä +Koordinater (mm) för adressfält = Êîîðäèíàòû (â ìì) äëÿ ïîëÿ àäðåñà +Funktion = Ôóíêöèÿ +Knyt bricka / deltagare = Ïðèêðåïèòü ÷èï ê ó÷àñòíèêó +Kod = Íîìåð +Kontrollmappning = Íàçíà÷åíèå ÊÏ +Lopp-id = Id ñòàðòà +Mapp = Ïàïêà +Med km-tid = Äîáàâèòü òåìï (ìèí/êì) +Varvningskontroll = Îáùèé ÊÏ +Vill du ta bort 'X'? = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü 'X'? +Fakturainställningar = Íàñòðîéêè ñ÷åòîâ +Resultat online = On-Line ðåçóëüòàòû +classcourseresult = Ðåçóëüòàòû ãðóïïû è ïî äèñòàíöèè +Resultat vid målstämpling = Ðåçóëüòàòû ïî ôèíèøíîé îòìåòêå +Organisatör = Îðãàíèçàòîð +PDF = PDF +Packa stora filer (zip) = Óïàêîâûâàòü áîëüøèå ôàéëû â zip +Antal deltagare = Ó÷àñòíèêîâ +Besökare = Ïîñåòèòåëè +Föregående kontroll = Ïðåäûäóùèé ÊÏ +Förekomst = Êîë-âî íà äèñòàíöèè +Inga bommar registrerade = Îòìåòêà ÎÊ +Ja = Äà +Nej = Íåò +Bricknr = Íîìåð ÷èïà +Underlag saknas för bomanalys = Îòìåòêà íå ïðîâåðÿëàñü +Onlineservern svarade felaktigt = Óäàë¸ííûé ñåðâåð íå îòâå÷àåò (Íåâåðíûé íàñòðîéêè?) +Onlineservern svarade: Felaktigt lösenord = Ïîëó÷åí îòâåò îò ñåðâåðà: Íåâåðíûé ïàðîëü +Onlineservern svarade: Felaktigt tävlings-id = Ïîëó÷åí îòâåò îò ñåðâåðà: Íåâåðíûé id ñîðåâíîâàíèé +Onlineservern svarade: Serverfel = Ïîëó÷åí îòâåò îò ñåðâåðà: Îøèáêà ñåðâåðà +Onlineservern svarade: ZIP stöds ej = Ïîëó÷åí îòâåò îò ñåðâåðà: ZIP íå ïîääåðæèâàåòñÿ. +Installerbara listor = Âîçìîæíà óñòàíîâêà ïðîòîêîëîâ: +Mappnamnet får inte vara tomt = Èìÿ ïàïêè íå ìîæåò áûòü ïóñòûì +Radera permanent = Óäàëèòü íàâñåãäà +Redigera = Ðåäàêòèðîâàòü +Listor i tävlingen = Ïðîòîêîëû â òåêóùèõ ñîðåâíîâàíèÿõ +Knyt automatiskt efter inläsning = Íàçíà÷àòü àâòîìàòè÷åñêè ïîñëå ñ÷èòûâàíèÿ +Skriver sträcktider när tävlingsdata ändras = Çàïèñûâàòü ôàéë ïîñëå èçìåíåíèÿ ïðîòîêîëà ñîðåâíîâàíèé +På banan = Íà äèñòàíöèè +Tillgängliga listor = Äîñòóïíû ïðîòîêîëû +Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa = Âû äåéñòâèòåëüíî õîòèòå óäàëèòü âñå êëóáû è î÷èñòèòü ïîëå Êëóá ó ó÷àñòíèêîâ? +X har redan bricknummer Y. Vill du ändra det? = X óæå èìååò ÷èï íîìåð Y. Âû õîòèòå ñìåíèòü åãî? +Publicera resultat direkt på nätet = Ïóáëèêîâàòü ðåçóëüòàòû ñîðåâíîâàíèé â èíòåðíåò +En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning = Äèñòàíöèÿ ñ áàáî÷êîé ïîçâîëÿåò ïðîõîäèòü ïåòëè áàáî÷êè â ëþáîì ïîðÿäêå +Hämta stämplingar m.m. från nätet = Ñ÷èòûâàòü îòìåòêè èç Èíòåðíåòà. +Misslyckades med att ladda upp onlineresultat = Îøèáêà ïðè îòïðàâêå îíëàéí ðåçóëüòàòîâ +Skicka till webben = Ñëàòü â èíòåðíåò +Radera alla klubbar och ta bort klubbtillhörighet = Óäàëèòü âñå êëóáû è î÷èñòèòü ïîëå Êëóá ó ó÷àñòíèêîâ +Definierade mappningar = Îïðåäåë¸ííûå íàçíà÷åíèÿ +Ange om kontrollen fungerar och hur den ska användas = Óêàæèòå êàêèì îáðàçîì áóäåò èñïîëüçîâàòüñÿ ïóíêò +Exporterar om = Ýêñïîðò â +Filen finns redan: X = Ôàéë óæå ñóùåñòâóåò: X +Markera 'X' för att hantera deltagarna en och en = Îòìåòüòå 'X' äëÿ àâòîìàòè÷åñêîãî äîáàâëåíèÿ ó÷àñòíèêîâ +Stämpelkod = Íîìåð ÊÏ +Tid efter: X; har tagit in Y = Îòñòàâàíèå: X; îòûãðàë Y +Tid efter: X; har tappat Y = Îòñòàâàíèå: X; ïîòåðÿë Y +Tidpunkt = Ðåçóëüòàò +Slå ihop text med föregående = Îáúåäèíèòü ñ ïðåäûäóùèì +Okänd = Íåèçâåñòíûé +Ogiltig funktion = Íåâåðíàÿ ôóíêöèÿ +Skicka och ta emot snabb förhandsinformation om stämplingar och resultat = Îïòèìèçèðîâàòü îòïðàâêó è ïîëó÷åíèå èíôîðìàöèè îá îòìåòêàõ è ðåçóëüòàòàõ +Tidsförluster (kontroll-tid) = Time loss (control/time) +Till exempel X = Íàïðèìåð X +Tilldela nya fakturanummer till alla klubbar? = Ïðèñâîèòü íîâûå íîìåðà ñ÷åòîâ âñåì êëóáàì? +Överför nya deltagare i ej valda klasser med status "deltar ej" = Ïåðåíåñòè ó÷àñòíèêîâ â íîâûé ïðîòîêîë çà èñêëþ÷åíèåì èìåþùèõ ñòàòóñ "Íå ïðèíèìàåò ó÷àñòèå" +warn:notextended = Âíèìàíèå: Çàïðîãðàììèðóéòå óïðàâëÿþùóþ ñòàíöèþ ñ îïöèåé Extended protocol äëÿ ïîâûøåíèÿ ñêîðîñòè ñ÷èòûâàíèÿ äàííûõ. +help:onlineinput = Ñëóæáà èñïîëüçóåòñÿ äëÿ ïîëó÷åíèÿ îòìåòîê ñ ðàäèî ÊÏ ÷åðåç Èíòåðíåò. Ê ïðèìåðó ÊÏ ïîäêëþ÷åííûå ïîñðåäñòâîì GSM. Òàê æå åñòü âîçìîæíîñòü ââîäèòü ðåçóëüòàòû âðó÷íóþ ïîñðåäñòâîì ôîðìû íà ñàéòå.\n\nÒàê æå ïðîòîêîë ñëóæáû ïîääåðæèâàåò è äðóãèå ôóíêöèè, íàïðèìåð, çàÿâêè ó÷àñòíèêîâ, èçìåíåíèå ÷èïà...\n\nÅñëè âû õîòèòå ðàçðàáîòàòü ñîáñòâåííûé ñåðâèñ, òî ïîäðîáíîå îïèñàíèå ïðîòîêîëà ìîæíî íàéòè íà íàøåì ñàéòå: www.melin.nu/meos. +help:onlineresult = Ñëóæáà èñïîëüçóåòñÿ äëÿ àâòîìàòè÷åñêîé îòïðàâêè ðåçóëüòàòîâ è ñòàðòîâûõ ïðîòîêîëîâ â Èíòåðíåò.\n\nÅñëè âû õîòèòå ðàçðàáîòàòü ñîáñòâåííûé ñåðâèñ, òî ïîäðîáíîå îïèñàíèå ïðîòîêîëà ìîæíî íàéòè íà íàøåì ñàéòå: www.melin.nu/meos. +help:DirectResult = - If there is no course, the status is set to OK on finish punch.\n\n- If there is a course, radio punches are used as controls. No card readout is necessary. +DATABASE ERROR = Îøèáêà áàçû äàííûõ +Lyssnar pa X = Ïðîñóøèâàíèå X +Press Enter to continue = Íàæìèòå äëÿ ïðîäîëæåíèÿ +X (press Ctrl+Space to confirm) = X (íàæìèòå + äëÿ ïîäòâåðæäåíèÿ) +ask:overwriteresult = X óæå èìååò ðåçóëüòàò. Ïåðåïèñàòü åãî? +Brickan används av X = ×èï óæå ïðèñâîåí ó÷àñòíèêó X +Lyssnar på X = Îæèäàíèå ñîîáùåíèé ñ X +Failed to save pdf the specified file = Íåâîçìîæíî îòêðûòü óêàçàííûé PDF ôàéë +Portable Document Format (PDF) = Ôîðìàò PDF (PDF) +[Bort] = [Óäàëèòü] +Club and runner database = Áàçà êëóáîâ è ñïîðòñìåíîâ +Anmäl inga deltagare nu = Áåç ïðåäâàðèòåëüíûõ çàÿâîê +Banan saknar rogainingkontroller =  äèñòàíöèè íå îïðåäåëåíû ÊÏ äëÿ ðîãåéíà +Stämplingstid = Âðåìÿ îòìåòêè +Första tillåtna starttid = Âðåìÿ ñòàðòà ïåðâîãî ó÷àñòíèêà +Alla funktioner = Âñå îïöèè +ask:cleardb = Âû äåéñòâèòåëüíî õîòèòå î÷èñòèòü áàçó äàííûõ ó÷àñòíèêîâ è êëóáîâ? +newcmp:featuredesc = Âûáåðèòå êàêèå îïöèè MeOS âàì áóäóò íåîáõîäèìû â ýòèõ ñîðåâíîâàíèÿõ. Âû âîæåòå äîáàâëÿòü è óáèðàòü îïöèè â ëþáîå âðåìÿ íàæàâ <Íàñòðîéêè MeOS> íà ñòðàíèöå Ñîðåâíîâàíèÿ. +Välj vilka funktioner du vill använda = Âûáåðèòå îïöèè MeOS êîòîðûå âàì íåîáõîäèìû äëÿ äàííîãî ñòàðòà +Klassval = Âûáîð ãðóïï +Resultatuträkning = Âû÷èñëåíèå ðåçóëüòàòà +Status calculation for team = Âû÷èñëåíèå ñòàòóñà äëÿ êîìàíäû +Status calculation for runner = Âû÷èñëåíèå ñòàòóñà äëÿ ó÷àñòíèêà +Calculate and apply forking = Âû÷èñëèòü è ïðèìåíèòü ðàññåâ +Klassen X är individuell = Ãðóïïà X èíäèâèäóàëüíàÿ +Data from result module (X) = Äàííûå èç ìîäóëÿ (X) +Datum (för första start) = Äàòà (ïåðâîãî ñòàðòà) +Välj från lista = Äåòàëèçèðîâàííîå âûäåëåíèå +Gafflade banor = Äèñòàíöèè ñ ðàññåâîì +Underfilter = Äîïîëíèòåëüíûé ôèëüòð +Available symbols = Äîñòóïíûå çíà÷åíèÿ +Result module identifier = Èäåíòèôèêàòîð ìîäóëÿ +Importera anmälda = Èìïîðò çàÿâîê +Importera laguppställningar = Èìïîðò êîìàíä ïîñòðî÷íî +Individuellt, gafflat = Èíäèâèäóàëüíûå ñ ðàññåâîì +Individuell tävling = Èíäèâèäóàëüíûå ñîðåâíîâàíèÿ +Use initials in names = Èíèöèàëû â èìåíàõ +Använd endast en bana i klassen = Èñïîëüçîâàòü òîëüêî îäíó äèñòàíöèþ äëÿ ãðóïïû +Source code = Èñõîäíûé êîä +TeamRogainingPointTotal = Èòîãîâûå î÷êè êîìàíäû +Alla lopp som individuella = Êàæäûé çàáåã êàê èíäèâèäóàëüíûé +Clubs = Êëóáû +Teams and forking = Êîìàíäû è äèñòàíöèè +Poängjustering = Êîððåêòèðîâêà î÷êîâ +Result Modules = Ìîäóëè +Result Module – X = Ìîäóëü X +vid kontroll X = íà ÊÏ X +Bakåt = Íàçàä +Namn och tidpunkt = Íàçâàíèå è äàòà +Name of result module = Íàçâàíèå ìîäóëÿ +Tävlingens namn = Íàçâàíèå ñîðåâíîâàíèé +Assign courses and apply forking to X = Íàçíàæåíèå äèñòàíöèé è ïðèìåíåíèå ðàññåâà äëÿ X +Assign selected courses to selected legs = Íàçíà÷èòü âûáðàííûå äèñòàíöèè âûáðàííûì ýòàïàì +CustomSort = Íàñòðàèâàåìàÿ ñîðòèðîâêà +Forking setup = Íàñòðîéêà ðàññåâà +Funktioner i MeOS = Íàñòðîéêà MeOS +MeOS Features = Íàñòðîéêè MeOS +MeOS Funktioner = Íàñòðîéêè MeOS +Failed to read file = Íå ìîãó ïðî÷èòàòü ôàéë. +Okänd klass på rad X = Íåèçâåñòíàÿ ãðóïïà â ñòðîêå X +Several races for a runner = Íåñêîëüêî äèñòàíöèé äëÿ ó÷àñòíèêà +Several stages = Íåñêîëüêî ñòàäèé (äíåé) +Unfair control legs = Íåñïðàâåäëèâûé ðàññåâ íà ÊÏ +New Set of Result Rules = Íîâûé íàáîð ïðàâèë îáðàáîòêè ðåçóëüòàòîâ +Bibs = Íîìåðà +Description = Îïèñàíèå +Point calculation for team = Îïðåäåëåíèå î÷êîâ êîìàíäû +Point calculation for runner = Îïðåäåëåíèå î÷êîâ ó÷àñòíèêà +Time calculation for team = Îïðåäåëåíèå ðåçóëüòàòà êîìàíäû +Time calculation for runner = Îïðåäåëåíèå ðåçóëüòàòà ó÷àñòíèêà +Define forking = Îïðåäåëèòü ðàññåâ +General = Îñíîâíûå +Endast grundläggande = Îñíîâíûå íàñòðîéêè +Open a Copy = Îòêðûòü êàê êîïèþ +Cancel = Îòìåíà +Track runners in forest = Îòñëåæèâàíèå íåôèíèøèðîâàâøèõ +Töm databasen = Î÷èñòèòü áàçó äàííûõ +Clear selections = Î÷èñòèòü âûäåëåíèå +Clear Memory = Î÷èñòèòü ïàìÿòü +Patrols = Ïàòðóëè +TimingFrom = Ïåðâûé ÊÏ +FinishTimeReverse = Ïåðåâåíóòü ôèíèøíûå âðåìåíÿ (ïîñëåäíèå ñíà÷àëà) +Växel = Ïåðåäà÷à +Print Card Data = Ïå÷àòü äàííûõ +Print card data = Ïå÷àòü äàííûõ +Prepare start lists = Ïîäãîòîâêà ñòàðòîâûõ ïðîòîêîëîâ +Support time to control = Ïîääåðæêà âðåìåíè äî ÊÏ +Support time from control = Ïîääåðæêà âðåìåíè îò ÊÏ +Result score calculation for team = Ïîäñ÷¸ò èòîãîâûõ î÷êîâ êîìàíäû +Result score calculation for runner = Ïîäñ÷¸ò èòîãîâûõ î÷êîâ ñïîðòñìåíà +info:runnerdbonline = Ïîêà âû ïîäêëþ÷åíû ê ñåðâåðó, âû íå ìîæåòå ðåäàêòèðîâàòü áàçó ñïîðòñìåíîâ è êëóáîâ âðó÷íóþ. Äåëàéòå âñå èçìåíåíèÿ äî çàãðóçêè ñîðåâíîâàíèé íà ñåðâåð. Òàæå âîçìîæíî çàìåíèòü ñóùåñòâóþùèå ñîðåâíîâàíèÿ íà ñåðâåðå ïóò¸ì èìïîðòà íîâîé áàçû (èç IOF XML). +Show forking = Ïîêàçàòü ðàññåèâàíèå +TimingTo = Ïîñëåäíèé ÊÏ +Regler för resultatuträkning - X = Ïðàâèëà äëÿ âû÷èñëåíèÿ ðåçóëüòàòîâ - X +FilterPrelResult = Ïðåä. Ðåçóëüòàò +Applying rules to the current competition = Ïðèìåíåíèå ïðàâèëÿ äëÿ òåêóùèõ ñîðåâíîâàíèé +Test Result Module = Ïðîâåðèòü ìîäóëü +Several MeOS Clients in a network = Ðàáîòà ïî ñåòè +Unroll split times for loop courses = Ðàçâîðà÷èâàòü ñïëèòû äëÿ äèñòàíöèé ñ ïåòëÿìè +The forking is not fair = Ðàññåâ — íåñïðàâåäëèâûé +The forking is fair = Ðàññåâ — ñïðàâåäëèâûé +Forked individual courses = Ðàññåâ â èíäèâèäóàëüíûõ äèñòàíöèÿõ +Forkings for X = Ðàññåâ äëÿ X +Forkings = Ðàññåâû +Edit Clubs = Ðåäàêòèðîâàíèå êëóáîâ +Edit Result Modules = Ðåäàêòèðîâàíèå ìîäóëåé +Edit rule for = Ðåäàêòèðîâàíèå ïðàâèëà äëÿ +Vacancies and entry cancellations = Ðåçåðâ è îòìåíà çàÿâîê +Time: X = Ðåçóëüòàò: X +Manual point reductions and adjustments = Ðó÷íîé ââîä è êîððåêòèðîâêà î÷êîâ +Manual time penalties and adjustments = Ðó÷íîé ââîä è êîððåêòèðîâêà øòðàôîâ +Brickhantering = Ñîäåðæèìîå ÷èïà +Skapar tävling = Ñîçäàíèå ñîðåâíîâàíèé +Created X distinct forkings using Y courses = Ñîçäàíî X ðàçëè÷íûõ ðàññåâîâ èñïîëüçóÿ Y äèñòàíöèé +New Result Module = Ñîçäàòü íîâûé ìîäóëü +Skapa = Ñîçäàòü íîâûé ìîäóëü +Create Competition = Ñîçäàòü ñîðåâíîâàíèÿ +Skapa tävlingen = Ñîçäàòü ñîðåâíîâàíèÿ +Tävlingen måste avgöras mellan X och Y = Ñîðåâíîâàíèé äîëæíû ïðîéòè â èíòåðâàëå ìåæäó X è Y +Tävling med lag = Ñîðåâíîâàíèÿ ñ êîìàíäàìè +Save = Ñîõðàíèòü +Save changes = Ñîõðàíèòü èçìåíåíèÿ +Standard = Ñòàíäàðò +Start: X = Ñòàðò: X +Economy and fees = Ñòàðòîâûå âçíîñû +RunnerRogainingPointTotal = Ñóììà î÷êîâ ó÷àñòíèêà +ResultDescription = Òèï ðåçóëüòàòà +Exporttyp = Òèï ýêñïîðòà +Löpare per klass = Ó÷àñòíèêè ïî ãðóïïàì +Använd befintliga deltagare = Ó÷àñòíèêè óæå åñòü â äàííûõ ñîðåâíîâàíèÿõ +Målfil = Ôàéë íàçíà÷åíèÿ +Exportera till fil = Ýêñïîðò â ôàéë +Exportera klubbar (IOF-XML) = Ýêñïîðò êëóáîâ (IOF-XML) +Exportval, IOF-XML = Ýêñïîðò íàñòðîåê, IOF-XML +Exportera personer (IOF-XML) = Ýêñïîðò ñïîðòñìåíîâ (IOF-XML) +Exportera startlista = Ýêñïîðò ñòàðòîâîãî ïðîòîêîëà +Exportera individuella lopp istället för lag = Ýêñïîðòèðîâàòü êàê èíäèâèäóàëüíóþ ãîíêó íåñìîòðÿ íà êîìàíäû +Relays = Ýñòàôåòû +help:analyzecard = Ýòà ôóíêöèÿ ïîçâîëÿåò ïå÷àòàòü ñîäåðæèìîå ÷èïîâ áåç êàêèõ-ëèáî ñîðåâíîâàíèé, ïðîñòî êàê ïå÷àòàþùàÿ ñòàíöèÿ. Íàæìèòå Ïå÷àòü ñïëèòîâ è íàñòðîéòå ïðèíòåð.\n\n Ñ÷èòàííûå ÷èïû ñîõðàíÿòñÿ â ïàìÿòè (íî íå â ñîðåâíîâàíèÿõ). Âû ìîæåòå ðåäàêòèðîâàòü èìÿ è êëóá ñ÷èòàííûõ èç ÷èïà. Òàêæå âû ìîæåòå ñîõðàíèòü äàííûå â ôàéë èëè ñîçäàòü íîâûå ñîðåâíîâàíèÿ íà îñíîâå äàííûõ â ÷èïå. Çàïîìíèòå, âû äîëæíû çàêðûòü òåêóùèå ñîðåâíîâàíèÿ ÷òîáû ïîëó÷èòü äîñòóï ê äàííîé ôóíêöèè. +Leg X = Ýòàï X +Leg X: Use Y = Ýòàï X: Èñïîëüçóåò Y +Leg X: Do not modify = Ýòàï X: Íå èçìåíÿëñÿ +Legs = Ýòàïû +Gruppera = Ãðóïïèðîâêà +Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka) = Ñãðóïïèðîâàòü óæå ñóùåñòâóþùèõ ó÷àñòíèêîâ â êîìàíäó (èäåíòèôèêàöèÿ ïî èìåíè è/èëè íîìåðó ÷èïà) +help:teamlineup = Çäåñü âû ìîæåòå èìïîðòèðîâàòü ðàññòàíîâêó êîìàíä èç òåêñòîâîãî ôàéëà, êîòîðûé ëåãêî ñîçäàòü â ëþáîì ðåäàêòîðå òàáëèö. Ôàéë äîëæåí áûòü ñëåäóþùåãî ôîðìàòà:\n\nÃðóïïà;Íàçâàíèå êîìàíäû;[Êëóá]\nÓ÷àñòíèê 1;[×èï];[Êëóá];[Äèñòàíöèÿ];[Ãðóïïà ó÷àñòíèêà]\nÓ÷àñòíèê 2;[×èï];[Êëóá];[Äèñòíöèÿ];[Ãðóïïà ó÷àñòíèêà]\n...\nÃðóïïà;Íàçâàíèå êîìàíäû;[Êëóá]\n...\n\nÏîëÿ îòìå÷åííûå [] ìîæíî íå óêàçûâàòü. Âíèìàíèå, óêàçàííûå ãðóïïû è äèñòàíöèè äîëæíû ñóùåñòâîâàòü è êîëè÷åñòâî ýòàïîâ â ãðóïïå äîëæíî ñîîòâåòñòâîâàòü êîëè÷åñòâó ó÷àñòíèêîâ â êîìàíäå. Åñëè ó÷àñòíèêà íåò, òî ìîæíî âñòàâèòü ïóñòóþ ñòðîêó. Îïöèÿ <Ó÷àñòíèêè óæå åñòü â äàííûõ ñîðåâíîâàíèÿõ> çíà÷èò ÷òî åñòü òåêóùåé áàçå è îíè áóäóò ïåðåìåùåíû â óêàçàííûå êîìàíäû, îñòàëüíûå ó÷àñòíèêè èãíîðèðóþòñÿ. +HTML med AutoRefresh = HTML ñ àâòîîáíîâëåíèåì +Ogiltigt lag på rad X = Íåâåðíàÿ êîìàíäà â ñòðîêå X +IOF Klubbdatabas, version 3.0 (xml) = IOF ñïèñîê îðãàíèçàöèé, version 3.0 (xml) +IOF Löpardatabas, version 3.0 (xml) = IOF ñïèñîê ñïîðòñìåíîâ, version 3.0 (xml) +IOF Startlista, version 2.0.3 (xml) = IOF ñòàðòîâûé ïðîòîêîë, version 2.0.3 (xml) +IOF Startlista, version 3.0 (xml) = IOF ñòàðòîâûé ïðîòîêîë, version 3.0 (xml) +MeOS – Funktioner = MeOS – Íàñòðîéêè +Klassen saknas = Ïðîïóùåííàÿ ãðóïïà +Banan saknas = Ïðîïóùåííàÿ äèñòàíöèÿ +Regler för resultatuträkning = Regler för resultatuträkning +Result Calculation = Âû÷èñëåíèå ðåçóëüòàòà +Spara laguppställningar = Ñîõðàíèòü ðàññòàíîâêó êîìàíä +Spara tid = Ñîçðàíèòü ðåçóëüòàò +Laguppställning = Ðàññòàíîâêà êîìàíä +Banans kontroller ger för få poäng för att täcka poängkravet = Î÷êîâ íà âñåõ ÊÏ íåäîñòàòî÷íî äëÿ óäîâëåòðîðåíèÿ òðåáîâàíèÿì +help:assignforking = Ýòà ôóíêöèÿ âû÷èñëÿåò îïòèìàëüíûå ðàññåâû äëÿ âûáðàííûõ êóðñîâ. Íàçíà÷üòå îäèí èëè íåñêîëüêî äèñòàíöèè íà ýòàïû, âûáðàâ äèñòàíöèè è ýòàïû èç ñïèñêîâ íèæå. Âñå ýòàïû ìîãóò èìåòü îäèíàêîâûé íàáîð äèñòàíöèé, èëè âû ìîæåòå íàçíà÷èòü ðàçëè÷íûå íàáîðû äèñòàíöèé äëÿ êàæäîãî ýòàïà, åñëè äèñòàíöèè ïîçâîëÿþò ñäåëàòü ýòî. +tooltip_explain_status = - = Íåèçâåñòíûé ñòàòóñ (Åù¸ íåò ðåçóëüòàòà)\nOK = êîððåêòíûé ðåçóëüòàò\nDNS = Íå ñòàðò.n\nMP = ï.ï.2.6.10\nDNF = Ñîø¸ë\nDISQ = Äèñêâ.\nOMT = Ïðåâ. êîíòð. âð.\nNTP = ÂÊ +Automatic rogaining point reduction = Àâòîìàòè÷åñêîå âû÷èòàíèå î÷êîâ â ðîãåéíå +Time as computed by your time method = Âðåìÿ âû÷èñëåíî ïî âàøåìó ìåòîäó +Do you want to clear the card memory? = Âû äåéñòâèòåëüíî õîòèòå î÷èñòèòü ïàìÿòü ÷èïà? +Vill du sätta resultatet från tidigare etapper till ? = Âû õîòèòå èçìåíèòü ðåçóëüòàò â ïðåäûäóùèõ ñòàäèÿõ íà <íå ïðèíèìàë ó÷àñòèå>? +Choose result module = Âûáåðèòå ìîäóëü +Length of course = Äëèíà äèñòàíöèè +Valfri = Äîïîëíèòåëüíî +Symboler = Çíà÷åíèÿ +Index in X[index] = Èíäåêñ â X[èíäåêñ] +Individuella resultat = Èíäèâèäóàëüíûå ðåçóëüòàòû +Individual results in a club = Èíäèâèäóàëüíûå ðåçóëüòàòû â êëóáå +TeamGlobal = Êîìàíäà (Âñå ãðóïïû âìåñòå) +Team Rogaining = Êîìàíäíûé ðîãåéí +Maximum allowed running time = Êîíòðîëüíîå âðåìÿ +Placering = Ìåñòî +Place on course leg = Ìåñòî íà ïåðåãîíå +Resultatmodulen används i X = Ìîäóëü èñïîëüçóåòñÿ â X +ResultModuleTime = Ìîäóëü: ðåçóëüòàò +ResultModuleNumber = Ìîäóëü: ÷èñëî +Kunde inte ladda X\n\n(Y) = Íå ìîãó çàãðóçèòü X\n\n(Y) +Kunde inte öppna tävlingen = Íå ìîãó îòêðûòü ñîðåâíîâàíèÿ +Invalid operator X = Íåâåðíûé îïåðàòîð X +Unknown symbol X = Íåèçâåñòíîå çíà÷åíèå X +Leg number in team, zero indexed = Íîìåð ýòàïà â êîìàíäå, âêëþ÷àÿ 0 +Hantera deltagare som bytt klass = Îáðàáîòêà ó÷àñòíèêîâ ñìåíèâøèõ ãðóïïó +Övertid = Îïîçäàíèå +TeamRogainingOvertime = Îïîçäàíèå êîìàíäû (ðîãåéí) +User input number = Îïðåäåë¸ííûé ïîëüçîâàòåëåì âõîäíîé ïàðàìåòð +Deviation +/- from expected time on course leg = Îòêëîíåíèå +/- îò îæèäàåìîãî âðåìåíè íà ó÷àñòêå äèñòàíöèè +Debug = Îòëàäêà +Debug X for Y = Îòëàäêà X äëÿ Y +Debug Output = Îòëàäî÷íûé âûâîä +Punch codes for each team member = Îòìåòêè äëÿ êàæäîãî ó÷àñòíèêà êîìàíäû +TeamPointAdjustment = Î÷êè êîìàíäû, êîððåêòèðîâêà +TeamRogainingReduction = Î÷êè êîìàíäû, øòðàô +Points as computed by your point method = Î÷êè ïîñ÷èòàííûå âàøèì ìåòîäîì +Rogaining points for each team member = Î÷êè ðîãåéíà äëÿ êàæäîãî ÷ëåíà êîìàíäû +Error in result module X, method Y (Z) = Îøèáêà â ìîäóëå 'X', ìåòîä 'Y'\n\nZ +Variabler = Ïåðåìåííûå +Input Results = Ïðåäûäóùèå ðåçóëüòàòû +Input Results - X = Ïðåäûäóùèå ðåçóëüòàòû - X +Check: X = Ïðîâåðêà: X +Time after leg winner = Ïðîèãðûø ïîáåäèòåëþ ýòàïà +Tillåt ny klass, inget totalresultat = Ðàçðåøèòü íîâóþ ãðóïïó áåç èòîãîâîãî ðåçóëüòàòà +Tillåt ny klass, behåll resultat från annan klass = Ðàçðåøèòü íîâóþ ãðóïïó è ïðèñâîèòü ðåçóëüòàòû èç äðóãîé +TeamTimeAdjustment = Ðåçóëüòàò êîìàíäû, êîððåêòèðîâêà +Resultat från tidigare etapper = Ðåçóëüòàòû ïðåäûäóùèõ ñòàäèé +Shortest time in class = Ñàìîå áûñòðîå âðåìÿ â ãðóïïå +Följande deltagare har bytt klass (inget totalresultat) = Ñëåäóþùèå ñïîðòñìåíû ñìåíèëè ãðóïïó (íåò èòîãîâîãî ðåçóëüòàòà) +warn:opennewversion = Ñîðåâíîâàíèÿ ñîçäàíû â MeOS X. Äàííûå ìîãóò áûòü óòåðÿíû â ñëó÷àå ïðîäîëæåíèÿ. +Save changes in rule code? = Ñîõðàíèòü èçìåíåíèÿ â êîäå ïðàâèëà? +List Error: X = Ñïèñîê îøèáîê: X +Punch times for each team member = Ñïëèòû äëÿ êàæäîãî ó÷àñòíèêà êîìàíäû +Narrow Results = Óçêèé ïðîòîêîë ðåçóëüòàòîâ +Välj klasser med nya anmälningar = Óêàæèòå ãðóïïû â êîòîðûå ðàçðåøåíà çàÿâêà íîâûõ ó÷àñòíèêîâ +Runner/team running time = Ó÷àñòíèê/Êîìàíäà: áåãîâîå âðåìÿ +Runner/team fee = Ó÷àñòíèê/Êîìàíäà: âçíîñ +Runner/team input running time = Ó÷àñòíèê/Êîìàíäà: âõîäíîå áåãîâîå âðåìÿ +Runner/team input place = Ó÷àñòíèê/Êîìàíäà: âõîäíîå ìåñòî +Runner/team input status = Ó÷àñòíèê/Êîìàíäà: âõîäíîé ñòàòóñ +Runner/team input points = Ó÷àñòíèê/Êîìàíäà: âõîäíûå î÷êè +Runner/team total running time = Ó÷àñòíèê/Êîìàíäà: èòîãîâîå áåãîâîå âðåìÿ +Runner/team total place = Ó÷àñòíèê/Êîìàíäà: èòîãîâîå ìåñòî +Runner/team total status = Ó÷àñòíèê/Êîìàíäà: èòîãîâûé ñòàòóñ +Runner/team rogaining points adjustment = Ó÷àñòíèê/Êîìàíäà: êîððåêòèðîâêà î÷êîâ +Runner/team time adjustment = Ó÷àñòíèê/Êîìàíäà: êîððåêòèðîâêà ðåçóëüòàòà +Runner/team place = Ó÷àñòíèê/Êîìàíäà: ìåñòî +Runner/team rogaining overtime = Ó÷àñòíèê/Êîìàíäà: îïîçäàíèå (ðîãåéí) +Runner/team rogaining points = Ó÷àñòíèê/Êîìàíäà: î÷êè ðîãåéíà +Runner/team start time = Ó÷àñòíèê/Êîìàíäà: ñòàðòîâîå âðåìÿ +Runner/team status = Ó÷àñòíèê/Êîìàíäà: ñòàòóñ +Runner/team finish time = Ó÷àñòíèê/Êîìàíäà: ôèíèøíîå âðåìÿ +Finish time for each team member = Ôèíèøíîå âðåìÿ äëÿ êàæäîãî ÷ëåíà êîìàíäû +Poängavdrag = Øòðàô (î÷êè) +Avdrag = Øòðàôîâàíèå +RunnerGlobal = Ó÷àñòíèê (âñå ãðóïïû) +RunnerRogainingOvertime = Ó÷àñòíèê: îïîçäàíèå (ðîãåéí) +RunnerRogainingReduction = Ó÷àñòíèê: øòðàô +Club id number = ID íîìåð êëóáà +District id number = ID íîìåð ðàéîíà +Matched control ids (-1 for unmatched) for each team member = Matched control ids (-1 for unmatched) for each team member +Rader markerade med (*) kommer från en lista i tävlingen = Rows with a (*) originates from a list in the competition +Runner's card, matched control ids (-1 for unmatched punches) = ×èï ó÷àñòíèêà: matched control ids (-1 for unmatched punches) +Runner's card, punch codes = ×èï ó÷àñòíèêà: íîìåðà ÊÏ +Runner's card, punch times = ×èï ó÷àñòíèêà: âðåìåíà îòìåòîê +Runner's course = Ó÷àñòíèê: äèñòàíöèÿ +Runner's method output numbers = Ó÷àñòíèê: ìåòîä âûâîäà ÷èñåë +Runner's method output times = Ó÷àñòíèê: ìåòîä âûâîäà ðåçóëüòàòà +RunnerPointAdjustment = Ó÷àñòíèê: êîððåêòèðîâêà î÷êîâ +Runner's split times = Ó÷àñòíèê: ñïëèòû +RunnerTimeAdjustment = Ó÷àñòíèê: êîððåêòèðîâêà ðåçóëüòàòà +Runner's total running time to control = Ó÷àñòíèê: èòîãîâîå áåãîâîå âðåìÿ äî ÊÏ +Running time for each team member = Áåãîâîå âðåìÿ äëÿ êàæäîãî ÷ëåíà êîìàíäû +Start time for each team member = Ñòàðòîâîå âðåìÿ äëÿ êàæäîãî ÷ëåíà êîìàíäû +Status as computed by your status method = Ñòàòóñ ïîëó÷åííûé Âàøèì ìåòîäîì ðàñ÷¸òà +Status code for a missing punch = Ñòàòóñ äëÿ ïðîïóñòèâøåãî ÊÏ +Status code for a time over the maximum = Ñòàòóñ äëÿ ïðåâûñèâøåãî êîíòð. Âðåìÿ +Status code for a valid result = Ñòàòóñ äëÿ âàëèäíîãî ðåçóëüòàòà +Status code for an unknown result = Ñòàòóñ äëÿ íåèçâåñòíîãî ðåçóëüòàòà +Status code for disqualification = Ñòàòóñ äëÿ äèñêâàëèôèöèðîâàííîãî +Status code for not competing = Ñòàòóñ äëÿ ó÷àñòíèêà âíå êîíêóðñà +Status code for not finishing = Ñòàòóñ äëÿ ñîøåäøåãî +Status code for not starting = Ñòàòóñ äëÿ íå ñòàðòîâàâøåãî +Status for each team member = Ñòàòóñ êàæäîãî ÷ëåíà êîìàíäû +Byt till vakansplats i rätt klass (om möjligt) = Ïåðåìåñòèòü íà ðåçåðâíîå ìåñòî â ïðàâèëüíîé ãðóïïå (åñëè âîçìîæíî) +Byt till rätt klass (behåll eventuell starttid) = Ïåðåìåñòèòü â ïðàâèëüíóþ ãðóïïó (ñîõðàíèâ ñòàðòîâîå âðåìÿ) +X är inget giltigt index = X íåâåðíûé èíäåêñ diff --git a/code/small.ico b/code/small.ico new file mode 100644 index 0000000000000000000000000000000000000000..b4160c6eccc2a894356deff25085af8a9bbfed30 GIT binary patch literal 1718 zcmc(gKWHOI6o;RJ!FnlQxj4>vSCX~M8B)A_GfERMq)3s~zWMW;nfJbZZx@NQZ;5>1h^7r)BB`K_sm)OxVj5!*=8_V?fH?p*}B+JXova+%wYinz= zzP>J-o13z|y)8RCJ92nQY`?lC-#fx*CFU@$O5Bp3_~1_lFzfgxhTU|=vX7#Iu;5gi5tgMq=oU|=wc z28V&e1PwXj%NEG+SnVX*|a1hP1_u*5X5Xc<^oEG#iCa9B7j92O1>M@$tQ z76uE0g(0NQ!eL>sF!=b!`$Y8wZ1f!I6hhHnI|*9)+GZl#v{G;(6FS9G-Zww1I;hcsP9E z;K5?KIpksSuy`Om0plwGi|3$clSlBdaAWwPCLR_a@)23W+YqXN27|(&FenTPgTfGB zCm1{o3WLJnVZaT>ei#%6g+XD!HHHp@!k{oH07`t1Gv%PN$>PH@w{U3m9rjrHQht`B zqa!&vIgwtkCue78a(Q_v=jZ2geSIxAH#c&7dn7+cJYNJV(b+Y|wP1o5kn>zbYXx+}5f}QRCS@9uLZQA<} z^?labYCjY#h4pFHYX4Xib6w9S&0wojcfLsG$;VWiL6&9hRErM%cMrsz7irVf^Lbhn zY1+(d)p|Ca&o`<`GD<63ex~*C^U=n!9S)DHQC?2V*&lgzk(cR+9eFwYx_p}_7y0qy zvu8=wd)0e;*SAU4zn}E&pz7tXX2aZ0(quU7pCZ3G-AMZRAWf?zNd~j(Vw9%I$0W`M P1Jd!Y*Ww@P>1}@jvo?FQ literal 0 HcmV?d00001 diff --git a/code/socket.cpp b/code/socket.cpp new file mode 100644 index 0000000..634a5e5 --- /dev/null +++ b/code/socket.cpp @@ -0,0 +1,183 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + + +#include "stdafx.h" +#include +#include +#include "socket.h" +#include "meosexception.h" +#include + +//#define MEOS_DIRECT_PORT 21338 + + +DirectSocket::DirectSocket(int cmpId, int p) { + competitionId = cmpId; + port = p; + InitializeCriticalSection(&syncObj); + shutDown = false; + sendSocket = -1; + hDestinationWindow = 0; + clearQueue = false; +} + +DirectSocket::~DirectSocket() { + EnterCriticalSection(&syncObj); + shutDown = true; + LeaveCriticalSection(&syncObj); + + if (sendSocket != -1) { + closesocket(sendSocket); + sendSocket = -1; + } + + Sleep(1000); + DeleteCriticalSection(&syncObj); + shutDown = true; +} + +void DirectSocket::addPunchInfo(const SocketPunchInfo &pi) { + //OutputDebugString("Enter punch in queue\n"); + EnterCriticalSection(&syncObj); + if (clearQueue) + messageQueue.clear(); + clearQueue = false; + messageQueue.push_back(pi); + LeaveCriticalSection(&syncObj); + PostMessage(hDestinationWindow, WM_USER + 3, 0,0); +} + +void DirectSocket::getPunchQueue(vector &pq) { + pq.clear(); + + EnterCriticalSection(&syncObj); + if (!clearQueue) + pq.insert(pq.begin(), messageQueue.begin(), messageQueue.end()); + + clearQueue = true; + LeaveCriticalSection(&syncObj); + return; +} + +void DirectSocket::listenDirectSocket() { + + SOCKET clientSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (clientSocket == -1) { + throw meosException("Socket error"); + } + + SOCKADDR_IN UDPserveraddr; + memset(&UDPserveraddr,0, sizeof(UDPserveraddr)); + UDPserveraddr.sin_family = AF_INET; + UDPserveraddr.sin_port = htons(port); + UDPserveraddr.sin_addr.s_addr = INADDR_ANY; + + if (bind(clientSocket, (SOCKADDR*)&UDPserveraddr,sizeof(SOCKADDR_IN)) < 0) { + throw meosException("Socket error"); + } + + fd_set fds; + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 200000; + + while (!shutDown) { + FD_ZERO(&fds); + FD_SET(clientSocket, &fds); + + int rc = select(0, &fds, NULL, NULL, &timeout); + + if (shutDown) { + closesocket(clientSocket); + return; + } + + if (rc > 0) { + ExtPunchInfo pi; + SOCKADDR_IN clientaddr; + int len = sizeof(clientaddr); + if (recvfrom(clientSocket, (char*)&pi, sizeof(pi), 0, (sockaddr*)&clientaddr, &len) > 0) { + if (pi.cmpId == competitionId) + addPunchInfo(pi.punch); + } + } + } + closesocket(clientSocket); +} + +void startListeningDirectSocket(void *p) { + string error; + try { + ((DirectSocket*)p)->listenDirectSocket(); + } + catch (std::exception &ex) { + error = ex.what(); + } + catch (...) { + error = "Unknown error"; + } + if (!error.empty()) { + error = "Setting up advance information service for punches failed. Punches will be recieved with some seconds delay. Is the network port blocked by an other MeOS session?\n\n" + error; + MessageBox(NULL, error.c_str(), "MeOS", MB_OK|MB_ICONSTOP); + } +} + +void DirectSocket::startUDPSocketThread(HWND targetWindow) { + hDestinationWindow = targetWindow; + _beginthread(startListeningDirectSocket, 0, this); +} + +void DirectSocket::sendPunch(SocketPunchInfo &pi) { + + if (sendSocket == -1) { + WORD w = MAKEWORD(1,1); + WSADATA wsadata; + WSAStartup(w, &wsadata); + + sendSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sendSocket == -1) { + throw meosException("Socket error"); + } + char opt = 1; + setsockopt(sendSocket, SOL_SOCKET, SO_BROADCAST, (char*)&opt, sizeof(char)); + } + + SOCKADDR_IN brdcastaddr; + memset(&brdcastaddr,0, sizeof(brdcastaddr)); + brdcastaddr.sin_family = AF_INET; + brdcastaddr.sin_port = htons(port); + brdcastaddr.sin_addr.s_addr = INADDR_BROADCAST; + + int len = sizeof(brdcastaddr); + + ExtPunchInfo epi; + epi.cmpId = competitionId; + epi.punch = pi; + + int ret = sendto(sendSocket, (char*)&epi, sizeof(epi), 0, (sockaddr*)&brdcastaddr, len); + + if (ret < 0) { + OutputDebugString("Error broadcasting to the clients"); + } +} diff --git a/code/socket.h b/code/socket.h new file mode 100644 index 0000000..dfb2764 --- /dev/null +++ b/code/socket.h @@ -0,0 +1,72 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +#include + +struct SocketPunchInfo { + int runnerId; + int iHashType; // Hash including contolId, courseControlId (duplicate info in course), race number + int status; + int time; + SocketPunchInfo() { + runnerId = -1; + iHashType = -1; + status = -1; + time = -1; + } +}; + +class DirectSocket { +private: + + struct ExtPunchInfo { + int cmpId; + SocketPunchInfo punch; + }; + + int competitionId; + list messageQueue; + HWND hDestinationWindow; + CRITICAL_SECTION syncObj; + volatile bool shutDown; + void listenDirectSocket(); + void addPunchInfo(const SocketPunchInfo &pi); + bool startedUDPThread; + + SOCKET sendSocket; + bool clearQueue; + int port; +public: + + void startUDPSocketThread(HWND targetWindow); + void sendPunchInfo(SocketPunchInfo &pi); + void getPunchQueue(vector &queue); + + void sendPunch(SocketPunchInfo &pi); + + DirectSocket(int cmpId, int port); + ~DirectSocket(); + + friend void startListeningDirectSocket(void *p); +}; diff --git a/code/speakermonitor.cpp b/code/speakermonitor.cpp new file mode 100644 index 0000000..a6a6895 --- /dev/null +++ b/code/speakermonitor.cpp @@ -0,0 +1,790 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "oEvent.h" +#include "gdioutput.h" +#include "meos_util.h" +#include +#include "Localizer.h" +#include +#include "gdifonts.h" +#include "meosexception.h" +#include "speakermonitor.h" +#include "oListInfo.h" + +SpeakerMonitor::SpeakerMonitor(oEvent &oe) : oe(oe) { + placeLimit = 0; + numLimit = 0; + + maxClassNameWidth = 0; + + classWidth = 0; + timeWidth = 0; + totWidth = 0; + extraWidth = 0; +} + +SpeakerMonitor::~SpeakerMonitor() { +} + +void SpeakerMonitor::setClassFilter(const set &filter, const set &cfilter) { + classFilter = filter; + controlIdFilter = cfilter; + oListInfo li; + maxClassNameWidth = li.getMaxCharWidth(&oe, classFilter, lClassName, "", normalText, false); +} + +void SpeakerMonitor::setLimits(int place, int num) { + placeLimit = place; + numLimit = num; +} + +bool orderResultsInTime(const oEvent::ResultEvent &a, + const oEvent::ResultEvent &b) { + if (a.time != b.time) + return a.time > b.time; + + if (a.time > 0) { + const string &na = a.r->getName(); + const string &nb = b.r->getName(); + + return CompareString(LOCALE_USER_DEFAULT, 0, + na.c_str(), na.length(), + nb.c_str(), nb.length()) == CSTR_LESS_THAN; + } + return a.r->getId() < b.r->getId(); +} + +void SpeakerMonitor::show(gdioutput &gdi) { + classWidth = gdi.scaleLength(1.5*maxClassNameWidth); + timeWidth = gdi.scaleLength(60); + totWidth = gdi.scaleLength(600); + extraWidth = gdi.scaleLength(200); + dash = MakeDash("- "); + + oe.getResultEvents(classFilter, controlIdFilter, results); + calculateResults(); + + orderedResults.resize(results.size()); + for (size_t k = 0; k < results.size(); k++) { + // Initialize forward map + results[k].localIndex = k; + orderedResults[k].r = results[k].r; + orderedResults[k].totalTime = results[k].runTime; + } + + // Sort + sort(results.begin(), results.end(), orderResultsInTime); + + // Initialize map back + for (size_t k = 0; k < results.size(); k++) { + orderedResults[results[k].localIndex].eventIx = k; + } + + for (size_t k = 0; k < results.size(); k++) { + oEvent::ResultEvent &re(results[results.size()-(1+k)]); + if (re.status == StatusOK) { + map &dynLead = dynamicTotalLeaderTimes[ResultKey(re.classId(), re.control, re.leg())]; + int totTime = re.runTime; + if (dynLead.empty() || totTime < dynLead.rbegin()->second) + dynLead[re.time] = totTime; + } + } + + int order = 0; + for (size_t k = 0; k < results.size() && (order < numLimit || numLimit == 0); k++) { + if (results[k].time > 0) { + oEvent::ResultEvent *ahead = 0, *behind = 0; + + if (results[k].status == StatusOK) + ahead = k > 0 && sameResultPoint(results[k], results[k-1]) ? &results[k-1] : 0; + if (results[k].status == StatusOK) + behind = (k + 1) < results.size() && sameResultPoint(results[k], results[k+1]) ? &results[k+1] : 0; + + renderResult(gdi, ahead, results[k], behind, order, true); + } + } + + for (size_t k = 0; k < results.size() && (order < numLimit || numLimit == 0); k++) { + if (results[k].time == 0) + renderResult(gdi, 0, results[k], 0, order, false); + else + break; + } +} + +bool SpeakerMonitor::sameResultPoint(const oEvent::ResultEvent &a, + const oEvent::ResultEvent &b) { + return a.control == b.control && a.classId() == b.classId() && a.leg() == b.leg(); +} + +void SpeakerMonitor::renderResult(gdioutput &gdi, + const oEvent::ResultEvent *ahead, + const oEvent::ResultEvent &res, + const oEvent::ResultEvent *behind, + int &order, + bool firstResults) { + + + /*string s = itos(res.localIndex) + ": " + res.r->getName() + " control: " + + itos(res.control) + " tid: " + formatTime(res.runTime); + gdi.addStringUT(0, s); + */ + int finishLargePlaceLimit = 5; + int radioLargePlaceLimit = 3; + const bool showClass = classFilter.size() > 1; + + if (res.status == StatusOK) { + if (res.place > placeLimit && res.r->getSpeakerPriority() == 0 ) { + return; + } + } + else if (order < max(2, numLimit/20)) { + return; + } + else if (res.status == StatusNotCompetiting) { + return; // DQ on ealier leg, for example + } + + order++; + const int extra = 5; + + int t = res.time; + string msg = t>0 ? oe.getAbsTime(t) : MakeDash("--:--:--"); + pRunner r = res.r; + + RECT rc; + rc.top = gdi.getCY(); + rc.left = gdi.getCX(); + + int xp = rc.left + extra; + int yp = rc.top + extra; + + bool largeFormat = res.status == StatusOK && + ((res.control == oPunch::PunchFinish && res.place <= finishLargePlaceLimit) || + res.place <= radioLargePlaceLimit); + string message; + deque details; + getMessage(res,message, details); + + if (largeFormat) { + gdi.addStringUT(yp, xp, 0, msg); + + int dx = 0; + if (showClass) { + pClass pc = res.r->getClassRef(); + if (pc) { + gdi.addStringUT(yp, xp + timeWidth, fontMediumPlus, pc->getName()); + dx = classWidth; + } + } + + string bib = r->getBib(); + if (!bib.empty()) + msg = bib + ", "; + else + msg = ""; + + msg += r->getCompleteIdentification(false); + int xlimit = totWidth + extraWidth - (timeWidth + dx); + gdi.addStringUT(yp, xp + timeWidth + dx, fontMediumPlus, msg, xlimit); + + yp += int(gdi.getLineHeight() * 1.5); + + msg = dash + lang.tl(message); + gdi.addStringUT(yp, xp + 10, breakLines, msg, totWidth); + + for (size_t k = 0; k < details.size(); k++) { + gdi.addStringUT(gdi.getCY(), xp + 20, 0, dash + lang.tl(details[k])).setColor(colorDarkGrey); + } + + if (res.control == oPunch::PunchFinish && r->getStatus() == StatusOK) { + splitAnalysis(gdi, xp + 20, gdi.getCY(), r); + } + + GDICOLOR color = colorLightRed; + + if (res.control == oPunch::PunchFinish) { + if (r && r->statusOK()) + color = colorLightGreen; + else + color = colorLightRed; + } + else { + color = colorLightCyan; + } + + rc.bottom = gdi.getCY() + extra; + rc.right = rc.left + totWidth + extraWidth + 2 * extra; + gdi.addRectangle(rc, color, true); + gdi.dropLine(0.5); + } + else { + if (showClass) { + pClass pc = res.r->getClassRef(); + if (pc) + msg += " (" + pc->getName() + ") "; + else + msg += " "; + } + else + msg += " "; + + msg += r->getCompleteIdentification(false) + " "; + + msg += lang.tl(message); + gdi.addStringUT(gdi.getCY(), gdi.getCX(), breakLines, msg, totWidth); + + for (size_t k = 0; k < details.size(); k++) { + gdi.addString("", gdi.getCY(), gdi.getCX()+50, 0, details[k]).setColor(colorDarkGrey); + } + + if (res.control == oPunch::PunchFinish && r->getStatus() == StatusOK) { + splitAnalysis(gdi, xp, gdi.getCY(), r); + } + gdi.dropLine(0.5); + } + + +} + +bool compareResult(const oEvent::ResultEvent &a, + const oEvent::ResultEvent &b) { + + if (a.classId() != b.classId()) + return a.classId() < b.classId(); + if (a.control != b.control) + return a.control < b.control; + int lega = a.leg(); + int legb = b.leg(); + if (lega != legb) + return legagetId() < b.r->getId(); +} + +void SpeakerMonitor::calculateResults() { + // TODO Result modules + + for (size_t k = 0; k < results.size(); k++) { + /*int t = results[k].time; + if (t == 16016 || t == 15610) { + pRunner r = results[k].r; + pTeam tm = r->getTeam(); + int rt = t - r->getStartTime(); + int start = r->getStartTime(); + int rtIn = tm->getLegRunningTime(r->getLegNumber() - 1, true); + int ttt = rtIn + rt; + string x = r->getName() + ":" + formatTime(rt) + "/" + formatTimeHMS(start) + + "/" + formatTime(rtIn) + "/" + formatTime(ttt) + "\n"; + + OutputDebugString(x.c_str()); + + int tttt = r->getTotalRunningTime(t); + }*/ + results[k].runTime = results[k].r->getTotalRunningTime(results[k].time); + if (results[k].status == StatusOK) + results[k].resultScore = results[k].runTime; + else + results[k].resultScore = RunnerStatusOrderMap[results[k].status] + 3600*24*7; + } + + totalLeaderTimes.clear(); + firstTimes.clear(); + dynamicTotalLeaderTimes.clear(); + runnerToTimeKey.clear(); + timeToResultIx.clear(); + sort(results.begin(), results.end(), compareResult); + + int clsId = -1; + int ctrlId = -1; + int legId = -1; + int lastScore = 0; + int place = 0; + + for (size_t k = 0; k < results.size(); k++) { + if (results[k].partialCount > 0) + continue; // Skip in result calculation + int totTime = results[k].r->getTotalRunningTime(results[k].time); + int leg = results[k].leg(); + + if (clsId != results[k].classId() || ctrlId != results[k].control || legId != leg) { + clsId = results[k].classId(); + ctrlId = results[k].control; + legId = leg; + place = 1; + ResultKey key(clsId, ctrlId, leg); + + totalLeaderTimes[key] = totTime; + } + else if (lastScore != results[k].resultScore) + place++; + + ResultKey key(clsId, ctrlId, leg); + lastScore = results[k].resultScore; + + if (results[k].status == StatusOK) { + results[k].place = place; + runnerToTimeKey[results[k].r->getId()].push_back(ResultInfo(key, results[k].time, totTime)); + + if (results[k].time > 0) { + int val = firstTimes[key]; + firstTimes[key] = (val > 0 && val < results[k].time) ? val : results[k].time; + } + } + else + results[k].place = 0; + } + + // Sort times for each runner + for (map >::iterator it = runnerToTimeKey.begin(); + it != runnerToTimeKey.end(); ++it) { + sort(it->second.begin(), it->second.end(), timeSort); + } +} + +void SpeakerMonitor::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) { + +} + +void SpeakerMonitor::splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r) { + vector delta; + r->getSplitAnalysis(delta); + string timeloss = lang.tl("Bommade kontroller: "); + pCourse pc = 0; + bool first = true; + const int charlimit = 90; + for (size_t j = 0; j 0) { + if (pc == 0) { + pc = r->getCourse(true); + if (pc == 0) + break; + } + + if (!first) + timeloss += " | "; + else + first = false; + + timeloss += pc->getControlOrdinal(j) + ". " + formatTime(delta[j]); + } + if (timeloss.length() > charlimit || (!timeloss.empty() && !first && j+1 == delta.size())) { + gdi.addStringUT(yp, xp, 0, timeloss).setColor(colorDarkRed); + yp += gdi.getLineHeight(); + timeloss = ""; + } + } + if (first) { + gdi.addString("", yp, xp, 0, "Inga bommar registrerade").setColor(colorDarkGreen); + } +} + +string getOrder(int k); +string getNumber(int k); +void getTimeAfterDetail(string &detail, int timeAfter, int deltaTime, bool wasAfter); + +string getTimeDesc(int t1, int t2) { + int tb = abs(t1 - t2); + string stime; + if (tb == 1) + stime = "1" + lang.tl(" sekund"); + else if (tb <= 60) + stime = itos(tb) + lang.tl(" sekunder"); + else + stime = formatTime(tb); + + return stime; +} + +void SpeakerMonitor::getMessage(const oEvent::ResultEvent &res, + string &message, deque &details) { + pClass cls = res.r->getClassRef(); + if (!cls) + return; + + string &msg = message; + + int totTime = res.runTime; + int leaderTime = getLeaderTime(res); + int timeAfter = totTime - leaderTime; + + ResultKey key(res.classId(), res.control, res.leg()); + + vector &rResults = runnerToTimeKey[res.r->getId()]; + ResultInfo *preRes = 0; + pRunner preRunner = 0; + + for (size_t k = 0; k < rResults.size(); k++) { + if (rResults[k] == key) { + if (k > 0) { + preRes = &rResults[k-1]; + preRunner = res.r; + } + else { + int leg = res.r->getLegNumber(); + if (leg > 0 && res.r->getTeam()) { + while (leg > 0) { + pRunner pr = res.r->getTeam()->getRunner(--leg); + // TODO: Pursuit + if (pr && pr->prelStatusOK() && pr->getFinishTime() == res.r->getStartTime()) { + vector &rResultsP = runnerToTimeKey[pr->getId()]; + if (!rResultsP.empty()) { + preRes = &rResultsP.back(); + preRunner = pr; + } + break; + } + } + } + } + + } + } + + if (res.status != StatusOK) { + if (res.status != StatusDQ) + msg = "är inte godkänd."; + else + msg = "är diskvalificerad."; + + return; + } + + bool hasPrevRes = false; + int deltaTime = 0; + + const oEvent::ResultEvent *ahead = getAdjacentResult(res, -1); + const oEvent::ResultEvent *behind = getAdjacentResult(res, +1); + + if (preRes != 0) { + int prevLeader = getDynamicLeaderTime(*preRes, preRes->time); + int prevAfter = preRes->totTime - prevLeader; // May be negative (for leader) + int after = totTime - getDynamicLeaderTime(res, res.time); + + hasPrevRes = totTime > 0 && preRes->totTime > 0; + + if (after == 0) { // Takes (and holds) the lead in a relay (for example) + if (!behind) { + hasPrevRes = false; + } + else { + after = totTime - behind->runTime; // A negative number. Time ahead. + } + } + + if (prevAfter == 0) { // Took (and holds) the lead + int rix = getResultIx(*preRes); + const oEvent::ResultEvent *prevBehind = 0; + if (rix != -1) + prevBehind = getAdjacentResult(results[rix], +1); + + if (!prevBehind) { + hasPrevRes = false; + } + else { + prevAfter = preRes->totTime - prevBehind->runTime; // A negative number. Time ahead + } + + } + + deltaTime = after - prevAfter; // Positive -> more after. + } + + string timeS = formatTime(res.runTime); + + + string detail; + const string *cname = 0; + if (timeAfter > 0 && ahead) + cname = &ahead->r->getName(); + else if (timeAfter < 0 && behind) + cname = &behind->r->getName(); + + int ta = timeAfter; + if (res.place == 1 && behind && behind->status == StatusOK) + ta = res.runTime - behind->runTime; + + getTimeAfterDetail(detail, ta, deltaTime, hasPrevRes); + if (!detail.empty()) + details.push_back(detail); + + pCourse crs = res.r->getCourse(false); + + string location, locverb, thelocation; + + bool finish = res.control == oPunch::PunchFinish; + bool changeover = false; + int leg = res.r->getLegNumber(); + int numstage = cls->getNumStages(); + if (finish && res.r->getTeam() != 0 && (leg + 1) < numstage) { + for (int k = leg + 1; k < numstage; k++) + if (!cls->isParallel(k) && !cls->isOptional(k)) { + finish = false; + changeover = true; + break; + } + } + + if (finish) { + location = "i mål"; + locverb = "går i mål"; + thelocation = lang.tl("målet") + "#"; + } + else if (changeover) { + location = "vid växeln"; + locverb = "växlar"; + thelocation = lang.tl("växeln") + "#"; + } + else { + thelocation = crs ? (crs->getRadioName(res.control) + "#") : "#"; + } + + + bool sharedPlace = (ahead && ahead->place == res.place) || (behind && behind->place == res.place); + + if (finish || changeover) { + if (res.place == 1) { + if ((ahead == 0 && behind == 0) || firstTimes[key] == res.time) + msg = "är först " + location + " med tiden X.#" + timeS; + else if (!sharedPlace) { + msg = "tar ledningen med tiden X.#" + timeS; + if (behind && res.place>2) { + string stime(getTimeDesc(behind->runTime, totTime)); + details.push_back("är X före Y#" + stime + "#" + behind->r->getCompleteIdentification(false)); + } + } + else + msg = "går upp i delad ledning med tiden X.#" + timeS; + } + else { + if (firstTimes[key] == res.time) { + msg = "var först " + location + " med tiden X.#" + timeS; + + if (!sharedPlace) { + details.push_front("är nu på X plats med tiden Y.#" + + getOrder(res.place) + "#" + timeS); + if (ahead && res.place != 2) { + string stime(getTimeDesc(ahead->runTime, totTime)); + details.push_back("är X efter Y#" + stime + "#" + ahead->r->getCompleteIdentification(false)); + } + } + else { + details.push_back("är nu på delad X plats med tiden Y.#" + getOrder(res.place) + + "#" + timeS); + string share; + getSharedResult(res, share); + details.push_back(share); + } + } + else if (!sharedPlace) { + msg = locverb + " på X plats med tiden Y.#" + + getOrder(res.place) + "#" + timeS; + if (ahead && res.place != 2) { + string stime(getTimeDesc(ahead->runTime, totTime)); + details.push_back("är X efter Y#" + stime + "#" + ahead->r->getCompleteIdentification(false)); + } + } + else { + msg = locverb + " på delad X plats med tiden Y.#" + getOrder(res.place) + + "#" + timeS; + string share; + getSharedResult(res, share); + details.push_back(share); + } + } + if (changeover && res.r->getTeam() && res.r->getTeam()->getClassRef() != 0) { + string vxl = "skickar ut X.#"; + pTeam t = res.r->getTeam(); + pClass cls = t->getClassRef(); + bool second = false; + int nextLeg = cls->getNextBaseLeg(res.r->getLegNumber()); + if (nextLeg > 0) { + for (int k = nextLeg; k < t->getNumRunners(); k++) { + pRunner r = t->getRunner(k); + if (!r && !vxl.empty()) + continue; + if (second) + vxl += ", "; + second = true; + vxl += r ? r->getName() : "?"; + if (!(cls->isParallel(k) || cls->isOptional(k))) + break; + } + } + details.push_front(vxl); + } + } + else { + if (res.place == 1) { + if ((ahead == 0 && behind == 0) || res.time == firstTimes[key]) + msg = "är först vid X med tiden Y.#" + thelocation + timeS; + else if (!sharedPlace) { + msg = "tar ledningen vid X med tiden Y.#" + thelocation + timeS; + if (behind) { + string stime(getTimeDesc(behind->runTime, totTime)); + details.push_back("är X före Y#" + stime + "#" + behind->r->getCompleteIdentification(false)); + } + } + else + msg = "går upp i delad ledning vid X med tiden Y.#" + thelocation + timeS; + } + else { + if (firstTimes[key] == res.time) { + msg = "var först vid X med tiden Y.#" + thelocation + timeS; + + if (!sharedPlace) { + details.push_front("är nu på X plats med tiden Y.#" + + getOrder(res.place) + "#" + timeS); + if (ahead) { + string stime(getTimeDesc(ahead->runTime, totTime)); + details.push_back("är X efter Y#" + stime + "#" + ahead->r->getCompleteIdentification(false)); + } + } + else { + details.push_back("är nu på delad X plats med tiden Y.#" + getOrder(res.place) + + "#" + timeS); + string share; + getSharedResult(res, share); + details.push_back(share); + } + } + else if (!sharedPlace) { + msg = "stämplar vid X som Y, på tiden Z.#" + + thelocation + getNumber(res.place) + + "#" + timeS; + if (ahead && res.place>2) { + string stime(getTimeDesc(ahead->runTime, totTime)); + details.push_back("är X efter Y#" + stime + "#" + ahead->r->getCompleteIdentification(false)); + } + } + else { + msg = "stämplar vid X som delad Y med tiden Z.#" + thelocation + getNumber(res.place) + + "#" + timeS; + string share; + getSharedResult(res, share); + details.push_back(share); + } + } + } + return; +} + +void SpeakerMonitor::getSharedResult(const oEvent::ResultEvent &res, string &detail) const { + vector shared; + getSharedResult(res, shared); + if (!shared.empty()) + detail = "delar placering med X.#"; + else + detail = ""; + + for (size_t k = 0; k < shared.size(); k++) { + if (k > 0) + detail += ", "; + + detail += shared[k]->getCompleteIdentification(false); + } +} + +void SpeakerMonitor::getSharedResult(const oEvent::ResultEvent &res, vector &shared) const { + shared.clear(); + if (res.status != StatusOK) + return; + int p = 1; + const oEvent::ResultEvent * ar;; + while ( (ar = getAdjacentResult(res, p++)) != 0 && ar->place == res.place) { + shared.push_back(ar->r); + } + p = 1; + while ( (ar = getAdjacentResult(res, -(p++))) != 0 && ar->place == res.place) { + shared.push_back(ar->r); + } +} + +const oEvent::ResultEvent *SpeakerMonitor::getAdjacentResult(const oEvent::ResultEvent &res, int delta) const { + while (true) { + int orderIx = res.localIndex + delta; + if (orderIx < 0 || orderIx >= int(orderedResults.size()) ) + return 0; + + int aIx = orderedResults[orderIx].eventIx; + + if (!sameResultPoint(res, results[aIx])) + return 0; + + if (results[aIx].partialCount == 0) + return &results[aIx]; + + if (delta < 0) + delta--; + else + delta++; + } +} + +int SpeakerMonitor::getLeaderTime(const oEvent::ResultEvent &res) { + return totalLeaderTimes[ResultKey(res.classId(), res.control, res.leg())]; +} + +int SpeakerMonitor::getDynamicLeaderTime(const oEvent::ResultEvent &res, int time) { + return getDynamicLeaderTime(ResultKey(res.classId(), res.control, res.leg()), time); +} + +int SpeakerMonitor::getDynamicLeaderTime(const ResultKey &res, int time) { + map &leaderMap = dynamicTotalLeaderTimes[res]; + map::iterator g = leaderMap.lower_bound(time); + if (leaderMap.empty()) + return 0; + + if (g != leaderMap.end()) { + if (g != leaderMap.begin()) + --g; + return g->second; + } + else + return leaderMap.rbegin()->second; +} + + +int SpeakerMonitor::getResultIx(const ResultInfo &rinfo) { + if (timeToResultIx.empty()) { + for (size_t k = 0; k < results.size(); k++) { + timeToResultIx.insert(make_pair(results[k].time, k)); + } + } + + pair::iterator, multimap::iterator> range = timeToResultIx.equal_range(rinfo.time); + while (range.first != range.second) { + int ix = range.first->second; + if (results[ix].classId() == rinfo.classId && + results[ix].leg() == rinfo.leg && + results[ix].control == rinfo.radio) { + return ix; + } + ++range.first; + } + + return -1; +} diff --git a/code/speakermonitor.h b/code/speakermonitor.h new file mode 100644 index 0000000..0f14a49 --- /dev/null +++ b/code/speakermonitor.h @@ -0,0 +1,141 @@ +#pragma once +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "oListInfo.h" +#include + +class gdioutput; + +class SpeakerMonitor : public GuiHandler { +private: + + struct ResultKey { + int classId; + int radio; + int leg; + + ResultKey(int classId, int radio, int leg) : + classId(classId), radio(radio), leg(leg) {} + + bool operator<(const ResultKey &key) const { + if (classId != key.classId) + return classId < key.classId; + else if (radio != key.radio) + return radio < key.radio; + else + return leg < key.leg; + } + + bool operator==(const ResultKey &key) const { + return radio == key.radio && classId == key.classId && leg == key.leg; + } + }; + + struct ResultInfo : public ResultKey { + int time; + int totTime; + + ResultInfo(const ResultKey &key, int time, int totalTime) : + + ResultKey(key), time(time), totTime(totalTime) {} + + ResultInfo(int classId, int radio, int leg, int time, int totalTime) : + ResultKey(classId, radio, leg), time(time), totTime(totalTime) {} + }; + + struct SimpleResult { + SimpleResult() : r(0), eventIx(-1) {} + int totalTime; + pRunner r; + int eventIx; + bool isValid() const {return r != 0;} + }; + + + oEvent &oe; + SpeakerMonitor &operator=(const SpeakerMonitor&); // Not used + + set classFilter; + set controlIdFilter; + vector results; + + int placeLimit; + int numLimit; + + int maxClassNameWidth; + + int classWidth; + int timeWidth; + int totWidth; + int extraWidth; + string dash; + + void renderResult(gdioutput &gdi, + const oEvent::ResultEvent *ahead, + const oEvent::ResultEvent &res, + const oEvent::ResultEvent *behind, + int &order, bool firstResults); + + static bool sameResultPoint(const oEvent::ResultEvent &a, + const oEvent::ResultEvent &b); + + void getSharedResult(const oEvent::ResultEvent &res, vector &shared) const; + void getSharedResult(const oEvent::ResultEvent &res, string &detail) const; + + void splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r); + + void getMessage(const oEvent::ResultEvent &res, + string &message, deque &details); + + map firstTimes; + map totalLeaderTimes; + map > dynamicTotalLeaderTimes; + multimap timeToResultIx; + + int getResultIx(const ResultInfo &rinfo); + + map > runnerToTimeKey; + vector orderedResults; + + static bool timeSort(ResultInfo &a, ResultInfo &b) { + return a.time < b.time; + } + + const oEvent::ResultEvent *getAdjacentResult(const oEvent::ResultEvent &res, int delta) const; + + int getLeaderTime(const oEvent::ResultEvent &res); + int getDynamicLeaderTime(const oEvent::ResultEvent &res, int time); + int getDynamicLeaderTime(const ResultKey &res, int time); + +public: + void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type); + + SpeakerMonitor(oEvent &oe); + virtual ~SpeakerMonitor(); + + void setClassFilter(const set &filter, const set &controlIdFilter); + + void setLimits(int placeLimit, int numLimit); + void show(gdioutput &gdi); + + void calculateResults(); +}; diff --git a/code/swedish.lng b/code/swedish.lng new file mode 100644 index 0000000..b5f2b4d --- /dev/null +++ b/code/swedish.lng @@ -0,0 +1,2241 @@ +%s m = %s m +%s meter = %s meter +%s, block: %d = %s, block: %d +(ledare) = (ledare) +(lokalt) = (lokalt) +(okänd) stämplade vid = (okänd) stämplade vid +(på server) = (på server) +(sekunder) = (sekunder) +(sträckseger) = (sträckseger) +ALLA( = ALLA( +API-nyckel = API-nyckel +Accepterade elektroniska fakturor = Accepterade elektroniska fakturor +Adress = Adress +Adress och kontakt = Adress och kontakt +Aktivera = Aktivera +Alla = Alla +Alla banfiler = Alla banfiler +Alla deltagare måste ha ett namn = Alla deltagare måste ha ett namn +Alla fakturor = Alla fakturor +Alla händelser = Alla händelser +Alla lag måste ha ett namn = Alla lag måste ha ett namn +Alla listor = Alla listor +Alla lopp = Alla lopp +Alla sträckor/lopp i separata filer = Alla sträckor/lopp i separata filer +Alla typer = Alla typer +Allmänna resultat = Allmänna resultat +Andel vakanser = Andel vakanser +Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar = Ange första nummerlappsnummer eller lämna blankt för inga nummerlappar +Ange om kontrollen fungerar och hur den ska användas = Ange om kontrollen fungerar och hur den ska användas +Ange startintervall för minutstart = Ange startintervall för minutstart +Ange tiden relativt klassens första start = Ange tiden relativt klassens första start +Anm. avg = Anm. avg +Anm. avgift = Anm. avgift +Anm. datum = Anm. datum +Anmäl = Anmäl +Anmäl X = Anmäl X +Anmälda = Anmälda +Anmälda per distrikt = Anmälda per distrikt +Anmälningar = Anmälningar +Anmälningar (IOF (xml) eller OE-CSV) = Anmälningar (IOF-XML eller OE-CSV) +Anmälningsavgift = Anmälningsavgift +Anmälningsläge = Anmälningsläge +Anslut = Anslut +Anslut till en server = Anslut till en server +Ansluten till = Ansluten till +Ansluter till Internet = Ansluter till Internet +Anslutna klienter = Anslutna klienter +Anslutningar = Anslutningar +Anslutningsinställningar = Anslutningsinställningar +Antal = Antal +Antal besökare X, genomsnittlig bomtid Y, största bomtid Z = Antal besökare X, genomsnittlig bomtid Y, största bomtid Z +Antal ignorerade: X = Antal ignorerade: X +Antal importerade = Antal importerade +Antal kartor = Antal kartor +Antal klasser = Antal klasser +Antal löpare = Antal löpare +Antal löpare på vanligaste banan X = Antal löpare på vanligaste banan X +Antal misslyckade: X = Antal misslyckade: X +Antal startande per block = Antal startande per block +Antal startande per intervall (inklusive redan lottade) = Antal startande per intervall (inklusive redan lottade) +Antal sträckor = Antal sträckor +Antal vakanser = Antal vakanser +Antal: %d = Antal: %d +Antal: X = Antal: X +Antalet rader i urklipp får inte plats i selektionen = Antalet rader i urklipp får inte plats i selektionen +Använd Eventor = Använd Eventor +Använd banpool = Använd banpool +Använd funktioner för fleretappsklass = Använd funktioner för fleretappsklass +Använd första kontrollen som start = Använd första kontrollen som start +Använd löpardatabasen = Använd löpardatabasen +Använd sista kontrollen som mål = Använd sista kontrollen som mål +Använd speakerstöd = Använd speakerstöd +Använd stor font = Använd stor font +Använd symbolen X där MeOS ska fylla i typens data = Använd symbolen X där MeOS ska fylla i typens data +Användarnamn = Användarnamn +Applicera för specifik sträcka = Tillämpa för specifik sträcka +Arrangör = Arrangör +Att betala = Att betala +Att betala: X = Att betala: X +Automater = Automater +Automatisera = Automatisera +Automatisk lottning = Automatisk lottning +Automatisk skroll = Automatisk rullning +Automatisk utskrift = Automatisk utskrift +Automatisk utskrift / export = Automatisk utskrift/export +Av MeOS: www.melin.nu/meos = Av MeOS: www.melin.nu/meos +Avancerat = Avancerat +Avbryt = Avbryt +Avgift = Avgift +Avgifter = Avgifter +Avgiftshöjning (procent) = Avgiftshöjning (procent) +Avgjorda klasser (prisutdelningslista) = Avgjorda klasser (prisutdelningslista) +Avgjorda placeringar - %s = Avgjorda placeringar - %s +Avgörande händelser = Avgörande händelser +Avgörs X = Avgörs X +Avgörs kl = Avgörs kl +Avläsning/radiotider = Avläsning/radiotider +Avmarkera allt = Avmarkera allt +Avrundad tävlingsavgift = Avrundad tävlingsavgift +Avsluta = Avsluta +Bad file format = Felaktigt filformat +Bana = Bana +Bana %d = Bana %d +Banan används och kan inte tas bort = Banan används och kan inte tas bort +Banan måste ha ett namn = Banan måste ha ett namn +Banmall = Banmall +Banor = Banor +Banor (antal kontroller) = Banor (antal kontroller) +Banor för %s, sträcka %d = Banor för %s, sträcka %d +Banor, IOF (xml) = Banor, IOF (XML) +Banor, OCAD semikolonseparerat = Banor, OCAD semikolonseparerat +Banpool = Banpool +Banpool, gemensam start = Banpool, gemensam start +Banpool, lottad startlista = Banpool, lottad startlista +Bantilldelning = Bantilldelning +Bantilldelning, individuell = Bantilldelning, individuell +Bantilldelning, stafett = Bantilldelning, stafett +Bantilldelningslista - %s = Bantilldelningslista - %s +Basintervall (min) = Basintervall (min) +Begränsa antal per klass = Begränsa antal per klass +Begränsa per klass = Begränsa per klass +Begränsning, antal visade per klass = Begränsning, antal visade per klass +Behandlar löpardatabasen = Behandlar löpardatabasen +Behandlar tävlingsdata = Behandlar tävlingsdata +Behandlar: X = Behandlar: X +Bekräfta att %s byter klass till %s = Bekräfta att %s byter klass till %s +Bekräfta att deltagaren har lämnat återbud = Bekräfta att deltagaren har lämnat återbud +Betalat = Betalat +Betalningsinformation = Betalningsinformation +Bevakar händelser i X = Bevakar händelser i X +Bevakningsprioritering = Bevakningsprioritering +Block = Block +Blockbredd = Blockbredd +Bläddra = Bläddra +Bold = Fetstil +BoldHuge = Fet, gigantisk +BoldLarge = Fet, stor +BoldSmall = Fet, liten +Bommade kontroller = Bommade kontroller +Bomtid = Bomtid +Bomtid (max) = Bomtid (max) +Bomtid (medel) = Bomtid (medel) +Bomtid (median) = Bomtid (median) +Bomtid: X = Bomtid: X +Bricka = Bricka +Bricka %d används redan av %s och kan inte tilldelas = Bricka %d används redan av %s och kan inte tilldelas +Brickan redan inläst = Brickan redan inläst +Brickhyra = Brickhyra +Bricknummret är upptaget (X) = Bricknumret är upptaget (X) +Brickor = Brickor +Bygg databaser = Bygg databaser +COM-Port = COM-Port +Check = Check +ClassCourseResult = Klass, bana, resultat +ClassFinishTime = Klass, måltid +ClassLength = Banlängd för klass +ClassName = Klass +ClassPoints = Klass, poäng +ClassResult = Klass, resultat +ClassResultFraction = Andel klar av klass +ClassStartName = Startnamn +ClassStartTime = Klass, starttid, namn +ClassStartTimeClub = Klass, starttid, klubb +ClassTotalResult = Klass, totalresultat +Club = Klubb +ClubName = Klubb +ClubRunner = Klubb (deltagare) +CmpDate = Tävlingsdatum +CmpName = Tävlingsnamn +CourseClimb = Banans stigning +CourseLength = Banlängd, specifik bana +CourseName = Banans namn +CourseResult = Bana, resultat +CurrentTime = Aktuell tid +Databasanslutning = Databasanslutning +Databasvarning: X = Databasvarning: X +Datorröst som läser upp förvarningar = Datorröst som läser upp förvarningar +Datum = Datum +Decimalseparator = Decimaltecken +DefaultFont = Standardformatering +Dela = Dela +Dela efter ranking = Dela efter ranking +Dela klass: X = Dela klass: X +Dela klassen = Dela klassen +Dela klubbvis = Dela klubbvis +Deltagare = Deltagare +Deltagare %d = Deltagare %d +Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga +Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga +Deltagaren 'X' saknar klass = Deltagaren 'X' saknar klass +Deltar ej = Deltar ej +Denna etapps nummer = Denna etapps nummer +Destinationskatalog = Destinationskatalog +Det går endast att sätta in vakanser på sträcka 1 = Det går endast att sätta in vakanser på sträcka 1 +Det här programmet levereras utan någon som helst garanti. Programmet är = Det här programmet levereras utan någon som helst garanti. Programmet är +Direktanmälan = Direktanmälan +Disk = Disk +Distriktskod = Distriktskod +Don't know how to align with 'X' = Kan inte justera mot 'X' +Du kan importera banor och klasser från OCADs exportformat = Du kan importera banor och klasser från OCAD:s exportformat +Du måste välja en klass = Du måste välja en klass +Duplicera = Duplicera +E-post = E-post +Efter = Efter +Efteranm. avg. = Efteranm. avg. +Efteranmälda (efter ordinarie) = Efteranmälda (efter ordinarie) +Efteranmälda (före ordinarie) = Efteranmälda (före ordinarie) +Efteranmälda före ordinarie = Efteranmälda före ordinarie +Efteranmälningar = Efteranmälningar +Egen listrubrik = Egen listrubrik +Egen text = Egen text +Egenskaper = Egenskaper +Eget fönster = Eget fönster +Egna listor = Egna listor +Ej accepterade elektroniska fakturor = Ej accepterade elektroniska fakturor +Ej elektronisk = Ej elektronisk +Ej lottade = Ej lottade +Ej lottade, efter = Ej lottade, efter +Ej lottade, före = Ej lottade, före +Ej start = Ej start +Ej tidtagning = Ej tidtagning +Ekonomisk sammanställning = Ekonomisk sammanställning +Elektronisk = Elektronisk +Elektronisk godkänd = Elektronisk godkänd +Elit = Elit +Elitavgift = Elitavgift +Elitklasser = Elitklasser +En gafflad sträcka = En gafflad sträcka +En klass kan inte slås ihop med sig själv = En klass kan inte slås ihop med sig själv +En klubb kan inte slås ihop med sig själv = En klubb kan inte slås ihop med sig själv +Endast en bana = Endast en bana +Enhetstyp = Enhetstyp +Etapp = Etapp +Etapp X = Etapp X +Etappresultat = Etappresultat +Eventorkoppling = Eventorkoppling +Export av resultat/sträcktider = Export av resultat/sträcktider +Exportera = Exportera +Exportera / Säkerhetskopiera = Exportera/Säkerhetskopiera +Exportera alla till HTML = Exportera alla till HTML +Exportera datafil = Exportera datafil +Exportera elektroniska fakturor = Exportera elektroniska fakturor +Exportera inställningar och löpardatabaser = Exportera inställningar och löpardatabaser +Exportera löpardatabas = Exportera löpardatabas +Exportera nu = Exportera nu +Exportera på fil = Exportera på fil +Exportera resultat på fil = Exportera resultat på fil +Exportera startlista på fil = Exportera startlista på fil +Exportera sträcktider = Exportera sträcktider +Exportera tävlingsdata = Exportera tävlingsdata +Externt Id = Externt Id +Extra = Extra +Extra stämplingar = Extra stämplingar +Extralöparstafett = Extralöparstafett +FAKTURA = FAKTURA +FEL, inget svar = FEL, inget svar +FEL: Porten kunde inte öppnas = FEL: Porten kunde inte öppnas +Failed to generate card = Kunde inte generera inläsning +Failed to open 'X' for reading = Kunde inte öppna 'X' för läsning +Faktiskt startdjup: X minuter = Faktiskt startdjup: X minuter +Faktura = Faktura +Faktura nr = Faktura nr +Faktureras = Faktureras +Fakturor = Fakturor +Fel: X = Fel: X +Fel: hittar inte filen X = Fel: hittar inte filen 'X' +Felaktig kontroll = Felaktig kontroll +Felaktig nyckel = Felaktig nyckel +Felaktig sträcka = Felaktig sträcka +Felaktigt filformat = Felaktigt filformat +Felst = Felst +Fil att exportera till = Fil att exportera till +Fil: X = Fil: X +Filnamn = Filnamn +Filnamn (OCAD banfil) = Filnamn (OCAD banfil) +Filnamn IOF (xml) med klubbar = Filnamn IOF (XML) med klubbar +Filnamn IOF (xml) med löpare = Filnamn IOF (XML) med löpare +Filnamnet får inte vara tomt = Filnamnet får inte vara tomt +Filter = Filtrering +FilterHasCard = Med bricka +FilterNoCard = Utan bricka +FilterNotVacant = Inte vakant +FilterOnlyVacant = Endast vakanta +FilterRentCard = Hyrbricka +FilterResult = Med resultat +FilterStarted = Har startat +Filtrering = Filtrering +FinishTime = Måltid, namn +Flera banor = Flera banor +Flera banor / stafett / patrull / banpool = Flera banor/stafett/patrull/banpool +Flera banor/stafett = Flera banor/stafett +Flytta höger = Flytta höger +Flytta vänster = Flytta vänster +Format = Format +Formaterat webbdokument (html) = Formaterat webbdokument (html) +Formateringsregler = Formateringsregler +Formulärläge = Formulärläge +Fortsätt = Fortsätt +Fri anmälningsimport = Fri anmälningsimport +Fri starttid = Fri starttid +Fria starttider = Fria starttider +Från kontroll = Från kontroll +Fullskärm = Fullskärm +Funktioner = Funktioner +Födelseår = Födelseår +Följande deltagare deltar ej = Följande deltagare deltar ej +Följande deltagare har bytt klass = Följande deltagare har bytt klass +Följande deltagare har bytt klass (inget totalresultat) = Följande deltagare har bytt klass (inget totalresultat) +Följande deltagare har tilldelats en vakant plats = Följande deltagare har tilldelats en vakant plats +Följande deltagare är anmälda till nästa etapp men inte denna = Följande deltagare är anmälda till nästa etapp men inte denna +Följande deltagare är nyanmälda = Följande deltagare är nyanmälda +Följande deltagare överfördes ej = Följande deltagare överfördes ej +För att ändra måltiden måste löparens målstämplingstid ändras = För att ändra måltiden måste löparens målstämplingstid ändras +För muspekaren över en markering för att få mer information = För muspekaren över en markering för att få mer information +För många kontroller = För många kontroller +Förbered lottning = Förbered lottning +Fördefinierade tävlingsformer = Fördefinierade tävlingsformer +Fördela starttider = Fördela starttider +Föregående = Föregående +Föregående etapp = Föregående etapp +Förhandsgranskning, import = Förhandsgranskning, import +Förhöjd avgift = Förhöjd avgift +Först-i-mål, gemensam = Först-i-mål, gemensam +Först-i-mål, klassvis = Först-i-mål, klassvis +Första (ordinarie) start = Första (ordinarie) start +Första kontrollen = Första kontrollen +Första omstartstid = Första omstartstid +Första ordinarie starttid = Första ordinarie starttid +Första start = Första start +Första starttid = Första starttid +Första sträckan kan inte vara parallell = Första sträckan kan inte vara parallell +Försöket misslyckades = Försöket misslyckades +Förvarning på (SI-kod): alla stämplingar = Förvarning på (SI-kod): alla stämplingar +Förvarningsröst = Förvarningsröst +Förväntad andel efteranmälda = Förväntad andel efteranmälda +Gata = Gata +Gemensam start = Gemensam start +Generera = Generera +Generera testtävling = Generera testtävling +Genererad = Genererad +Geografisk fördelning = Geografisk fördelning +Global sorteringsordning = Global sorteringsordning +Godkänd API-nyckel = Godkänd API-nyckel +Granska inmatning = Granska inmatning +Grund avg = Grund avg +Grundavgift = Grundavgift +Grundinställningar = Grundinställningar +Hantera brickor = Hantera brickor +Hantera flera etapper = Hantera flera etapper +Hantera jaktstart = Hantera jaktstart +Hantera klubbar och ekonomi = Hantera klubbar och ekonomi +Hantera kvar-i-skogen = Hantera kvar-i-skogen +Hantera löparbrickor = Hantera löparbrickor +Hemsida = Hemsida +Hjälp = Hjälp +Hoppar över stafettklass: X = Hoppar över stafettklass: X +Huvudlista = Huvudlista +Hyravgift = Hyravgift +Hyrbricka = Hyrbricka +Hyrbricksrapport = Hyrbricksrapport +Hyrbricksrapport - %s = Hyrbricksrapport - %s +Hyrd = Hyrd +Hämta (efter)anmälningar från Eventor = Hämta (efter)anmälningar från Eventor +Hämta data från Eventor = Hämta data från Eventor +Hämta efteranmälningar = Hämta efteranmälningar +Hämta löpardatabasen = Hämta löpardatabasen +Hämta svar om elektroniska fakturor = Hämta svar om elektroniska fakturor +Hämta tävlingsdata = Hämta tävlingsdata +Hämta tävlingsdata för X = Hämta tävlingsdata för X +Hämtar anmälda = Hämtar anmälda +Hämtar information om = Hämtar information om +Hämtar klasser = Hämtar klasser +Hämtar klubbar = Hämtar klubbar +Hämtar löpardatabasen = Hämtar löpardatabasen +Hämtar tävling = Hämtar tävling +Händelser = Händelser +Händelser - tidslinje = Händelser - tidslinje +Hög avgift = Hög avgift +IOF (xml) = IOF (XML) +IOF Resultat (xml) = IOF Resultat (XML) +IOF Resultat, version 2.0.3 (xml) = IOF Resultat, version 2.0.3 (XML) +IOF Resultat, version 3.0 (xml) = IOF Resultat, version 3.0 (XML) +IOF Startlista (xml) = IOF Startlista (XML) +IP-adress eller namn på en MySQL-server = IP-adress eller namn på en MySQL-server +Id = Id +Identifierar X unika inledningar på banorna = Identifierar X unika inledningar på banorna +Importera = Importera +Importera IOF (xml) = Importera IOF (XML) +Importera anmälningar = Importera anmälningar +Importera banor = Importera banor +Importera banor/klasser = Importera banor/klasser +Importera en tävling från fil = Importera en tävling från fil +Importera fil = Importera fil +Importera från OCAD = Importera från OCAD +Importera från fil = Importera från fil +Importera löpardatabas = Importera löpardatabas +Importera löpare = Importera löpare +Importera löpare och klubbar / distriktsregister = Importera löpare och klubbar/distriktsregister +Importera stämplingar = Importera stämplingar +Importera tävling = Importera tävling +Importera tävlingsdata = Importera tävlingsdata +Importerar = Importerar +Importerar OCAD csv-fil = Importerar OCAD CSV-fil +Importerar OE2003 csv-fil = Importerar OE2003 CSV-fil +Importerar OS2003 csv-fil = Importerar OS2003 CSV-fil +Importerar anmälningar (IOF, xml) = Importerar anmälningar (IOF, XML) +Importerar banor (IOF, xml) = Importerar banor (IOF, XML) +Importerar klasser (IOF, xml) = Importerar klasser (IOF, XML) +Importerar klubbar (IOF, xml) = Importerar klubbar (IOF, XML) +Importerar tävlingsdata (IOF, xml) = Importerar tävlingsdata (IOF, XML) +Importerbara = Importerbara +Index = Index +Individuell = Individuell +Individuell resultatlista, alla lopp = Individuell resultatlista, alla lopp +Individuell resultatlista, sammanställning av flera lopp = Individuell resultatlista, sammanställning av flera lopp +Individuell resultatlista, visst lopp = Individuell resultatlista, visst lopp +Individuell resultatlista, visst lopp (STOR) = Individuell resultatlista, visst lopp (STOR) +Individuell startlista, visst lopp = Individuell startlista, visst lopp +Individuella deltagare = Individuella deltagare +Individuella slutresultat = Individuella slutresultat +Individuella totalresultat = Individuella totalresultat +Info = Info +Inga = Inga +Inga deltagare = Inga deltagare +Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning = Inga vakanser tillgängliga. Vakanser skapas vanligen vid lottning +Ingen = Ingen +Ingen bana = Ingen bana +Ingen deltagare matchar sökkriteriet = Ingen deltagare matchar sökkriteriet +Ingen klass = Ingen klass +Ingen klass vald = Ingen klass vald +Ingen löpare saknar bricka = Ingen löpare saknar bricka +Ingen matchar 'X' = Ingen matchar 'X' +Ingen rogaining = Ingen rogaining +Inkommande = Inkommande +Inläst bricka ställd i kö = Inläst bricka ställd i kö +Inlästa brickor = Inlästa brickor +Inmatning av mellantider = Inmatning av mellantider +Inspekterar klasser = Inspekterar klasser +Installera = Installera +Inställningar = Inställningar +Inställningar MeOS = Inställningar MeOS +Interaktiv inläsning = Interaktiv inläsning +Intervall = Intervall +Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras = Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras +Intervallet måste anges på formen MM:SS = Intervallet måste anges på formen MM:SS +Italic = Kursiv +ItalicMediumPlus = Kursiv, större storlek +Jag sköter lottning själv = Jag sköter lottning själv +Jaktstart = Jaktstart +Justera blockvis = Justera blockvis +Justera mot = Justera mot +Klart = Klart +Klart. Antal importerade: X = Klart. Antal importerade: X +Klart. X deltagare importerade = Klart. X deltagare importerade +Klart. X lag importerade = Klart. X lag importerade +Klart. X patruller importerade = Klart. X patruller importerade +Klart: alla klasser lottade = Klart: alla klasser lottade +Klart: inga klasser behövde lottas = Klart: inga klasser behövde lottas +Klass = Klass +Klass %d = Klass %d +Klass saknad = Klass saknad +Klass / klasstyp = Klass/klasstyp +Klass att slå ihop = Klass att slå ihop med +Klassbyte = Klassbyte +Klassen 'X' har jaktstart/växling på första sträckan = Klassen 'X' har jaktstart/växling på första sträckan +Klassen används och kan inte tas bort = Klassen används och kan inte tas bort +Klassen lottas inte, startstämpling = Klassen lottas inte, startstämpling +Klassen måste ha ett namn = Klassen måste ha ett namn +Klassens bana = Klassens bana +Klasser = Klasser +Klasser (IOF, xml) = Klasser (IOF, XML) +Klasser där nyanmälningar ska överföras = Klasser där nyanmälningar ska överföras +Klassinställningar = Klassinställningar +Klassnamn = Klassnamn +Klasstyp = Klasstyp +Klientnamn = Klientnamn +Klistra in = Klistra in +Klistra in data från urklipp (X) = Klistra in data från urklipp (X) +Klocktid: X = Klocktid: X +Klubb = Klubb +Klubb att ta bort = Klubb att ta bort +Klubb: X = Klubb: X +KlubbId = KlubbId +Klubbar = Klubbar +Klubbar (IOF, xml) = Klubbar (IOF, XML) +Klubbar som inte svarat = Klubbar som inte svarat +Klubbdatabasen = Klubbdatabasen +Klubblös = Klubblös +Klubbresultat = Klubbresultat +Klubbresultatlista = Klubbresultatlista +Klubbresultatlista - %s = Klubbresultat - %s +Klubbstartlista = Klubbstartlista +Klubbstartlista - %s = Klubbstartlista - %s +Klungstart = Klungstart +Knyt löpare till sträckan = Knyt löpare till sträckan +Knyt löparna till banor från en pool vid målgång = Knyt löparna till banor från en pool vid målgång +Kom ihåg listan = Kom ihåg listan +Kommentar / version = Kommentar/version +Kommunikation = Kommunikation +Kontant = Kontant +Kontant betalning = Kontant betalning +Konto = Konto +Kontroll = Kontroll +Kontroll %s = Kontroll %s +Kontroll X = Kontroll X +Kontroll inför tävlingen = Kontroll inför tävlingen +Kontrollen används och kan inte tas bort = Kontrollen används och kan inte tas bort +Kontrollens ID-nummer = Kontrollens ID-nummer +Kontroller = Kontroller +Kontrollnamn = Kontrollnamn +Kopia X = Kopia X +Kopiera länken till urklipp = Kopiera länken till urklipp +Kopiera selektionen till urklipp (X) = Kopiera selektionen till urklipp (X) +Koppla ifrån = Koppla ifrån +Koppla ner databas = Koppla ner databas +Kopplar ifrån SportIdent på = Kopplar ifrån SportIdent på +Kortast teoretiska startdjup utan krockar är X minuter = Kortast teoretiska startdjup utan krockar är X minuter +Kortnamn = Kortnamn +Kunde inte ansluta till Eventor = Kunde inte ansluta till Eventor +Kunde inte ladda upp tävlingen (X) = Kunde inte ladda upp tävlingen (X) +Kvar-i-skogen = Kvar-i-skogen +Kvinna = Kvinna +Kvinnor = Kvinnor +Källkatalog = Källkatalog +Kön = Kön +Kör kontroll inför tävlingen = Kör kontroll inför tävlingen +Ladda upp öppnad tävling på server = Ladda upp öppnad tävling på server +Lag = Lag +Lag %d = Lag %d +Lag(flera) = Lag +Laget 'X' saknar klass = Laget 'X' saknar klass +Laget hittades inte = Laget hittades inte +Lagnamn = Lagnamn +Lagrade säkerhetskopior = Lagrade säkerhetskopior +Land = Land +LargeFont = Stor text +Latitud = Latitud +Lista = Lista +Lista av typ 'X' = Lista av typ 'X' +Lista med mellantider = Lista med mellantider +Lista med sträcktider = Lista med sträcktider +Listan kan inte visas = Listan kan inte visas +Listegenskaper = Listegenskaper +Listnamn = Listnamn +Listor = Listor +Listor och sammanställningar = Listor och sammanställningar +Listpost = Listpost +Listredigerare = Listredigerare +Listredigerare – X = Listredigerare – X +Listrubrik = Listrubrik +Listtyp = Listtyp +Listval = Listval +Ljudfiler, baskatalog = Ljudfiler, baskatalog +Lokalt = Lokalt +Longitud = Longitud +Lopp %d = Lopp %d +Lopp %s = Lopp %s +Lopp X = Lopp X +Lotta = Lotta +Lotta / starttider = Lotta/starttider +Lotta flera klasser = Lotta flera klasser +Lotta klassen = Lotta klassen +Lotta klassen X = Lotta klassen 'X' +Lotta löpare som saknar starttid = Lotta löpare som saknar starttid +Lotta om hela klassen = Lotta om hela klassen +Lottad = Lottad +Lottad startlista = Lottad startlista +Lottar efteranmälda = Lottar efteranmälda +Lottar: X = Lottar: X +Lottning = Lottning +Lyssna = Lyssna +Lägg till = Lägg till +Lägg till alla = Lägg till alla +Lägg till en ny rad i tabellen (X) = Lägg till en ny rad i tabellen (X) +Lägg till klasser = Lägg till/uppdatera klasser +Lägg till ny = Lägg till ny +Lägg till ny etapp = Lägg till ny etapp +Lägg till rad = Lägg till rad +Lägg till stämpling = Lägg till stämpling +Lägger till klubbar = Lägger till klubbar +Lägger till löpare = Lägger till löpare +Längd (m) = Längd (m) +Länk till resultatlistan = Länk till resultatlistan +Länk till startlistan = Länk till startlistan +Läs brickor = Läs brickor +Läser klubbar = Läser klubbar +Läser löpare = Läser löpare +Långt namn = Långt namn +Låt klassen ha mer än en bana eller sträcka = Låt klassen ha mer än en bana eller sträcka +Löpande information om viktiga händelser i tävlingen = Löpande information om viktiga händelser i tävlingen +Löparbricka %d = Löparbricka %d +Löpardatabasen = Löpardatabasen +Löpare = Löpare +Löpare saknar klass eller bana = Löpare saknar klass eller bana +Löpare som förekommer i mer än ett lag = Löpare som förekommer i mer än ett lag +Löpare utan SI-bricka: %d = Löpare utan SI-bricka: %d +Löpare utan bana: %d = Löpare utan bana: %d +Löpare utan klass: %d = Löpare utan klass: %d +Löpare utan klubb: %d = Löpare utan klubb: %d +Löpare utan starttid: %d = Löpare utan starttid: %d +Löpare, Ej Start, med registrering (kvar-i-skogen!?) = Löpare, Ej Start, med registrering (kvar-i-skogen!?) +Löpare, Status Okänd, med registrering (kvar-i-skogen) = Löpare, Status Okänd, med registrering (kvar-i-skogen) +Löpare, Status Okänd, som saknar registrering = Löpare, Status Okänd, som saknar registrering +Löpare: = Löpare: +Löpare: X, kontroll: Y, kl Z = Löpare: X, kontroll: Y, kl: Z +Löparen hittades inte = Löparen hittades inte +Löptid = Löptid +Lösenord = Lösenord +Man = Man +Manuell lottning = Manuell lottning +Manuella avgifter = Manuella avgifter +Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar = Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar +Mata in radiotider manuellt = Mata in radiotider manuellt +Max antal gemensamma kontroller = Max antal gemensamma kontroller +Max parallellt startande = Max antal parallellt startande +Max. vakanser (per klass) = Max. vakanser (per klass) +Maximal tid efter ledaren för att delta i jaktstart = Maximal tid efter ledaren för att delta i jaktstart +Maxtid = Maxtid +Maxtid efter = Maxtid efter +MeOS = MeOS +MeOS lokala datakatalog är = MeOS lokala datakatalog är +MeOS – Resultatkiosk = MeOS – Resultatkiosk +Med stafettklasser = Med stafettklasser +Med sträcktidsanalys = Med sträcktidsanalys +MediumFont = Medelstor text +MediumPlus = Något större text +Medlöpare = Medlöpare +Mellantider visas för namngivna kontroller = Mellantider visas för namngivna kontroller +Metod = Metod +Min. vakanser (per klass) = Min. vakanser (per klass) +Minitid = Minitid +Minst MySQL X krävs. Du använder version Y = Minst MySQL X krävs. Du använder version Y +Minsta intabbning = Minsta indrag +Minsta intervall i klass = Minsta intervall i klass +Minsta startintervall = Minsta startintervall +Minsta sträcktid = Minsta sträcktid +Minutstartlista = Minutstartlista +Motion = Motion +Multipel = Multipel +MySQL Server / IP-adress = MySQL Server/IP-adress +Män = Män +Mål = Mål +Målstämpling saknas = Målstämpling saknas +Måltid = Måltid +Måltid saknas = Måltid saknas +Måltid: X = Måltid: X +Namn = Namn +Nationalitet = Nationalitet +Nollställ avgifter = Nollställ avgifter +Nollställ databaser = Nollställ databaser +Nollställde avgift för X deltagare = Nollställde avgift för X deltagare +Nolltid = Nolltid +None = Ingen +Normal = Normal +NormalFont = Normal text +Normalavgift = Normalavgift +Not implemented = Funktionen saknas +Nr = Nr +Nummerlapp = Nummerlapp +Nummerlappar = Nummerlappar +Nummerlappar i X = Nummerlappar i X +Nuvarande innehavare: X = Nuvarande innehavare: X +Ny bana = Ny bana +Ny deltagare = Ny deltagare +Ny klass = Ny klass +Ny klubb = Ny klubb +Ny kontroll = Ny kontroll +Ny lista = Ny lista +Ny tävling = Ny tävling +Nyckel för Eventor = Nyckel för Eventor +Nytt fönster = Nytt fönster +Nytt lag = Nytt lag +Nästa = Nästa +Nästa etapp = Nästa etapp +Nästa försök = Nästa försök +OE Semikolonseparerad (csv) = OE Semikolonseparerad (CSV) +OK = OK +Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y' = Ogiltig banfil. Kontrollnummer förväntades på position X, men hittade 'Y' +Ogiltig föregående/efterföljande etapp = Ogiltig föregående/efterföljande etapp +Ogiltig första starttid. Måste vara efter nolltid = Ogiltig första starttid. Måste vara efter nolltid +Ogiltig omstartstid = Ogiltig omstartstid +Ogiltig repdragningstid = Ogiltig repdragningstid +Ogiltig starttid i 'X' på sträcka Y = Ogiltig starttid i 'X' på sträcka Y +Ogiltig starttid: X = Ogiltig starttid: X +Ogiltig tid = Ogiltig tid +Ogiltigt bricknummer X = Ogiltigt bricknummer X +Ogiltigt filformat = Ogiltigt filformat. +Okänd bricka = Okänd bricka +Okänd funktion = Okänd funktion +Okänd klass = Okänd klass +Okänd klubb med id X = Okänd klubb med id X +Om MeOS = Om MeOS +Om MeOS – ett Mycket Enkelt OrienteringsSystem = Om MeOS – ett Mycket Enkelt OrienteringsSystem +Omstart = Omstart +Omstart i stafettklasser = Omstart i stafettklasser +Omstartstid = Omstartstid +Omvänd jaktstart = Omvänd jaktstart +Oparad = Oparad +Operationen misslyckades = Operationen misslyckades +Operationen stöds ej = Operationen stöds ej +Optimerar startfördelning = Optimerar startfördelning +Ordinarie anmälningsdatum = Ordinarie anmälningsdatum +Ordinarie avgift = Ordinarie avgift +Organisation = Organisation +Oväntad kontroll 'X' i bana Y = Oväntad kontroll 'X' i bana Y +Packar upp löpardatabas = Packar upp löpardatabas +Par- eller singelklass = Par- eller singelklass +Para ihop = Para ihop +Para ihop bricka X med en deltagare = Para ihop bricka X med en deltagare +Parallell = Parallell +PatrolClubNameNames = Deltagares (eller patrulls) klubb(ar) +PatrolNameNames = Deltagares (eller patrulls) namn +Patrull = Patrull +Patrull, 1 SI-pinne = Patrull, 1 SI-pinne +Patrull, 2 SI-pinnar = Patrull, 2 SI-pinnar +Personer = Personer +Plac = Plac +Placering in = Placering in +Plats = Plats +Port = Port +Port för TCP = Port för TCP +Postadress = Postadress +Postkod = Postkod +Poäng = Poäng +Poäng in = Poäng in +Poängavdrag (per minut) = Poängavdrag (per minut) +Poängavdrag per påbörjad minut = Poängavdrag per påbörjad minut +Poänggräns = Poänggräns +Prel. bomtid = Prel. bomtid +Prel. placering = Prel. placering +Prioritering = Prioritering +Prisutdelningslista = Prisutdelningslista +Programinställningar = Programinställningar +Prolog + jaktstart = Prolog + jaktstart +Publicera resultat = Publicera resultat +Publicera resultat och sträcktider på Eventor och WinSplits online = Publicera resultat och sträcktider på Eventor och WinSplits online +Publicera startlista = Publicera startlista +Publicera startlistan på Eventor = Publicera startlistan på Eventor +Publicerar resultat = Publicerar resultat +Publicerar startlistan = Publicerar startlistan +PunchNamedTime = Namngiven mellantid +PunchTime = Stämplingstid +Punches = Stämplingar +Radera = Radera +Radera listan från aktuell tävling = Radera listan från aktuell tävling +Radera starttider = Radera starttider +Radera tävlingen = Radera tävlingen +Radera vakanser = Radera vakanser +Radiotider, kontroll = Radiotider, kontroll +Ranking = Ranking +Ranking (IOF, xml) = Ranking (IOF, xml) +Rapport inför = Rapport inför +Rapporter = Rapporter +Rapportläge = Rapportläge +Red. avg. efteranm = Red. avg. efteranm +Red. avgift = Red. avgift +Redigera deltagaren = Redigera deltagaren +Redigera lista = Redigera lista +Redigera listpost = Redigera listpost +Reducerad avg = Reducerad avg +Reduktionsmetod = Reduktionsmetod +Region = Distrikt +Relativ skalfaktor för typsnittets storlek i procent = Relativ skalfaktor för typsnittets storlek i procent +Rep = Rep +Reparera vald tävling = Reparera vald tävling +Reparerar tävlingsdatabasen = Reparerar tävlingsdatabasen +Repdragningstid = Repdragningstid +Repdragningstiden måste ligga före omstartstiden = Repdragningstiden måste ligga före omstartstiden +Reserverade = Reserverade +Resultat = Resultat +Resultat && sträcktider = Resultat && sträcktider +Resultat (STOR) = Resultat (STOR) +Resultat - %s = Resultat - %s +Resultat - X = Resultat - X +Resultat banvis per klass = Resultat banvis per klass +Resultat efter klass och bana - X = Resultat efter klass och bana - X +Resultat efter sträcka X = Resultat efter sträcka X +Resultat efter sträckan = Resultat efter sträckan +Resultat för ett visst lopp = Resultat för ett visst lopp +Resultat lopp X - Y = Resultat lopp X - Y +Resultat per bana = Resultat per bana +Resultat per bana - X = Resultat per bana - X +Resultat, generell = Resultat, generell +Resultat, individuell = Resultat, individuell +Resultat, patrull = Resultat, patrull +Resultatkiosk = Resultatkiosk +Resultatlista - %s = Resultatlista - %s +Resultatlista – inställningar = Resultatlista – inställningar +Resultatlistor = Resultatlistor +Resultatutskrift = Resultatutskrift +Resultatutskrift / export = Resultatutskrift/export +Rogaining = Rogaining +Rogaining, individuell = Rogaining, individuell +Rogaining-poäng = Rogaining-poäng +RogainingPunch = Stämpling, rogaining +Rubrik = Rubrik +Rulla upp och ner automatiskt = Rulla upp och ner automatiskt +Runner = Deltagare +RunnerBib = Nummerlapp, deltagare +RunnerCard = Bricknummer +RunnerClassCoursePlace = Placering på bana inom klass +RunnerClassCourseTimeAfter = Tid efter på bana inom klass +RunnerClub = Deltagarklubb +RunnerCompleteName = Fullständigt namn +RunnerCourse = Deltagares bana +RunnerFamilyName = Efternamn +RunnerFinish = Deltagares måltid +RunnerGivenName = Förnamn +RunnerLegNumberAlpha = Deltagares exakta sträcknummer +RunnerLegNumber = Deltagares grupperade sträcknummer +RunnerName = Deltagarnamn +RunnerPlace = Deltagares placering +RunnerPlaceDiff = Deltagares placeringsförändring +RunnerRank = Ranking +RunnerRogainingPoint = Rogainingpoäng +RunnerStart = Deltagares starttid +RunnerStartNo = Deltagares startnummer +RunnerTempTimeAfter = Deltagares tid efter vid speciell kontroll +RunnerTempTimeStatus = Deltagares tid/status vid speciell kontroll +RunnerTime = Deltagares tid +RunnerTimeAfter = Deltagares tid efter +RunnerTimeAfterDiff = Deltagares tid-efter-förändring +RunnerTimeLost = Deltagares bomtid +RunnerTimePlaceFixed = Tidpunkt när placering fastställs +RunnerTimeStatus = Deltagares tid/status +RunnerTotalPlace = Deltagares totalplacering +RunnerTotalTime = Deltagares totaltid +RunnerTotalTimeAfter = Deltagares totala tid efter +RunnerTotalTimeStatus = Deltagares totala tid/status +RunnerUMMasterPoint = Uppsala möte, mästarpoäng +SI X inläst. Brickan tillhör Y som saknar klass = SI X inläst. Brickan tillhör Y som saknar klass +SI X inläst. Brickan är inte knuten till någon löpare (i skogen) = SI X inläst. Brickan är inte knuten till någon löpare (i skogen) +SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen = SI X är redan inläst. Använd interaktiv inläsning om du vill läsa brickan igen +SI X är redan inläst. Ska den läsas in igen? = SI X är redan inläst. Ska den läsas in igen? +SI på = SI på +SI-dubbletter: %d = SI-dubbletter: %d +SOFT-avgift = SOFT-avgift +SOFT-lottning = SOFT-lottning +Saknad starttid = Saknad starttid +Sammanställning = Sammanställning +Sammanställning, ekonomi = Sammanställning, ekonomi +Sammanställning, klasser = Sammanställning, klasser +Samtliga deltagare tilldelades resultat = Samtliga deltagare tilldelades resultat +Seedad lottning = Seedad lottning +Sekundär typ = Sekundär typ +Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? = Selektionens storlek matchar inte urklippets storlek. Klistra in i alla fall? +Semikolonseparerad (csv) = Semikolonseparerad (CSV) +Sen avgift = Sen avgift +Sen red. avgift = Sen red. avgift +Server = Server +Server: [X] Y = Server: [X] Y +Sidbrytning mellan klasser = Sidbrytning mellan klasser +Sidbrytning mellan klasser / klubbar = Sidbrytning mellan klasser/klubbar +Simulera inläsning av stämplar = Simulera inläsning av stämplingar +Sista betalningsdatum = Sista betalningsdatum +Sista ordinarie anmälningsdatum = Sista ordinarie anmälningsdatum +Sista start (nu tilldelad) = Sista start (nu tilldelad) +Sista start (nu tilldelad): X = Sista start (nu tilldelad): X +Sista sträckan = Sista sträckan +Ska X raderas från tävlingen? = Ska X raderas från tävlingen? +Skalfaktor = Skalfaktor +Skapa en ny tävling med data från Eventor = Skapa en ny tävling med data från Eventor +Skapa en ny, tom, tävling = Skapa en ny, tom, tävling +Skapa fakturor = Skapa fakturor +Skapa generell lista = Skapa generell lista +Skapa listan = Skapa listan +Skapa ny klass = Skapa ny klass +Skapad av = Skapad av +Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) = Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d) +Skapade en lokal kopia av tävlingen = Skapade en lokal kopia av tävlingen +Skapar ny etapp = Skapar ny etapp +Skapar ny tävling = Skapar ny tävling +Skapar saknad klass = Skapar saknad klass +Skattad avgift = Skattad avgift +Skippar lottning = Skippar lottning +Skript = Skript +Skript att köra efter export = Skript att köra efter export +Skriv endast ut ändade sidor = Skriv endast ut ändrade sidor +Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben = Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben +Skriv första starttid på formen HH:MM:SS = Skriv första starttid på formen HH:MM:SS +Skriv ut = Skriv ut +Skriv ut alla = Skriv ut alla +Skriv ut dem utan e-post = Skriv ut dem utan e-post +Skriv ut ej accepterade elektroniska = Skriv ut ej accepterade elektroniska +Skriv ut eller exportera listan automatiskt = Skriv ut eller exportera listan automatiskt +Skriv ut fakturan = Skriv ut fakturan +Skriv ut listan = Skriv ut listan +Skriv ut nu = Skriv ut nu +Skriv ut rapporten = Skriv ut rapporten +Skriv ut sträcktider = Skriv ut sträcktider +Skriv ut tabellen = Skriv ut tabellen +Skriv ut tabellen (X) = Skriv ut tabellen (X) +Skriv över existerande bricknummer? = Skriv över existerande bricknummer? +Skrivare = Skrivare +Skrivarinställningar för sträcktider = Skrivarinställningar för sträcktider +Skriver sträcktider om = Skriver sträcktider om +Slutresultat = Slutresultat +Slå ihop = Slå ihop +Slå ihop klass: X = Slå ihop klass: X +Slå ihop klass: X (denna klass behålls) = Slå ihop klass med X (denna klass behålls) +Slå ihop klasser = Slå ihop klasser +Slå ihop klubb = Slå ihop klubb +SmallFont = Liten text +SmallItalic = Liten kursiv text +Snabbinställningar = Snabbinställningar +SortNameOnly = Namn +Sortering = Sortering +Sortering: %s, antal rader: %d = Sortering: %s, antal rader: %d +Spara = Spara +Spara anmälningar = Spara anmälningar +Spara den här listan som en favoritlista = Spara den här listan som en favoritlista +Spara fil = Spara fil +Spara för webben = Spara för webben +Spara i aktuell tävling = Spara i aktuell tävling +Spara som = Spara som +Spara som fil = Spara som fil +Spara sträcktider till en fil för automatisk synkronisering med WinSplits = Spara sträcktider till en fil för automatisk synkronisering med WinSplits +Sparade listval = Sparade listval +Speaker = Speaker +Speakerstöd = Speakerstöd +SportIdent = SportIdent +Språk = Språk +Stad = Stad +Stafett = Stafett +Stafett (sammanställning) = Stafett (sammanställning) +Stafett - sammanställning = Stafett - sammanställning +Stafett - sträcka = Stafett - sträcka +Stafett - total = Stafett - total +Stafettklasser = Stafettklasser +Stafettresultat, delsträckor = Stafettresultat, delsträckor +Stafettresultat, lag = Stafettresultat, lag +Stafettresultat, sträcka = Stafettresultat, sträcka +Stafettresultat, sträcka (STOR) = Stafettresultat, sträcka (STOR) +Start = Start +Start nr = Start nr +StartTime = Starttid, namn +StartTimeForClass = Gemensam starttid, klass +Starta = Starta +Starta automaten = Starta automaten +Starta en guide som hjälper dig göra klassinställningar = Starta en guide som hjälper dig göra klassinställningar +Startade automater = Startade automater +Startande = Startande +Startar SI på = Startar SI på +Startblock = Startblock +Startblock: %d = Startblock: %d +Startintervall = Startintervall +Startintervall (min) = Startintervall (min) +Startlista = Startlista +Startlista %%s - sträcka %d = Startlista %%s - sträcka %d +Startlista - %s = Startlista - %s +Startlista - X = Startlista - X +Startlista ett visst lopp = Startlista för ett visst lopp +Startlista lopp X - Y = Startlista lopp X - Y +Startlista, individuell = Startlista, individuell +Startlista, patrull = Startlista, patrull +Startlista, stafett (lag) = Startlista, stafett (lag) +Startlista, stafett (sträcka) = Startlista, stafett (sträcka) +Startlistor = Startlistor +Startmetod = Startmetod +Startnamn = Startnamn +Startnummer = Startnummer +Starttid = Starttid +Starttid (HH:MM:SS) = Starttid (HH:MM:SS) +Starttid: X = Starttid: X +Starttiden är upptagen = Starttiden är upptagen +Starttyp = Starttyp +Status = Status +Status OK = Status OK +Status in = Status in +Stoppa automaten = Stoppa automaten +Stor = Stor +Str = Str +Str. %d = Str. %d +String = Text +Struken = Struken +Struken med återbetalning = Struken med återbetalning +Struken utan återbetalning = Struken utan återbetalning +Strukturerat exportformat = Strukturerat exportformat +Strukturerat webbdokument (html) = Strukturerat webbdokument (html) +Sträcka = Sträcka +Sträcka %d = Sträcka %d +Sträcka X = Sträcka X +Sträcka att lotta = Sträcka att lotta +Sträckans banor = Sträckans banor +Sträcktider = Sträcktider +Sträcktider (WinSplits) = Sträcktider (WinSplits) +Sträcktider / WinSplits = Sträcktider/WinSplits +Sträcktider/WinSplits = Sträcktider/WinSplits +Sträcktidsfil = Sträcktidsfil +Sträcktidsutskrift = Sträcktidsutskrift +Sträcktidsutskrift[check] = Automatisk sträcktidsutskrift +Sträcktilldelning, stafett = Sträcktilldelning, stafett +Sträcktyp = Sträcktyp +Stämpelkod(er) = Stämpelkod(er) +Stämpelkoder = Stämplingskoder +Stämplar om = Stämplar om +Stämplingar = Stämplingar +Stämplingar saknas: X = Stämplingar saknas: X +Stämplingsautomat = Stämplingsautomat +Stämplingsintervall (MM:SS) = Stämplingsintervall (MM:SS) +Stämplingstest = Stämplingstest +Stämplingstest [!] = Stämplingstest [!] +Stäng = Stäng +Stäng tävlingen = Stäng tävlingen +Större = Större +Störst = Störst +Största gruppen med samma inledning har X platser = Största gruppen med samma inledning har X platser +Största intervall i klass = Största intervall i klass +SubCounter = Sekundär räknare +SubSubCounter = Tertiär räknare +Summera = Summera +Synkronisera med Eventor = Synkronisera med Eventor +Säkerhetskopiera = Säkerhetskopiera +Sätt okända löpare utan registrering till = Sätt okända löpare utan registrering till +Sätt som oparad = Sätt som oparad +Sätter reptid (X) och omstartstid (Y) för = Sätter reptid (X) och omstartstid (Y) för +Sök = Sök +Sök (X) = Sök (X) +Sök deltagare = Sök deltagare +Sök och starta automatiskt = Sök och starta automatiskt +Sök på namn, bricka eller startnummer = Sök på namn, bricka eller startnummer +Söker efter SI-enheter = Söker efter SI-enheter +TCP: Port %d, Nolltid: %s = TCP: Port %d, Nolltid: %s +TRASIG( = TRASIG( +Ta bort = Ta bort +Ta bort / slå ihop = Ta bort/slå ihop +Ta bort listposten = Ta bort listposten +Ta bort markerad = Ta bort markerad +Ta bort stämpling = Ta bort stämpling +Ta bort valda rader från tabellen (X) = Ta bort valda rader från tabellen (X) +Tabellverktyg = Tabellverktyg +Tabelläge = Tabelläge +Team = Lag +TeamBib = Lags nummerlapp +TeamClub = Lags klubb +TeamLegTimeAfter = Lags tid efter på sträcka +TeamLegTimeStatus = Lags tid/status på sträcka +TeamName = Lagnamn +TeamPlace = Lagplacering +TeamRogainingPoint = Lags rogainingpoäng +TeamRunner = Lags deltagares namn +TeamRunnerCard = Lags deltagares bricknummer +TeamStart = Lags starttid +TeamStartNo = Lags startnummer +TeamStatus = Lags status +TeamTime = Lags tid +TeamTimeAfter = Lags tid efter +TeamTimeStatus = Lags tid/status +Telefon = Telefon +Test = Test +Test av stämplingsinläsningar = Test av stämplingsinläsningar +Testa rösten = Testa rösten +Text = Text +Text: X = Text: X +Textfiler = Textfiler +Textstorlek = Textstorlek +Tid = Tid +Tid efter: X = Tid efter: X +Tid efter: X; har tagit in Y = Tid efter: X; har tagit in Y +Tid efter: X; har tappat Y = Tid efter: X; har tappat Y +Tid in = Tid in +Tid: X, nuvarande placering Y/Z = Tid: X, nuvarande placering Y/Z +Tidsavdrag: X poäng = Tidsavdrag: X poäng +Tidsgräns = Tidsgräns +Tidsinmatning = Tidsinmatning +Tidsintervall (MM:SS) = Tidsintervall (MM:SS) +Tidsjustering = Tidsjustering +Tidslinje – X = Tidslinje – X +Tidsskalning = Tidsskalning +Till huvudsidan = Till huvudsidan +Till kontroll = Till kontroll +Tilldela = Tilldela +Tilldela avgifter = Tilldela avgifter +Tilldela endast avgift till deltagare utan avgift = Tilldela endast avgift till deltagare utan avgift +Tilldela hyrbrickor = Tilldela hyrbrickor +Tilldela nummerlappar = Tilldela nummerlappar +Tilldelning av hyrbrickor = Tilldelning av hyrbrickor +Tillgängliga automater = Tillgängliga automater +Tillsatte vakans = Tillsatte vakans +Tillsätt vakans = Tillsätt vakans +Tillämpa parstart = Tillämpa parstart +Tillåt decimaler = Tillåt decimaler +Tillåt direktanmälan = Tillåt direktanmälan +Tillåt valutauttryck med decimaler = Tillåt valutauttryck med decimaler +Topplista, N bästa = Topplista, N bästa +Total = Total +Total tävlingsavgift = Total tävlingsavgift +TotalCounter = Primär räknare +Totalresultat = Totalresultat +Totalresultat - X = Totalresultat - X +Totalt = Totalt +Totalt faktureras = Totalt faktureras +Totalt kontant = Totalt kontant +Totaltid = Totaltid +Trasig = Trasig +Träning = Träning +Tvåmannastafett = Tvåmannastafett +Typ = Typ +Typ av delning = Typ av delning +Typ av export = Typ av export +Typ av lista = Typ av lista +Typsnitt = Typsnitt +Tävling = Tävling +Tävling från Eventor = Tävling från Eventor +Tävlingen innehåller inga resultat = Tävlingen innehåller inga resultat +Tävlingen måste ha ett namn = Tävlingen måste ha ett namn +Tävlingens namn: X = Tävlingens namn: X +Tävlingsdata har sparats = Tävlingsdata har sparats +Tävlingsinställningar = Tävlingsinställningar +Tävlingsinställningar (IOF, xml) = Tävlingsinställningar (IOF, XML) +Tävlingsnamn = Tävlingsnamn +Tävlingsrapport = Tävlingsrapport +Tävlingsregler = Tävlingsregler +Tävlingsstatistik = Tävlingsstatistik +Underlag för tävlingsavgift = Underlag för tävlingsavgift +Underlista = Underlista +Underrubrik = Underrubrik +Undre datumgräns = Undre datumgräns +Undre gräns (år) = Undre gräns (år) +Undre ålder = Undre ålder +Ungdom = Ungdom +Ungdomsavgift = Ungdomsavgift +Ungdomsklasser = Ungdomsklasser +Uppdatera = Uppdatera +Uppdatera alla klubbar = Uppdatera alla klubbar +Uppdatera alla värden i tabellen = Uppdatera alla värden i tabellen +Uppdatera alla värden i tabellen (X) = Uppdatera alla värden i tabellen (X) +Uppdatera från Eventor = Uppdatera från Eventor +Uppdatera fördelning = Uppdatera fördelning +Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan = Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan +Uppdatera klubbar && löpare = Uppdatera klubbar && löpare +Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret = Uppdatera klubbarnas och löparnas uppgifter med data från löpardatabasen/distriktsregistret +Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret = Uppdatera klubbarnas uppgifter med data från löpardatabasen/distriktsregistret +Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret = Uppdatera klubbens uppgifter med data från löpardatabasen/distriktsregistret +Uppdatera löpardatabasen = Uppdatera löpardatabasen +Urval = Urval +Urval %c%s = Urval %c%s +Utan inställningar = Utan inställningar +Utan tidtagning = Utan tidtagning +Utbyt tävlingsdata med Eventor = Utbyt tävlingsdata med Eventor +Utför lottning = Utför lottning +Utfört = Utfört +Utg = Utg +Utskrift / export = Utskrift/export +Utskriftsintervall (MM:SS) = Utskriftsintervall (MM:SS) +Utökat protokoll = Utökat protokoll +VALFRI( = VALFRI( +Vak. ranking = Vak. ranking +Vakanser = Vakanser +Vakanser / klassbyte = Vakanser/klassbyte +Vakanser och efteranmälda = Vakanser och efteranmälda +Vakanser stöds ej i stafett = Vakanser stöds ej i stafett +Vakant = Vakant +Val av export = Val av export +Valbar = Valbar +Vald bricka = Vald bricka +Valuta = Valuta +Valutakod = Valutakod +Valutasymbol = Valutasymbol +Valutasymbol före = Valutasymbol före +Varning: Deltagaren 'X' finns inte = Varning: Deltagaren 'X' finns inte +Varning: Laget 'X' finns inte = Varning: Laget 'X' finns inte +Varning: Banan 'X' finns inte = Varning: Banan 'X' finns inte +Varning: Banan 'X' förekommer flera gånger = Varning: Banan 'X' förekommer flera gånger +Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) = Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar) +Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Varning: Inget kontonummer angivet (Se tävlingsinställningar) +Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) = Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) +Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' +Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' +Verkställ = Verkställ +Version X = Version X +Vi stöder MeOS = Vi stöder MeOS +Viktiga händelser = Viktiga händelser +Vill du flytta löpare från X till Y och ta bort Z? = Vill du flytta löpare från X till Y och ta bort Z? +Vill du klistra in X nya rader i tabellen? = Vill du klistra in X nya rader i tabellen? +Vill du lägga till banan 'X' (Y)? = Vill du lägga till banan 'X' (Y)? +Vill du lägga till deltagaren 'X'? = Vill du lägga till deltagaren 'X'? +Vill du lägga till klassen 'X'? = Vill du lägga till klassen 'X'? +Vill du lägga till laget 'X'? = Vill du lägga till laget 'X'? +Vill du radera X rader från tabellen? = Vill du radera X rader från tabellen? +Vill du radera alla vakanser från tävlingen? = Vill du radera alla vakanser från tävlingen? +Vill du skapa en ny klass? = Vill du skapa en ny klass? +Vill du spara ändringar? = Vill du spara ändringar? +Vill du verkligen radera alla starttider i X? = Vill du verkligen radera alla starttider i X? +Vill du verkligen radera starttider i X klasser? = Vill du verkligen radera starttider i X klasser? +Vill du verkligen radera tävlingen? = Vill du verkligen radera tävlingen? +Vill du verkligen stänga MeOS? = Vill du verkligen stänga MeOS? +Vill du verkligen ta bort laget? = Vill du verkligen ta bort laget? +Vill du verkligen ta bort löparen? = Vill du verkligen ta bort löparen? +Visa = Visa +Visa alla = Visa alla +Visa avancerade funktioner = Visa avancerade funktioner +Visa en tabell över alla stämplingar = Visa en tabell över alla stämplingar +Visa klubbdatabasen = Visa klubbdatabasen +Visa listan i fullskärm = Visa listan i fullskärm +Visa löpardatabasen = Visa löpardatabasen +Visa mellantider = Visa mellantider +Visa och hantera löpardatabasen = Visa och hantera löpardatabasen +Visa senast inlästa deltagare = Visa senast inlästa deltagare +Visa startlistan = Visa startlistan +Visa tillgängliga säkerhetskopior = Visa tillgängliga säkerhetskopior +Visa valda deltagare = Visa valda deltagare +Visar de X bästa = Visar de X bästa +Visualisera startfältet = Visualisera startfältet +Vuxen = Vuxen +Vuxenklasser = Vuxenklasser +Vuxna = Vuxna +Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad = Välj Spara för att lagra brickorna. Interaktiv inläsning är INTE aktiverad +Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad = Välj Spara för att lagra brickorna. Interaktiv inläsning är aktiverad +Välj alla = Välj alla +Välj alla klasser = Välj alla klasser +Välj allt = Välj allt +Välj automatiskt = Välj automatiskt +Välj den etapp som föregår denna tävling = Välj den etapp som föregår denna tävling +Välj den etapp som kommer efter denna tävling = Välj den etapp som kommer efter denna tävling +Välj en vakant plats nedan = Välj en vakant plats nedan +Välj ingen = Välj ingen +Välj inget = Välj inget +Välj klass = Välj klass +Välj klass och starttid nedan = Välj klass och starttid nedan +Välj klasser = Välj klasser +Välj klasser där alla löpare saknar starttid = Välj klasser där alla löpare saknar starttid +Välj klasser där någon löpare saknar starttid = Välj klasser där någon löpare saknar starttid +Välj kolumner = Välj kolumner +Välj kolumner att visa = Välj kolumner att visa +Välj kolumner för tabellen X = Välj kolumner för tabellen X +Välj lista = Välj lista +Välj lopp = Välj lopp +Välj löpare = Välj löpare +Välj löpare att prioritera bevakning för = Välj löpare att prioritera bevakning för +Välj löpare för sträcka X = Välj löpare för sträcka X +Välj skrivare = Välj skrivare +Välj tävling = Välj tävling +Välj vilka klasser och kontroller du vill bevaka = Välj vilka klasser och kontroller du vill bevaka +Välj vilka klasser och kontroller som bevakas = Välj vilka klasser och kontroller som bevakas +Välj vilka kolumner du vill visa = Välj vilka kolumner du vill visa +Välj vy = Välj vy +Välkommen till MeOS = Välkommen till MeOS +Vänligen betala senast = Vänligen betala senast +Vänligen återlämna hyrbrickan = Vänligen återlämna hyrbrickan +Växling = Växling +Webb = Webb +Webbdokument = Webbdokument +Webbdokument (html) = Webbdokument (html) +Webben (html) = Webben (html) +X (Saknar e-post) = X (Saknar e-post) +X (Y deltagare, grupp Z, W) = X (Y deltagare, grupp Z, W) +X har startat = X har startat +X kontroller = X kontroller +X meter = X meter +X poäng fattas = X poäng fattas +X rader kunde inte raderas = X rad(er) kunde inte raderas +X senaste = X senaste +X: Y. Tryck för att spara = X: Y. Tryck för att spara +Zooma in (Ctrl + '+') = Zooma in (Ctrl + '+') +Zooma ut (Ctrl + '-') = Zooma ut (Ctrl + '-') +[Bevaka] = [Bevaka] +[Bort] = [Bort] +[Klassens bana] = [Klassens bana] +[Uppdaterad anmälan] = [Uppdaterad anmälan] +[VARNING] ingen/okänd = [VARNING] ingen/okänd +[Återställ] = [Återställ] +[Flytta ner] = [Flytta ner] +andra = andra +ask:addpunches = Ingen bricka har lästs in för denna löpare. Vill du lägga till stämplingar manuellt? +ask:changedclassfee = Anmälningsavgiften har ändrats i vissa klasser. Vill du tillämpa de nya avgifterna på befintliga löpare i dessa klasser?\n\nVarning: Manuellt inmatade avgifter kommer att skrivas över. +ask:changedcmpfee = Anmälningsavgiften har ändrats. Vill du tillämpa de nya avgifterna på befintliga klasser och löpare?\n\nVarning: Manuellt inmatade avgifter kommer att skrivas över. +ask:firstasstart = Banan har redan deltagare med resultat. Om du använder första kontrollen som start kommer befintliga starttider att skrivas över.\n\nVill du fortsätta? +ask:kiosk = Om du startar en resultatkiosk hamnar MeOS i ett läge där det endast är möjligt att visa resultatrapporter. Inga andra operationer tillåts förrän programmet startats om. Om du har en aktiverad SI-enhet kopplad till datorn visar MeOS automatiskt resultat för senast inlästa bricka.\n\nDu bör överväga att lösenordsskydda databasen om du fritt exponerar en resultatkiosk.\n\nVill du starta en resultatkiosk? +ask:missingcourse = Vissa klasser (X) saknar bana.\n\nMeOS använder banorna vid lottning för att undvika att löpare med liknande inledning på banan startar samtidigt.\n\nVill du lotta i alla fall? +ask:overwrite_server = Tävlingen finns redan på servern. Vill du skriva över tävlingen på servern med denna? +ask:overwriteconfirm = Du har valt att skriva över tävlingen. Se till att ingen annan är ansluten.\n\nVill du fortsätta? +ask:repair = Reparera databasen endast om du har problem med den.\n\nViktigt:\n- Se till att ingen annan är uppkopplad mot databasen.\n- Om servern kraschar eller stängs av medan reparation pågår måste du omedelbart försöka en reparation till efter omstart. Om du gör någon annan operation dessförinnan går all data förlorad.\n\nVill du fortsätta? +backup = backup +c/o = c/o +check (X) = check (X) +ej aktiv = ej aktiv +elfte = elfte +elva = elva +ett Mycket Enkelt OrienteringsSystem = ett Mycket Enkelt OrienteringsSystem +eventor:help = Om du använder MeOS för orienteringsarrangemang i Sverige, rekommenderar vi att du använder MeOS:s Eventorkoppling. +eventor:question = X\n\nVill du använda MeOS Eventorkoppling? +femma = femma +femte = femte +fjärde = fjärde +fritt att använda och du är välkommen att distribuera det under vissa villkor = fritt att använda och du är välkommen att distribuera det under vissa villkor +fyra = fyra +går i mål på X plats med tiden Y = går i mål på X plats med tiden Y +går i mål på X plats, efter Y, på tiden Z = går i mål på X plats, efter Y, på tiden Z +går upp i delad ledning med tiden X = går upp i delad ledning med tiden X +handskakning = handskakning +har startat = har startat +help:10000 = En automat i MeOS är ett litet program som automatiskt gör någonting med jämna mellanrum eller när tävlingsdata förändras. +help:12138 = Välj en klass att slå ihop vald klass med. Om klasserna är lottade bör de lottas om, eftersom löparna behåller sin starttid +help:12290 = Den valda tävlingen är skapad av en annan version av MeOS och kan inte öppnas från servern. Den kan vid behov importeras från fil. +help:12352 = Den här operationen tar bort den klubb du nyss valde (%s, id=%d) och flyttar alla klubbens löpare den nya klubb du väljer nedan. Operationen kan inte ångras. +help:12662 = Lägg till kontroller genom att ange en följd av kontrollnummer (id-nummer). Målet behöver inte anges. Exempel: 31, 50, 33, 36, 50, 37, 100. +help:14070 = TCP-porten används för att ta emot stämplingar över TCP från andra system. Ange vilken port som ska användas. Protokollets nolltid är 00:00:00. +help:14343 = Här visas en lista med inlästa löparbrickor. För att knyta en löpare till en annan bricka, dubbelklicka på den bricka eller deltagare du vill flytta. +help:146122 = Du kan utöka MeOS kännedom om löpare, klubbar och klasser genom att genomsöka databaser i MeOS-format eller IOF XML-format.\n\nVill du fortsätta? +help:14692 = Mata in kontroll (SI-nummer), löpare (startnummer eller bricknummer) och klocktid (HH:MM:SS). Du kan lämna tiden blank, varvid datorns tid används. Tryck på för att spara. +help:15491 = Du kan exportera dina inställningar, klubb- och löpardatabaser till en katalog som du anger. Sedan kan du importera dessa inställningar på en annan dator. +help:21576 = Tips: Om du råkar göra en fel, klicka på löparens namn för att ändra anmälan. Under fliken deltagare kan du ta bort anmälningar. De klasser du kan anmäla till är de där direktanmälan är ikryssad (se fliken klasser). +help:25041 = Här definierar du de banor som du behöver. En bana knyts sedan till en eller flera klasser (eller löpare). Det går också att importera banor från OCAD, Condes eller annat banläggningsprogram. Om du anger antal tillgängliga kartor, håller MeOS reda på hur många som är kvar vid direktanmälan. +help:26963 = En banpool används för att använda en pool av banor per sträcka. Banan knyts till löparen vid målgång genom matchning. Definiera banorna i poolen genom att lägga till dem under Flera banor/stafett. Ett [S] efter klassen betyder att alla deltagare har tilldelats starttid. +help:29191 = Du kan installera inställningar, klubb- och löpardatabaser från en källkatalog som du anger. De lokala inställningarna skrivs över. Efter installationen kan MeOS behöva startas om.\n\nKnappen tar dig till en sida där du istället kan exportera dina nuvarande lokala inställningar. +help:29758 = Här hanterar du klubbar, genererar och skriver ut fakturor. Du kan tilldela tävlingsavgifter i efterhand, baserat på klasstyp och anmälningsdatum. Duplicerade (felstavade) klubbar kan slås ihop med den riktiga klubben och tas bort. Du kan också uppdatera klubbarna med data från distriktsregistret. +help:30750 = Här kan du skapa olika sorters listor och rapporter. Du kan visa dem på skärmen, skriva ut dem eller spara dem för webben. När tävlingsdata förändras uppdateras listan automatiskt. Automatiska utskrifter hittar du under fliken automater. Export av tävlingsdata, t.ex. sträcktider, gör du under fliken tävling. +help:31661 = En omstart definieras av en repdragningstid och en omstartstid. Vid repdragningstiden stängs växlingen, och inga startande släpps ut i skogen. Vid omstartstiden går omstarten. Det går att ställa in olika omstartstid på olika sträckor, men med hjälp av den här funktionen sätter du snabbt omstartstid för hela klasser. +help:33940 = Importera anmälningsdata i fritextformat. Ange Namn, Klubb, Klass, och SI (och eventuell starttid) gärna separerade med komma, en person (ett lag) per rad. Det går också att anmäla flera personer i samma klubb/klass genom att (delvis) utelämna fälten klubb/klass. Det är också möjligt att importera anmälningar formaterade på andra sätt.\n\nKlasser skapas automatiskt, men om du importerar lag för stafett eller patrull bör du lägga upp klasserna själv innan du importerar anmälningarna. Annars finns risk att sträcktilldelningen blir fel. +help:41072 = Markera en stämpling i stämplingslistan för att ta bort den eller ändra tiden. Från banmallen kan saknade stämplingar läggas till. Saknas måltid får löparen status utgått. Saknas stämpling får löparen status felstämplat. Det går inte att sätta en status på löparen som inte överensstämmer med stämplingsdata. Finns målstämpling måste tiden för denna ändras för att ändra måltiden; samma princip gäller för startstämpling. +help:41641 = Fyll i första starttid och startintervall. Lottning innebär slumpmässig lottning, SOFT-lottning en lottning enligt SOFT:s klubbfördelningsregler. Klungstart innebär att hela klassen startar i småklungor under det intervall du anger ("utdragen" masstart). \n\nAnge intervall 0 för gemensam start.\n\nNummerlappar: Ange första nummer eller lämna blankt för inga nummerlappar. I fältet sträcka (Str.) anger du vilken sträcka som ska lottas (om klassen har flera sträckor). +help:425188 = Du kan automatiskt hantera genom att läsa in SI-stationer (töm/check/start/kontroller) i SI-Config, spara inläsningen som en semikolonseparerad textfil och importera denna i MeOS. De löpare som förekommer i denna import får en registrering. Därefter kan du sätta på löpare utan registrering. Läser du senare in fler löpare kan du återställa de löpare som tidigare fått Ej Start men nu fått en registrering. +help:471101 = Aktivera SI-enheten genom att välja rätt COM-port, eller genom att söka efter installerade SI-enheter. Info ger dig information om den valda enheten/porten. För att läsa in brickor ska enheten vara programmerad utan autosänd (men för radiokontroller används autosänd). Utökat protokoll rekommenderas, då det ger en stabilare uppkoppling. Enheten programmeras med SportIdents programvara SI-Config.\n\nInteraktiv inläsning används om du direkt vill ta hand om eventuella problem som felaktigt bricknummer; avmarkera om arrangemanget använder 'röd utgång'.\n\nLöpardatabasen används om du automatiskt vill lägga till inkommande löpare med hjälp av löpardatabasen. Löparens stämplingar används för att välja rätt klass. +help:50431 = Du är nu ansluten mot en server. För att öppna en tävling från servern, markera den i listan och välj öppna. För att lägga upp en tävling på servern, öppna först tävlingen lokalt, och använd därefter knappen ladda upp tävling. När du öppnat en tävling på servern ser du vilka andra MeOS-klienter som är anslutna mot den.\n\nOm det står (på server) efter tävlingen är den öppnad på en server och kan delas av andra MeOS-klienter. Står det (lokalt) kan man bara komma åt tävlingen från den aktuella datorn. +help:52726 = Anslut mot en server nedan. \n\nInstallation\nLadda ner och installera MySQL 5 (Community Edition) från www.mysql.com, förslagsvis med standardinställningar. MySQL behöver bara installeras på den dator som ska vara server. Starta sedan MySQL Command Line Client och skapa ett användarkonto för MeOS. Man skriver så här:\n\n> CREATE USER meos;\n> GRANT ALL ON *.* TO meos;\n\nDu har nu skapat en användare meos (med blankt lösenord). Ange serverns namn nedan (om du inte kan ansluta måste du kontrollera eventuella brandväggar).\n\nEtt alternativ är att använda MySQL:s inbyggda rotkonto, det vill säga, användarnamn 'root' och det lösenord du angav vid installationen av MySQL. +help:5422 = Hittade ingen SI-enhet. Är de inkopplade och startade? +help:59395 = I det här formuläret kan du snabbt göra grundläggande inställningar för alla klasser i ett svep. \n\nStart anger namnet på starten, såsom det skrivs i startlistan. \n\nBlock är ett tal mellan 0 och 100 som anger än ännu finkornigare uppdelning av de startande. Klasser som tillhör samma block skrivs ut på samma minutstartlista. \n\nIndex anger en sorteringsnyckel. Alla listor sorterar klasserna stigande efter denna nyckel. \n\nBana kan anges för de klasser som har precis en bana; har klassen flera banor eller gafflingar måste detta ställas in klassvis. \n\nDirektanmälan anger om klassen stöder direktanmälan. +help:59395_more = Klassernas avgifter, som visas om du har aktiverat Ekonomifunktionerna, används för nya deltagare. Ändrar du dem får du en fråga om att uppdatera avgifterna för redan anmälda.\n\nFör nummerlapp finns alternativet Ingen, Löpande och Manuell. Du kan också skriva in ett första nummerlappsnummer i klassen, t.ex. A100, eller 50. Löpande betyder att sista nummerlappsnummer i föregående klass används för att sätta första nummer i denna klass. Reserverade nummerlappsnummer innebär att ett motsvarande hopp görs i numreringen mellan klasser.\n\nMeOS uppdaterar nummerlappar vid lottning, eller om inställningarna ändras. Manuell betyder att MeOS aldrig automatiskt ändrar klassens nummerlappar.\n\nFör klasser med lag styr inställningen Lagmedlem löparnas nummerlapp i förhållande till lagets. De kan vara samma, ökande (100, 101, 102), bero på sträcka (100-1, 100-2, etc.) eller vara helt oberoende. +help:7618 = Antalet löpare i laget ställer man in på sidan klasser. +help:7620 = Intervall (sekunder). Lämna blankt för att uppdatera när tävlingsdata ändras +help:89064 = Till varje kontroll anger man en eller flera kodsiffror (SI-kod). När man lägger banor refererar man till kontrollens ID-nummer. Man behöver normalt inte själv lägga till kontroller eftersom MeOS automatiskt lägger till de kontroller som används. \n\nFlera kodsiffror är användbart för att ersätta trasiga kontroller eller för att skapa enkla gafflingar. För en vanlig kontroll krävs att löparen besökt en av de angivna kontrollerna. Sätts status till måste löparen besöka samtliga listade kontroller i valfri ordning.\n\nOm man sätter kontrollens status till , kommer den inte att användas i stämplingskontrollen. \n\nEn kontroll kan tilldelas ett namn, t.ex. 'Varvning'. Det går att skriva ut resultatlistor som innehåller mellantider för namngivna kontroller.\n\nTidsjustering används om det visar sig att en kontrolls klocka går fel:formatet är +/-MM:SS eller +/-HH:MM:SS.\n\nMinsta sträcktid kan användas exempelvis vid vägpassage. Ingen löpare kan få en bättre sträcktid in mot kontrollen än den angivna tiden. Överskrider löparen den angivna tiden, används löparens faktiska tid.\n\nStatus betyder att löparens tid till kontrollen ignoreras; sluttiden blir densamma oavsett faktisk sträcktid. +help:9373 = Ange en eller flera kodsiffror (SI-kod) som används av den här kontrollen, t.ex. 31, 250. Fältet poäng används för Rogaining-kontroller. +help:9615 = Fick inget svar. Ska porten öppnas i passivt läge; ska MeOS lyssna efter inkommande stämplingar? +help:assignfee = MeOS hanterar i de flesta fall avgifter automatiskt. Deltagarna tilldelas en anmälningsavgift utifrån ålder och anmälningsdatum (gränser anger du under tävlingsinställningar). Varje klass definierar vilka avgifter som gäller. Standardvärden för olika klasstyper definierar du under tävlingsinställningar, men du kan också göra manuella ändringar på sidan klasser, under snabbinställningar.\n\nMed funktionerna här kan du tilldela manuellt filtrera olika åldrar och anmälningsfrister och tilldela avgifter. På sidan deltagare kan du också manuellt justera enskilda deltagares avgift. +help:baudrate = Överföringshastighet/Baudrate: använd 4800 eller 38400. +help:computer_voice = De stämplingar som inkommer till systemet matchas mot startnummer och filen , där N är startnumret, spelas upp. Filerna hämtas från katalogen nedan. Om löparen/laget tillhör nationen NAT, spelas i första hand filen . För svenska löpare spelas till exempel i första hand filerna +help:dbage = Löpardatabasen är äldre än 2 månader. Vill du ladda hem en uppdaterad databas från Eventor? +help:duplicate = Gör en lokal kopia på av den aktuella tävlingen. +help:eventorkey = Mata in klubbens API-nyckel för Eventor, den behövs för att du ska kunna ansluta till Eventor och hämta anmälningar och löparregister. Nyckeln får du av klubbens Eventor-administratör. +help:fullscreen = Du kan justera farten med Ctrl+M (öka) respektive Ctrl+N (minska) på tangentbordet. För att lämna fullskärmsläge, tryck på Esc. +help:import_entry_data = Du kan importera löpare, klasser, klubbar och anmälningar från en antal olika text- och XML-format. Det är inte nödvändigt att ange samtliga filer. Till exempel innehåller OE-CSV formatet för anmälningar även klasser och klubbar, så i det fallet ska fälten för klasser och klubbar lämnas tomma.\n\nOm samma löpare importeras flera gånger, kommer löparen att uppdateras den andra gången. Man får inte flera kopior på löparen. Det innebär att man kan importera efteranmälningar genom att läsa in en utökad fil med anmälda. +help:importcourse = Du kan importera banor och klasser från (exempelvis) OCAD:s eller Condes exportformat. +help:ocad13091 = Om du har tillgång till banorna på fil (till exempel från OCAD or Condes) kan du ange filens namn här. Annars kan du lägga in banorna senare. +help:relaysetup = Använd guiden nedan för att välja mellan ett antal fördefinierade tävlingsformer. När du trycker på verkställ sparas inställningarna. Därefter är det möjligt att manuellt anpassa inställningar för varje sträcka och välja banor.\n\nNågra förklaringar:\n- Stafett används för stafetter i olika former.\n- Tvåmannastafett innebär att två löpare utgör ett lag och springer varannan sträcka.\n- Extralöparstafett används ibland i ungdomsklasser och tillåter flera löpare på mellansträckorna (först i mål växlar).\n- Patrull kan springas med två SI-pinnar (varje löpare stämplar) eller en SI-pinne per patrull.\n- Prolog + jaktstart innebär att en löpare först springer en prolog, därefter en jaktstart baserad på resultatet.\n- Banpool innebär gaffling där man inte i förväg behöver bestämma vem som springer vilken bana; vid målgång avgörs vilken bana löparen sprungit. +help:restore_backup = Välj en säkerhetskopia att återställa genom att klicka på den tidpunkt då säkerhetskopian togs. +help:runnerdatabase = Genom att importera löparregister och klubbregister får du MeOS att automatiskt knyta ihop bricknummer med löpare vid brickinläsning och du får in adresser och kontaktuppgifter för klubbar.\n\nMeOS kan importera IOF (XML)-format från t.ex. Eventor. +help:save = MeOS sparar alla ändringar automatiskt när det behövs. +help:speaker_setup = Välj vilka klasser och kontroller du vill bevaka. +help:speakerprio = Sätt ett kryss för de löpare/lag som ska bevakas från början och så länge löparen/laget går bra. Sätt två kryss för att bevaka även om det går dåligt. Inget kryss betyder bevakning endast om det går bra (inte från start). +help:splitexport = Välj om du vill exportera totalresultat eller individuella resultat sträckvis. Om du väljer att exportera alla sträckor/lopp, kommer flera numrerade filer att sparas. +help:startmethod = MeOS tillämpar automatiskt vald startmetod. Oavsett vad du väljer kan du alltid ändra startmetod och eller lotta om senare. +help:winsplits_auto = Den här automaten sparar sträcktider i en IOF-fil med jämna mellanrum. Om du öppnar filen med WinSplits, kommer sträcktiderna där att uppdateras med ungefär lika jämna mellanrum +help:zero_time = Nolltid bör sättas till en timme före första start. +help_autodraw = Mata in första (ordinarie) starttid, minsta startintervall (inom en klass) och andel vakanser. Du kan också välja lottningsmetod och om efteranmälda ska starta först eller sist. Första starttid måste vara efter tävlingens nolltid.\n\nOm du väljer automatisk lottning, kommer MeOS att gå igenom samtliga klasser. Klasser som inte lottats tidigare kommer att lottas. MeOS lottar varje start för sig och försöker ordna en jämn ström av startande. MeOS ser också till att klasser med samma bana inte startar samtidigt, och om möjligt att löpare med samma första kontroll inte startar samtidigt. Dessutom lämnas utrymme att senare lotta in efteranmälda under samma villkor.\n\nI de klasser som redan har lottats kommer efteranmälda att lottas in efter eller före de ordinarie anmälda. De löpare som redan lottats behåller alltså sin starttid. Det är också möjligt att manuellt först lotta vissa klasser och sedan låta MeOS automatiskt lotta återstående klasser.\n\nOm du istället väljer manuell lottning kommer du till en sida där du kan välja exakt vilka klasser som ska lottas och har ännu fler inställningsmöjligheter. +help_draw = Lottning görs i två steg. Först anger du vilka klasser du vill lotta och gör grundläggande inställningar. När du trycker på använder MeOS inställningarna för att fördela starttider mellan klasser. MeOS ser till att klasser med liknande banor inte startar samtidigt och tar hänsyn till redan lottade klasser. Målet är ett så jämnt flöde av startande som möjligt.\n\nFördelningen presenteras i en tabell, där du kan göra egna förändringar och eventuellt låta MeOS göra en ny fördelning med hänsyn till de ändringar du gjort. När du är nöjd med fördelningen låter du MeOS lotta de valda klasserna.\n\nDe grundläggande inställningar du måste göra är första starttid och minsta startintervall. Inställningen max parallellt startande anger hur många löpare som får samtidigt. Ett större värde ger ett kortare startdjup.\n\nAndel vakanser anger om MeOS ska lotta in vakanta platser i startfältet. Ange 0% för inga vakanser. Förväntat antal efteranmälde används för att reservera plats i startfältet för efteranmälda. Inga vakanta platser sätts in, men det lämnas utrymme i startlistan med garanti för att inga samtidigt startande ska ha samma bana. +info:multieventnetwork = För att administrera flera etapper måste du arbeta lokalt. Spara en kopia av tävlingen, öppna den lokalt och överför resultat till nästa etapp. Därefter laddar du upp nästa etapp på servern för att genomföra den. +info:readout_action = X: Bricka Y avläst.\nManuell behandling är nödvändig. +info:readout_queue = X: Bricka Y avläst.\nBrickan har ställts i kö. +inforestwarning = Inga löpare befinns vara i skogen. Eftersom de uppgifter analysen baseras på kan vara felaktiga, bör du som arrangör också på andra sätt övertyga dig om att ingen är kvar i skogen. +kartor = kartor +klar = klar +kontroll = kontroll +kontroll X (Y) = kontroll X (Y) +localhost = localhost +lopp = lopp +mål = mål +målet = målet +målet (X) = målet (X) +nia = nia +nionde = nionde +radio X = radio X +saknas = saknas +se license.txt som levereras med programmet = se license.txt som levereras med programmet +serverbackup = serverbackup +sexa = sexa +sjua = sjua +sjunde = sjunde +sjätte = sjätte +skicka stämplar = skicka stämplingar +sortering: X, antal rader: Y = sortering: X, antal rader: Y +starten (X) = starten (X) +sträcka X = sträcka X +stämplade vid = stämplade vid +stämplar vid X som Y, på tiden Z = stämplar vid X som Y, på tiden Z +tar ledningen med tiden X = tar ledningen med tiden X +tia = tia +till = till +tionde = tionde +tolfte = tolfte +tolva = tolva +tooltip:analyze = Analysera inmatat data och förhandsgranska. +tooltip:builddata = Utöka MeOS kännedom om löpare, klubbar och klasser genom analys av tävlingsdata. +tooltip:import = Hämta anmälningar från en fil. +tooltip:inforest = Lista över löpare i skogen och ej startande löpare. +tooltip:paste = Klistra in anmälningar från urklipp. +tooltip:resultprint = Skriv ut resultatlistor att anslå +tooltip:voice = Datorröst som läser upp förvarningar. +trea = trea +tredje = tredje +tvåa = tvåa +väntas till X om någon minut = väntas till X om någon minut +väntas till X om någon minut, och kan i så fall ta en Y plats = väntas till X om någon minut, och kan i så fall ta en Y plats +väntas till X om någon minut, och kan i så fall ta ledningen = väntas till X om någon minut, och kan i så fall ta ledningen +växeln = växeln +växlar på X plats med tiden Y = växlar på X plats med tiden Y +växlar på X plats, efter Y, på tiden Z = växlar på X plats, efter Y, på tiden Z +växlar på delad X plats med tiden Y = växlar på delad X plats med tiden Y +warn:changedtimezero = Att ändra nolltid i en tävling med resultat rekommenderas inte.\n\nVill du fortsätta? +warn:olddbversion = Databasen används av en senare version av MeOS. Fortsätt på egen risk +warning:dbproblem = VARNING. Problem med databasen: 'X'. Anslutningen kommer automatiskt att återställas. Fortsätt arbeta som vanligt. +warning:drawresult = Klassen har redan resultat. Starttider kommer att skrivas över. Vill du verkligen fortsätta? +warning:has_entries = Klassen har redan anmälda deltagare. Att ändra sträckindelning i detta skede kan leda till att laguppställningar förloras.\n\nVill du fortsätta? +warning:has_results = Klassen har redan resultat. Att ändra sträckindelning i detta skede är en ovanlig åtgärd.\n\nVill du fortsätta? +xml-data = xml-data +Äldre protokoll = Äldre protokoll +Ändra = Ändra +Ändra grundläggande inställningar och gör en ny fördelning = Ändra grundläggande inställningar och gör en ny fördelning +Ändra inställningar = Ändra inställningar +Ändra klassinställningar = Ändra klassinställningar +Ändra lag = Ändra lag +Ändra sträckindelning = Ändra sträckindelning +Ändrad = Ändrad +Ändrade avgift för X deltagare = Ändrade avgift för X deltagare +Åldersfilter = Åldersfilter +Åldersgräns ungdom = Åldersgräns ungdom +Åldersgräns äldre = Åldersgräns äldre +Åldersgränser, reducerad anmälningsavgift = Åldersgränser, reducerad anmälningsavgift +Ångra = Ångra +Återansluten mot databasen, tävlingen synkroniserad = Återansluten mot databasen, tävlingen synkroniserad +Återbud = Återbud +Återgå = Återgå +Återställ = Återställ +Återställ / uppdatera klasstillhörighet = Återställ/uppdatera klasstillhörighet +Återställ löpare med registrering till = Återställ löpare med registrering till +Återställ säkerhetskopia = Återställ säkerhetskopia +Återställ tabeldesignen och visa allt = Återställ tabelldesignen och visa allt +ÅÅÅÅ-MM-DD = ÅÅÅÅ-MM-DD +Öppen = Öppen +Öppen klass = Öppen klass +Öppna = Öppna +Öppna fil = Öppna fil +Öppna från aktuell tävling = Öppna från aktuell tävling +Öppna föregående = Öppna föregående +Öppna föregående etapp = Öppna föregående etapp +Öppna i ett nytt fönster = Öppna i ett nytt fönster +Öppna klasser, ungdom = Öppna klasser, ungdom +Öppna klasser, vuxna = Öppna klasser, vuxna +Öppna nästa = Öppna nästa +Öppna nästa etapp = Öppna nästa etapp +Öppna tävling = Öppna tävling +Öppna vald tävling = Öppna vald tävling +Öppnad tävling = Öppnad tävling +Överför anmälda = Överför anmälda +Överför nya deltagare i ej valda klasser med status "deltar ej" = Överför nya deltagare i övriga klasser med status +Överför resultat = Överför resultat +Överför resultat till X = Överför resultat till X +Överför resultat till nästa etapp = Överför resultat till nästa etapp +Övre datumgräns = Övre datumgräns +Övre gräns (år) = Övre gräns (år) +Övre ålder = Övre ålder +Övriga = Övriga +är först i mål med tiden X = är först i mål med tiden X +är först vid X med tiden Y = är först vid X med tiden Y +är först vid växeln med tiden X = är först vid växeln med tiden X +är inte godkänd = är inte godkänd +återställd = återställd +åtta = åtta +åttonde = åttonde +Kopia (X) = Kopia (X) +Tillåt samma bana inom basintervall = Tillåt samma bana inom basintervall +Välj X = Välj X +Ett startblock spänner över flera starter: X/Y = Ett startblock spänner över flera starter: X/Y +Bricka X = Bricka X +RunnerTimePerKM = Löpfart min/km +X är inget giltigt sträcknummer = X är inget giltigt sträcknummer +Listan togs bort från tävlingen = Listan togs bort från tävlingen +Töm = Töm +Status matchar inte deltagarnas status = Status matchar inte deltagarnas status +Status matchar inte data i löparbrickan = Status matchar inte data i löparbrickan +Döp om = Döp om +går upp i delad ledning vid X med tiden Y = går upp i delad ledning vid X med tiden Y +X:e = X:e +tar ledningen vid X med tiden Y = tar ledningen vid X med tiden Y +Eventor server = Eventor server +(har stämplat) = (har stämplat) +documentation = meos_doc_swe.html +Hittar inte hjälpfilen, X = Hittar inte hjälpfilen, X +X har redan ett resultat. Vi du fortsätta? = X har redan ett resultat. Vi du fortsätta? +Aktuell tid = Aktuell tid +Godkänd = Godkänd +Nummerlapp, SI eller Namn = Nummerlapp, SI eller Namn +Utgått = Utgått +Manuell inmatning = Manuell inmatning +Tilldelad = Tilldelad +Eventors tider i UTC (koordinerad universell tid) = Eventors tider i UTC (koordinerad universell tid) +Exportera tider i UTC = Exportera tider i UTC +Tidszon = Tidszon +RunnerAge = Deltagares ålder +RunnerBirthYear = Deltagares födelseår +RunnerFee = Deltagares avgift +RunnerNationality = Deltagares nationalitet +RunnerPhone = Deltagares t.nr. +RunnerSex = Deltagares kön +TeamFee = Lags avgift +Varning: ändringar i X blev överskrivna = Varning: ändringar i X blev överskrivna +help:simulate = Med den här automaten kan du simulera inläsning av SI-brickor. Löptider slumpas fram för alla deltagare. Även radiostämplingar kan simuleras.\n\nVARNING: Endast för testning. Använder du den här automaten i samband med ett riktigt arrangemang, saboterar du tävlingen +Rogainingresultat - %s = Rogainingresultat - %s +TeamPlaceDiff = Lags placeringsförändring (denna etapp) +TeamTotalPlace = Lags sammanlagda placering (alla etapper) +TeamTotalTime = Lags sammanlagda tid (alla etapper) +TeamTotalTimeAfter = Lags sammanlagda tid (alla etapper) +TeamTotalTimeDiff = Lags tid-efter-förändring (denna etapp) +TeamTotalTimeStatus = Lags sammanlagda tid eller status (alla etapper) +Vill du dumpa aktuellt tävling och skapa en testtävling? = Vill du dumpa aktuellt tävling och skapa en testtävling? +Radera alla klubbar = Radera alla klubbar +Radera alla klubbar och ta bort klubbtillhörighet = Radera alla klubbar och ta bort klubbtillhörighet +Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa = Vill du ta bort alla klubbar från tävlingen? Alla deltagare blir klubblösa +Besökare = Besökare +Föregående kontroll = Föregående kontroll +Ja = Ja +Nej = Nej +På banan = På banan +Stämpelkod = Stämpelkod +Tidpunkt = Tidpunkt +Antal deltagare = Antal deltagare +Förekomst = Förekomst +Exporterar om = Exporterar om +Exportformat = Exportformat +Filnamnsprefix = Filnamnsprefix +Mapp = Mapp +Mappnamnet får inte vara tomt = Mappnamnet får inte vara tomt +Onlineresultat = Onlineresultat +Packa stora filer (zip) = Packa stora filer (ZIP) +Publicera resultat direkt på nätet = Publicera resultat direkt på nätet +Resultat online = Resultat online +Skicka till webben = Skicka till webben +Spara på disk = Spara på disk +Till exempel X = Till exempel X +Tävlingens ID-nummer = Tävlingens ID-nummer +URL = URL +URL måste anges = URL måste anges +Tidsintervall (sekunder) = Tidsintervall (sekunder) +Antal skickade uppdateringar X (Y kb) = Antal skickade uppdateringar X (Y kb) +Filen finns redan: X = Filen finns redan: X +Misslyckades med att ladda upp onlineresultat = Misslyckades med att ladda upp onlineresultat +Onlineservern svarade felaktigt = Onlineservern svarade felaktigt (servern felkonfigurerad?) +Onlineservern svarade: ZIP stöds ej = Onlineservern svarade: ZIP stöds ej +Onlineservern svarade: Serverfel = Onlineservern svarade: Serverfel +Onlineservern svarade: Felaktigt lösenord = Onlineservern svarade: Felaktigt lösenord +Onlineservern svarade: Felaktigt tävlings-id = Onlineservern svarade: Felaktigt tävlings-id +Online Results Error X = Onlineresultat, fel: X +PDF = PDF +ClassTeamLeg = Klass, lag, sträcka +Okänd = Okänd +Antal hämtade uppdateringar X (Y kb) = Antal hämtade uppdateringar X (Y kb) +Använd ROC-protokoll = Använd ROC-protokoll +Definierade mappningar = Definierade mappningar +Funktion = Funktion +Hämta stämplingar m.m. från nätet = Hämta stämplingar m.m. från nätet +Inmatning online = Fjärrinmatning +Kod = Kod +Kontrollmappning = Kontrollmappning +Ogiltig funktion = Ogiltig funktion +Ogiltig kontrollkod = Ogiltig kontrollkod +Onlineinput = Onlineinput +Online Input Error X = Online Input Error X +Ekonomi = Ekonomi +Fakturainställningar = Fakturainställningar +Hantera klubbar = Hantera klubbar +Spara som PDF = Spara som PDF +Avgifter och valuta ställer du in under = Avgifter och valuta ställer du in under +Fakturanummer = Fakturanummer +Formatering = Formatering +Första fakturanummer = Första fakturanummer +Internal Error, identifier not found: X = Internal Error, identifier not found: X +Koordinater (mm) för adressfält = Koordinater (mm) för adressfält +Organisatör = Organisatör +Tilldela nya fakturanummer till alla klubbar? = Tilldela nya fakturanummer till alla klubbar? +Exportera alla till PDF = Exportera alla till PDF +help:onlineresult = Automaten används för att skicka resultat och startlistor för direkt visning på webben eller i appar. Du måste göra inställningar som är anpassade för den tjänst du vill utnyttja: tjänsteleverantören kan ge dig detaljer.\n\nOm du vill utveckla egna tjänster finns dokumentation och exempel på MeOS hemsida: www.melin.nu/meos. +help:onlineinput = Automaten används för att ta emot radiostämplingar från internet, t.ex. radiokontroller anslutna via mobiltelefon. Det är också möjligt att ha ett enkelt webbformulär där personer vid en bemannad radiokontroll fyller i nummerlappasnummer på dem som passerar.\n\nAutomatens protokoll stöder också andra typer av inmatningar, såsom laguppställningar, direktanmälningar, brickändringar m.m. Om du vill utveckla egna tjänster finns dokumentation och exempel på MeOS hemsida: www.melin.nu/meos. +Egna textrader = Egna textrader +Inga bommar registrerade = Inga bommar registrerade +Inställningar sträcktidsutskrift = Inställningar sträcktidsutskrift +Med km-tid = Med km-tid +Tidsförluster (kontroll-tid) = Tidsförluster (kontroll/tid) +Underlag saknas för bomanalys = Underlag saknas för bomanalys +min/km = min/km +X har redan bricknummer Y. Vill du ändra det? = X har redan bricknummer Y. Vill du ändra det? +Avmarkera 'X' för att hantera alla bricktildelningar samtidigt = Avmarkera 'X' för att hantera alla bricktilldelningar samtidigt +Bricknr = Bricknummer +Knyt automatiskt efter inläsning = Knyt automatiskt efter inläsning +Knyt bricka / deltagare = Knyt bricka/deltagare +Nummerlapp, lopp-id eller namn = Nummerlapp, lopp-id eller namn +Lopp-id = Lopp-id +Markera 'X' för att hantera deltagarna en och en = Markera 'X' för att hantera deltagarna en och en +Installerbara listor = Installerbara listor +Listor i tävlingen = Listor i tävlingen +Radera permanent = Radera permanent +Tillgängliga listor = Tillgängliga listor +Vill du ta bort 'X'? = Vill du ta bort 'X'? +classcourseresult = Resultat klassvis och banvis +Hantera egna listor = Hantera egna listor +Redigera = Redigera +Skriver sträcktider när tävlingsdata ändras = Skriver sträcktider när tävlingsdata ändras +Bana med slingor = Bana med slingor +En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning = En bana med slingor tillåter deltagaren att ta slingorna i valfri ordning +Varvningskontroll = Varvningskontroll +warn:notextended = INFO: Programmera enheten med utökat protokoll i SIConfig för snabbare brickinläsning. +help:DirectResult = - Om bana ej tilldelats godkänns deltagaren vid målstämpling.\n\n- Om en bana finns används radiostämplingar som kontroller. Ingen brickavläsning ska göras. +Resultat vid målstämpling = Resultat vid målstämpling +Stämpling = Stämpling +Skicka och ta emot snabb förhandsinformation om stämplingar och resultat = Skicka och ta emot snabb förhandsinformation om stämplingar och resultat +Centrera = Centrera +Färg = Färg +Höger = Höger +PunchControlCode = Stämplingskod +PunchControlNumber = Kontrollnummer +PunchControlPlace = Placering, sträcka till kontroll +PunchControlPlaceAcc = Placering, efter kontroll +PunchLostTime = Missad tid till kontroll +Slå ihop text med föregående = Slå ihop text med föregående +Textjustering = Textjustering +Vänster = Vänster +X (press Ctrl+Space to confirm) = X (tryck + för att bekräfta) +Press Enter to continue = Tryck för att fortsätta +ask:overwriteresult = X har redan ett resultat. Vill du skriva över det? +Brickan används av X = Brickan används av X +DATABASE ERROR = DATABASFEL +Lyssnar på X = Lyssnar på X +vid kontroll X = vid kontroll X +info:runnerdbonline = Eftersom du är uppkopplad mot en server, är det inte möjligt att redigera klubb- och löpardatabasen manuellt. Ändringar kan göras lokalt innan tävlingen och laddas upp på en server. Det går också att ersätta den befintliga databasen på servern genom att importera en ny (från IOF XML). +IOF Startlista, version 3.0 (xml) = IOF Startlista, version 3.0 (xml) +IOF Startlista, version 2.0.3 (xml) = IOF Startlista, version 2.0.3 (xml) +IOF Löpardatabas, version 3.0 (xml) = IOF Löpardatabas, version 3.0 (xml) +IOF Klubbdatabas, version 3.0 (xml) = IOF Klubbdatabas, version 3.0 (xml) +ask:cleardb = Vill du tömma löpar- och klubbdatabasen? +Banan saknar rogainingkontroller = Banan saknar rogainingkontroller +Banans kontroller ger för få poäng för att täcka poängkravet = Banans kontroller ger för få poäng för att täcka poängkravet +CustomSort = Egen sortering +Brickhantering = Brickhantering +HTML med AutoRefresh = HTML med AutoRefresh +Importera laguppställningar = Importera laguppställningar +MeOS Funktioner = MeOS Funktioner +Målfil = Målfil +Spara tid = Spara tid +Stämplingstid = Stämplingstid +Data from result module (X) = Data från resultatmodul (X) +Forkings = Gafflingar +Forkings for X = Gafflingar för X +Gruppera = Gruppera +Resultatuträkning = Resultatuträkning +RunnerRogainingPointTotal = Deltagares totala poäng +Show forking = Visa gafflingar +Standard = Standard +TeamRogainingPointTotal = Lags totala poäng +The forking is fair = Gafflingen är rättvis +Underfilter = Underfilter +Ogiltigt lag på rad X = Ogiltigt lag på rad X +Okänd klass på rad X = Okänd klass på rad X +Klassen X är individuell = Klassen X är individuell +Använd befintliga deltagare = Använd befintliga deltagare +Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka) = Knyt redan anmälda deltagare till laget (identifiera genom namn och/eller bricka) +Laguppställning = Laguppställning +Bakåt = Bakåt +Bibs = Nummerlappar +Club and runner database = Klubb- och löpardatabas +Clubs = Klubbar +Economy and fees = Ekonomi och avgifter +Forked individual courses = Gafflade individuella banor +General = Allmänt +Manual point reductions and adjustments = Manuella poängavdrag/justeringar +Manual time penalties and adjustments = Manuellt tidstillägg/justering +MeOS Features = MeOS Funktioner +MeOS – Funktioner = MeOS – Funktioner +Patrols = Patruller +Prepare start lists = Förbereda startlistor +Relays = Stafetter och lagtävlingar +Several MeOS Clients in a network = Flera MeOS-klienter i nätverk +Several races for a runner = Flera lopp för en löpare +Spara laguppställningar = Spara laguppställningar +Teams and forking = Lag och gafflingar +Track runners in forest = Beräkna kvar-i-skogen +Vacancies and entry cancellations = Vakanser och återbud +Banan saknas = Banan saknas +Klassen saknas = Klassen saknas +Alla lopp som individuella = Alla lopp som individuella +Exportera individuella lopp istället för lag = Exportera individuella lopp istället för lag +Exportera startlista = Exportera startlista +Exporttyp = Exporttyp +Exportval, IOF-XML = Exportval, IOF-XML +Failed to read file = Kunde inte läsa filen. +Klassval = Klassval +The forking is not fair = Gafflingen är inte rättvis +Unfair control legs = Orättvisa sträckor +Växel = Växel +help:teamlineup = Här importerar du laguppställningar enligt ett strukturerat textbaserat format, som är enkelt att framställa i ett kalkylbladsprogram. Filen ska ha följande format:\n\nKlass;Lagnamn;[Klubb]\nDeltagarnamn 1;[Bricknummer];[Klubb];[Bana];[Deltagarklass]\nDeltagarnamn 2;[Bricknummer];[Klubb];[Bana];[Deltagarklass]\n...\nKlass;Lagnamn;[Klubb]\n...\n\nPoster inom [] kan utelämnas. Observera att refererade klasser och banor måste finnas, och att antalet sträckor i lagets klass exakt måste stämma med antalet deltagarrader i filen. Blankrader används för saknade deltagare. Valet betyder att endast deltagare som redan finns anmälda flyttas till laget; övriga deltagare i filen ignoreras. +Poängjustering = Poängjustering +Use initials in names = Använd initialer i namn +Exportera klubbar (IOF-XML) = Exportera klubbar (IOF-XML) +Exportera personer (IOF-XML) = Exportera personer (IOF-XML) +Töm databasen = Töm databasen +Several stages = Flera etapper +Assign courses and apply forking to X = Tilldela banor och gaffling till X +Assign selected courses to selected legs = Använd valda banor på valda sträckor +Calculate and apply forking = Beräkna och tillämpa gaffling +Clear selections = Nollställ val +Define forking = Definiera gaffling +Forking setup = Vald bantilldelning +Leg X: Do not modify = Sträcka X: Lämna bantilldelning orörd +Legs = Sträckor +help:assignforking = Den här funktionen beräknar ett optimalt gafflingsmönster från valda banor. Tilldela en eller flera banor till ett antal sträckor genom att markera banor och sträckor från listorna. Alla sträckor kan använda samma uppsättning banor (likvärdiga sträckor) eller så kan man använda olika uppsättningar banor för olika sträckor. Även sträckor med olika uppsättningar banor kan gafflas mot varandra, om bansträckningen så tillåter. +Leg X = Sträcka X +Leg X: Use Y = Sträcka X: Använd Y +Created X distinct forkings using Y courses = Skapade X olika gafflingsalternativ med hjälp av Y banor +Clear Memory = Töm minnet +Create Competition = Skapa tävling +Print Card Data = Skriv ut sträcktider +Print card data = Skriv ut sträcktider +Start: X = Start: X +Time: X = Tid: X +help:analyzecard = Här kan du skriva ut sträcktider utan att använda någon tävling, ungefär som en fristående sträcktidsskrivare. Klicka på Sträcktidsutskrift för att välja skrivare.\n\nDe inlästa brickorna sparas också i minnet (men inte i någon tävling). Du kan ändra namn och klubb för en inläst bricka genom att klicka på namnet (Eller 'Okänd'). Du kan också spara de inlästa brickorna på fil (Spara) eller välja att helt automatiskt skapa en riktig tävling från brickdata. Notera att om en tävling är öppnad så måste du stänga den för att detta alternativ ska bli tillgängligt. +Gafflade banor = Gafflade banor +Använd endast en bana i klassen = Använd endast en bana i klassen +Unroll split times for loop courses = Exportera slingor som raka banor +Löpare per klass = Löpare per klass +Alla funktioner = Alla funktioner +Anmäl inga deltagare nu = Anmäl inga deltagare nu +Datum (för första start) = Datum (för första start) +Endast grundläggande = Endast grundläggande +Funktioner i MeOS = Funktioner i MeOS +Första tillåtna starttid = Första tillåtna starttid +Importera anmälda = Importera anmälda +Individuell tävling = Individuell tävling +Namn och tidpunkt = Namn och tidpunkt +Skapar tävling = Skapar tävling +Tävling med lag = Tävling med lag +Tävlingen måste avgöras mellan X och Y = Tävlingen måste avgöras mellan X och Y +Tävlingens namn = Tävlingens namn +Välj från lista = Välj från lista +Välj vilka funktioner du vill använda = Välj vilka funktioner du vill använda +Individuellt, gafflat = Individuellt, gafflat +Skapa tävlingen = Skapa tävlingen +newcmp:featuredesc = Välj vilka funktioner som ska vara tillgängliga för den här tävlingen. Du kan när som helst lägga till eller ta bort funktionalitet genom att välja på sidan tävling. +Exportera till fil = Exportera till fil +FilterPrelResult = Preliminärt resultat +FinishTimeReverse = Omvänd målgångstid (senast först) +Open a Copy = Öppna som kopia +Point calculation for runner = Poängberäkning för deltagare +Point calculation for team = Poängberäkning för lag +Result score calculation for runner = Placeringspoäng för deltagare +Result score calculation for team = Placeringspoäng för lag +ResultDescription = Namn på resultattyp +Skapa = Skapa +Status calculation for runner = Statusberäkning för deltagare +Status calculation for team = Statusberäkning för lag +Support time from control = Stöd tidtagning från viss kontroll +Support time to control = Stöd tidtagning till viss kontroll +Time calculation for runner = Tidsberäkning för deltagare +Time calculation for team = Tidsberäkning för lag +TimingFrom = Namn på startpunkt +TimingTo = Namn på målpunkt +Applying rules to the current competition = Tillämpar regler på aktuell tävling +Available symbols = Tillgängliga symboler +Cancel = Avbryt +Description = Beskrivning +Edit Clubs = Redigera klubbar +Edit Result Modules = Redigera resultatmoduler +Edit rule for = Ändra regel för +Name of result module = Namn på resultatmodul +New Result Module = Ny resultatmodul +New Set of Result Rules = Ny resultatmodul +Result Modules = Resultatmoduler +Result Calculation = Resultatuträkning +Result Module – X = Resultatmodul – X +Result module identifier = Identifierare för resultatmodul +Save = Spara +Save changes = Spara ändringar +Source code = Källkod +Test Result Module = Testa resultatmodul +Index in X[index] = Index i X[index] +X är inget giltigt index = X är inget giltigt index +ResultModuleNumber = Resultmodul: tal +ResultModuleTime = Resultmodul: tid +ResultModuleNumberTeam = Resultmodul: tal för lag +ResultModuleTimeTeam = Resultmodul: tid för lag +RunnerRogainingOvertime = Deltagares övertid (rogaining) +RunnerRogainingReduction = Deltagares poängreduktion +TeamRogainingOvertime = Lags övertid (rogaining) +TeamRogainingReduction = Lags poängreduktion +Automatic rogaining point reduction = Uträknad poängreduktion för rogaining +Deviation +/- from expected time on course leg = Avvikelse +/- från förväntad tid på sträcka +Leg number in team, zero indexed = Sträcknummer, noll-baserad +Length of course = Banans längd +Maximum allowed running time = Maxtid +Place on course leg = Placering på sträcka +Runner's card, matched control ids (-1 for unmatched punches) = Deltagares bricka, matchade kontroller (-1 för omatchade stämplingar) +Runner's card, punch codes = Deltagares bricka, stämplingskoder +Runner's card, punch times = Deltagares bricka, stämplingstider +Runner's course = Deltagares bana +Runner's split times = Deltagares mellantider +Runner's total running time to control = Deltagares totala löptid till kontroll +Runner/team fee = Deltagares/lags avgift +Runner/team finish time = Deltagares/lags måltid +Runner/team input place = Deltagares/lags ingångsplacering +Runner/team input points = Deltagares/lags ingångspoäng +Runner/team input running time = Deltagares/lags ingångstid +Runner/team input status = Deltagares/lags ingångsstatus +Runner/team place = Deltagares/lags placering +Runner/team rogaining overtime = Deltagares/lags rogaining-övertid +Runner/team rogaining points = Deltagares/lags rogaining-poäng +Runner/team rogaining points adjustment = Deltagares/lags manuella poängjustering +Runner/team running time = Deltagares/lags tid +Runner/team start time = Deltagares/lags starttid +Runner/team status = Deltagares/lags status +Runner/team time adjustment = Deltagares/lags tidsjustering +Runner/team total place = Deltagares/lags sammanlagda placering +Runner/team total running time = Deltagares/lags sammanlagda tid +Runner/team total status = Deltagares/lags sammanlagda status +Shortest time in class = Snabbast tid i klassen +Status as computed by your status method = Status beräknad av modulens statusmetod +Status code for a missing punch = Statuskod för saknad stämpling +Status code for a time over the maximum = Statuskod för uppnådd maxtid +Status code for a valid result = Statuskod för giltigt resultat +Status code for an unknown result = Statuskod för okänt resultat +Status code for disqualification = Statuskod för diskvalificering +Status code for not competing = Statuskod deltar ej +Status code for not finishing = Statuskod för utgått +Status code for not starting = Statuskod för ej start +Points as computed by your point method = Poäng beräknad av modulens poängmetod +Time as computed by your time method = Tid beräknad av modulens tidsmetod +Time after leg winner = Tid efter sträcksegrare +Finish time for each team member = Måltid för varje lagmedlem +Matched control ids (-1 for unmatched) for each team member = Matchade kontroller (-1 för omatchade) för varje lagmedlem +Punch codes for each team member = Stämplingskoder för varje lagmedlem +Punch times for each team member = Stämplingstider för varje lagmedlem +Rogaining points for each team member = Poäng för varje lagmedlem +Runner's method output numbers = Utdata (tal) från varje lagmedlem +Runner's method output times = Utdata (tid) från varje lagmedlem +Running time for each team member = Tid för varje lagmedlem +Start time for each team member = Starttid för varje lagmedlem +Status for each team member = Status för varje lagmedlem +Check: X = Check: X +Debug = Testkör +Debug Output = Resultat av testkörning +Debug X for Y = Testkör X med Y +Do you want to clear the card memory? = Vill du tömma backupminnet? +Portable Document Format (PDF) = Portable Document Format (PDF) +Poängavdrag = Poängavdrag +RunnerPointAdjustment = Deltagares poängjustering +RunnerTimeAdjustment = Deltagares tidsjustering +Save changes in rule code? = Spara ändringar i regelns kod? +Symboler = Symboler +TeamPointAdjustment = Lags poängjustering +TeamTimeAdjustment = Lags tidsjustering +Variabler = Variabler +Check: X = Check: X +Choose result module = Välj resultatmodul +Result Modules = Resultatmoduler +Error in result module X, method Y (Z) = Kompileringsfel i resultatmodul 'X', metod 'Y'\n\nZ +Invalid operator X = Felaktig operator X +Unknown symbol X = Okänd symbol X +RunnerGlobal = Deltagare (klasser gemensamt) +TeamGlobal = Lag (klasser gemensamt) +List Error: X = Fel i listan: X +Rader markerade med (*) kommer från en lista i tävlingen = Rader markerade med (*) kommer från en lista i tävlingen +Resultatmodulen används i X = Resultatmodulen används i X +Valfri = Valfri +Vill du sätta resultatet från tidigare etapper till ? = Vill du sätta resultatet från tidigare etapper till ? +Hantera deltagare som bytt klass = Hantera deltagare som har bytt klass +Välj klasser med nya anmälningar = Välj klasser med nya anmälningar +Byt till rätt klass (behåll eventuell starttid) = Byt till rätt klass (behåll eventuell starttid) +Byt till vakansplats i rätt klass (om möjligt) = Byt till vakansplats i rätt klass (om möjligt) +Tillåt ny klass, behåll resultat från annan klass = Tillåt ny klass, behåll resultat från annan klass +Tillåt ny klass, inget totalresultat = Tillåt ny klass, inget totalresultat +tooltip_explain_status = - = Okänd status\nOK = Godkänt resultat\nEj start = Startade inte\nFelst. = Felstämplat\nUtgått = Måltid saknas\nDisk. = Diskvalificerad\nDeltar ej = Springer inte tävlingen +Placering = Placering +Resultat från tidigare etapper = Resultat från tidigare etapper +Input Results = Ingångsresultat +Input Results - X = Ingångsresultat - X +Individuella resultat = Individuella resultat +Avdrag = Avdrag +Team Rogaining = Lag-rogaining +Övertid = Övertid +Kunde inte öppna tävlingen = Kunde inte öppna tävlingen +warn:opennewversion = Tävlingen är skapad i MeOS X. Data kan gå förlorad om du öppnar tävlingen.\n\nVill du fortsätta? +District id number = Distrikt-id +Kunde inte ladda X\n\n(Y) = Kunde inte ladda X\n\n(Y) +Narrow Results = Smal resultatlista +Club id number = Klubb-id +User input number = Användardefinierat inmatat värde +listinfo:singleclub = Skapa en resultatlista för en utvald klubb.\nAnvänd listparametern för att specificera klubb-Id. +listinfo:inputresults = Visa inkommande resultat från tidigare etapper. +Ett värde vars tolkning beror på listan = Ett värde vars tolkning beror på listan +Listparameter = Listparameter +Individual results in a club = Individuella resultat inom en klubb +OL-Skytte med tidstillägg = OL-Skytte med tidstillägg +OL-Skytte utan tidstillägg = OL-Skytte utan tidstillägg +OL-Skytte stafettresultat = OL-Skytte stafettresultat +olshooting:timepunishment = Resultatlista OL-Skytte med tidstillägg.\n\nFör att använda listan aktiverar du stöd för Rogaining och manuell poängjustering. Använd sedan fältet poängavdrag på sidan deltagare för att ange bommar på formatet PPPLLSS där PPP är är mm fel i punktorientering, LL är antal liggande bom och SS är antal stående bom. Exempel 30201 betyder 3 mm fel, 2 liggande och 1 stående bom. +olshooting:notimepunishment = Resultatlista OL-Skytte utan tidstillägg.\n\nFör att använda listan aktiverar du stöd för Rogaining och manuell poängjustering. Använd sedan fältet poängavdrag på sidan deltagare för att ange bommar på formatet LLSS där LL är antal liggande bom och SS är antal stående bom. Exempel: 0201 betyder 2 liggande och 1 stående bom. +Namnet kan inte vara tomt = Namnet kan inte vara tomt +Sluttid = Sluttid +Ingen / okänd = Ingen / okänd +Inget nummer = Inget nummer +Stafettresultat = Stafettresultat +Döp om X = Döp om X +Gräns för maxtid = Gräns för maxtid +Individual Example = Exempel (Individuell) +Long = Lång +MeOS Three Days Race X = MeOS Tredagars, etapp X +Medium = Medel +Open = Öppen +Open X = Öppen X +Prologue + Pursuit = Exempel (Prolog + Jaktstart) +Relay Example = Exempel (Stafett) +Short = Kort +Ultra Long = Ultralång +Tillgängliga filer installerades. Starta om MeOS. = Tillgängliga filer installerades. Starta om MeOS. +edit_in_forest = Redigera\nkvar-i-skogen +Latest Results = Senaste resultaten +warning:direct_result = Observera att förutsätter att alla kontrollstämplingar has sänts som radiokontroller, eller att MeOS används endast för tidtagning utan bana.\n\nAktivera resultat vid målstämpling? +Inställningar startbevis = Inställningar startbevis +Skrivarinställningar = Skrivarinställningar +Skrivarinställningar för sträcktider och startbevis = Skrivarinställningar för sträcktider och startbevis +Startbevis = Startbevis +Startbevis X = Startbevis X +Skriv ut startbevis = Skriv ut startbevis +Skriv ut startbevis för deltagaren = Skriv ut startbevis för deltagaren +Utskrift = Utskrift +Från klassen = Från klassen +Tillsätt ytterligare vakans = Tillsätt ytterligare vakans +Överföring = Överföring +Anmäl till efterföljande etapper = Anmäl till efterföljande etapper +Totalt antal etapper = Totalt antal etapper +Vill du använda den nya brickan till alla etapper? = Vill du använda den nya brickan till alla etapper? +Avkortad banvariant = Avkortad banvariant +Avkortning = Avkortning +Hantera laget = Hantera laget +Med avkortning = Med avkortning +info_shortening = Välj den existerande bana som förkortar aktuell bana. Flera nivåer av förkortningar är möjliga. +Tilldela starttider = Tilldela starttider +Avkortar: X = Avkortar: X +Vill du nollställa alla manuellt tilldelade banor? = Vill du nollställa alla manuellt tilldelade banor? +Ange löpande numrering eller första nummer i klassen = Ange löpande numrering eller första nummer i klassen +Ange relation mellan lagets och deltagarnas nummerlappar = Ange relation mellan lagets och deltagarnas nummerlappar +Lagmedlem = Lagmedlem +Löpande = Löpande +Oberoende = Oberoende +Samma = Samma +Ökande = Ökande +Manuell = Manuell +Vill du uppdatera alla nummerlappar? = Vill du uppdatera alla nummerlappar? +Hela banan = Hela banan +Ogiltigt maximalt intervall = Ogiltigt maximalt intervall +Startintervallet får inte vara kortare än basintervallet = Startintervallet får inte vara kortare än basintervallet +Ett startintervall måste vara en multipel av basintervallet = Ett startintervall måste vara en multipel av basintervallet +Ogiltigt minimalt intervall = Ogiltigt minimalt intervall +Ogiltigt basintervall = Ogiltigt basintervall +Country = Land +CourseShortening = Banavkortningar +Nationality = Nationalitet +Number of shortenings = Antal banavkortningar +Längd = Längd +Redigera sträcklängder = Redigera sträcklängder +Redigera sträcklängder för X = Redigera sträcklängder för 'X' +Oordnade parallella sträckor = Oordnade parallella sträckor +Tillåt löpare inom en parallell grupp att springa gruppens banor i godtycklig ordning = Tillåt löpare inom en parallell grupp att springa gruppens banor i godtycklig ordning +Laguppställningen hade fel, som har rättats = Laguppställningen hade fel, som har rättats +ControlClasses = Kontrolls klasser +ControlCodes = Kontrolls stämpelkoder +ControlCourses = Kontrolls banor +ControlMaxLostTime = Kontrolls största bomtid +ControlMedianLostTime = Kontrolls medianbomtid +ControlMistakeQuotient = Kontrolls bomkvot +ControlName = Kontrolls namn +ControlPunches = Kontrolls faktiska antal besökande +ControlRunnersLeft = Kontrolls antal kvarvarande deltagare +ControlVisitors = Kontrolls väntade antal besökande +CourseClasses = Banas klasser +CourseUsage = Banas antal anmälda +CourseUsageNoVacant = Banas antal anmälda (ej vakanta) +Bomkvot = Bomkvot +Control = Kontroll +Control Statistics = Kontrollstatistik +Control Statistics - X = Kontrollstatistik - X +Course = Bana +Deltagare (kvarvarande) = Deltagare (kvarvarande) +FilterSameParallel = Samlade parallella sträckor +Kontrollrapport - X = Kontrollrapport - X +Maxbom = Maxbom +Control Overview = Kontrollöversikt +Medianbom = Medianbom +N.N. = N.N. +Endast på obligatoriska sträckor = Endast på obligatoriska sträckor +Fyll obesatta sträckor i alla lag med anonyma tillfälliga lagmedlemmar (N.N.) = Fyll obesatta sträckor i alla lag med anonyma tillfälliga lagmedlemmar (N.N.) +Skapa anonyma lagmedlemmar = Skapa anonyma lagmedlemmar +Tillsätt tillfälliga anonyma lagmedlemmar = Tillsätt tillfälliga anonyma lagmedlemmar +Tillsätt = Tillsätt +help:anonymous_team = Skapa anonyma (tillfälliga) lagmedlemmar för samtliga lag, som kan tilldelas SI-bricka, karta etc. +Anonymt namn = Anonymt namn +Med anmälningsavgift (lagets klubb) = Med anmälningsavgift (lagets klubb) +Tar bort X = Tar bort X +Källa = Källa +Ta bort eventuella avanmälda deltagare = Ta bort eventuella avanmälda deltagare +Verktyg = Verktyg +Automatisk = Automatisk +Avstånd = Avstånd +Extra avstånd ovanför textblock = Extra avstånd ovanför textblock +FilterSameParallelNotFirst = Parallella efterföljande sträckor +RunnerLeg = Deltagare (per stafettsträcka) +Texten ska innehålla tecknet X, som byts ut mot tävlingsspecifik data = Texten ska innehålla tecknet X, som byts ut mot tävlingsspecifik data +Antal reserverade nummerlappsnummer mellan klasser = Antal reserverade nummerlappsnummer mellan klasser +help:bibs = Du kan hantera nummerlappar automatiskt eller manuellt. På den här sidan kan du tilldela nummerlappar manuellt för en viss klass genom att ange metoden Manuell och ange första nummerlappsnummer i klassen.\n\nMetoden automatisk fungerar på samma sätt med den skillnaden att MeOS uppdaterar nummerlapparna i alla klasser på en gång. Även om det går att göra den inställningen här, är det bättre att använda Snabbinställningar för klasser, där du får en överblick över alla klasser.\n\nMetoden automatisk är tänkt att användas tillsammans med metoderna Ingen och Löpande, vilken innebär att föregående klass sista nummer används som första nummer. Antal reserverade nummerlappar mellan klasser anger det hopp som görs i den löpande numreringen mellan klasser.\n\nFör lagklasser kan du ange hur laget nummerlappar förhåller sig till deltagarnas. De kan vara samma, oberoende, ökande (Lag 1: 101, 102, 103, 104, Lag 2: 111, 112, 113, 114, o.s.v.) eller ange sträcka (100-1, 100-2, 100-3 o.s.v.) +RunnerGeneralPlace = Löpares lags eller individuella placering +RunnerGeneralTimeAfter = Löpares lags eller individuella tid efter +RunnerGeneralTimeStatus = Löpares lags eller individuella tid/status +open_error = Kan inte öppna X.\n\nY. +open_error_locked = Tävlingen är redan öppnad i MeOS.\n\nDu måste använda en databas för att öppna flera instanser av tävlingen. +Ogiltigt bricknummer = Ogiltigt bricknummer +ask:updatelegs = Sträcklängderna kan behöva uppdateras efter att banan har ändrats.\n\nVill du göra det nu? +warn:updatelegs = Stäcklängderna kan behöva uppdateras efter att banan har ändrats. +Ingen deltagare vald = Ingen deltagare vald +Från klubben = Från klubben +Från laget = Från laget +Gafflingsnyckel X = Gafflingsnyckel X +help:teamwork = Löparna byter plats. Du kan utföra en följd av byten för att nå rätt laguppställning. +Ordnat = Ordnat +Str. X = Str. X +Vill du att X går in i laget? = Vill du att X går in i laget? +Vill du att X och Y byter sträcka? = Vill du att X och Y byter sträcka? +Vill du att X tar sträckan istället för Y? = Vill du att X tar sträckan istället för Y? +Ändra lagets gaffling = Ändra lagets gaffling +Deltagarens klass styrs av laget = Deltagarens klass styrs av laget +För att delta i en lagklass måste deltagaren ingå i ett lag = För att delta i en lagklass måste deltagaren ingå i ett lag +Dela upp = Dela upp +Alla sträckor = Alla sträckor +Liveresultat, deltagare = Liveresultat, deltagare +Använd enhets-id istället för tävlings-id = Använd enhets-id istället för tävlings-id +Enhetens ID-nummer (MAC) = Enhetens ID-nummer (MAC) +Antal deltagare: X = Antal deltagare: X +Dela efter placering = Dela efter placering +Dela efter tid = Dela efter tid +Dela slumpmässigt = Dela slumpmässigt +Jämna klasser (placering) = Jämna klasser (placering) +Jämna klasser (ranking) = Jämna klasser (ranking) +Jämna klasser (tid) = Jämna klasser (tid) +Klass X = Klass X +Not yet implemented = Funktionen saknas +Tidstillägg = Tidstillägg +help:seeding_info = Seedad lottning innebär att tidigare resultat eller ranking delvis styr lottningen. I fältet seedningsgrupper kan du antingen ange en gruppstorlek, varvid hela klassen delas in i grupper av denna storlek. Gruppstorleken "1" innebär ingen lottning utan seedningsordning rakt av. Du kan också ange flera gruppstorlekar. "15, 1000" innebär att en seedad grupp med de 15 bästa skapas och övriga (högst 1000) placeras i en (oseedad) grupp. +Ange en gruppstorlek (som repeteras) eller flera kommaseparerade gruppstorlekar = Ange en gruppstorlek (som repeteras) eller flera kommaseparerade gruppstorlekar +Hindra att deltagare från samma klubb startar på angränsande tider = Hindra att deltagare från samma klubb startar på angränsande tider +Låt de bästa start först = Låt de bästa start först +Seedningsgrupper = Seedningsgrupper +Seedningskälla = Seedningskälla +error:invalidmethod = Den valda metoden gav ingen uppdelning. Underliggande data är otillräcklig. +Ogiltig storlek på seedningsgrupper X = Ogiltig storlek på seedningsgrupper: X +Bananvändning = Bananvändning +Tabell = Tabell +Antal banor = Antal banor +Could not load list 'X' = Kunde inte ladda listan 'X' +Från den här listan kan man skapa etiketter att klistra på kartor = Från den här listan kan man skapa etiketter att klistra på kartor +Gafflingar i tabellformat = Gafflingar i tabellformat +Vakanser - X = Vakanser - X +Kopiera = Kopiera +Kopiera till urklipp = Kopiera till urklipp +RunnerStartCond = Deltagares starttid (om individuell) +StartTimeForClassRange = Klassens starttidsområde +TeamStartCond = Lags starttid (om individuell) +Liveresultat = Liveresultat +Visa rullande tider mellan kontroller i helskärmsläge = Visa rullande tider mellan kontroller i helskärmsläge +help:liveresultat = Den här funktionen startar en timer i helskärmsläge (storbildskärm) när en deltagare i vald klass stämplar kontrollen från, och tar tid tills slutkontrollen nås. Däremellen visas en topplista med de bästa resultaten. Gör de inställningar som krävs, dra fönstret till den skärm som ska användas och tryck på . Vid använding av nätverk bör vara aktiverat för att undvika fördröjningar. +Result at a control = Resultat vid kontroll +Total/team result at a control = Lag- och totalresultat vid kontroll +Vissa inställningar kräver omstart av MeOS för att ha effekt = Vissa inställningar kräver omstart av MeOS för att ha effekt +false[boolean] = falskt +prefsAccount = Förvalt kontonummer +prefsAddress = Förvald adress +prefsAdvancedClassSettings = Visa avancerade klassinställningar +prefsAutoSaveTimeOut = Automatiskt backupintervall (ms) +prefsAutoTie = Knyt bricka/deltagare automatiskt +prefsCardFee = Förvald brickavgift +prefsClient = Klientnamn i nätverket +prefsControlFrom = Senaste från-kontroll +prefsControlTo = Senaste till-kontroll +prefsCurrencyFactor = Skalfaktor för valuta +prefsCurrencyPreSymbol = Placera valutasymbol först +prefsCurrencySeparator = Decimalseparator för valuta +prefsCurrencySymbol = Valutasymbol +prefsDatabase = Använd löpardatabasen +prefsDatabaseUpdate = Senaste löparbasuppdatering +prefsDefaultDrawMethod = Förvald lottningsmetod +prefsDirectPort = Nätverksport för förhandsinformation om stämplingar +prefsEMail = Arrangörs e-post +prefsEliteFee = Förvald elitavgift +prefsEntryFee = Förvald anmälningsavgift +prefsEventorBase = URL till Eventor +prefsFirstInvoice = Nästa fakturanummer +prefsFirstTime = Första start av MeOS +prefsHomepage = Organisatörs hemsida +prefsInteractive = Interaktiv brickhantering +prefsLateEntryFactor = Faktor för efteranmälningsvgift +prefsLiveResultFont = Typesnitt för liveresultat +prefsMIPURL = URL till MIP-server +prefsMOPFolderName = Lokal MOP mapp +prefsMOPURL = URL till MOP-server +prefsManualInput = Använd manuell resultatimport +prefsMaximumSpeakerDelay = Största fördröjning i speakerstödet (ms) +prefsOrganizer = Organisatör +prefsPort = MySQL nätverksport +prefsRentCard = Hyr brickor +prefsSeniorAge = Åldersgräns för pensionärsavgift +prefsServer = Förvald nätverksserver +prefsSpeakerShortNames = Använd initialer i namn +prefsStreet = Organisatörs gatuadress +prefsSynchronizationTimeOut = Timeout i nätverksprotokollet (ms) +prefsTextFont = MeOS typsnitt +prefsUseDirectSocket = Använd snabb förhandsinformation om stämplingar +prefsUseEventor = Använd Eventor +prefsUseEventorUTC = Använd koordinerad universell tid i Eventor +prefsUseHourFormat = Använd tidsformat HH:MM:SS istället för MMM:SS +prefsUserName = MySQL användarnamn +prefsYouthAge = Åldersgräns ungdom +prefsYouthFee = Reducerad avgift +prefsaddressxpos = Adress x-koordinat på fakturor +prefsaddressypos = Adress y-koordinat på fakturor +prefsclasslimit = Begränsa visade resultat per klass +prefsintertime = Visa mellantider +prefspagebreak = Sidbrytning mellan klasser/klubbar/motsvarande +prefssplitanalysis = Utför sträcktidsanalys +true[boolean] = sant +Ändra MeOS lokala systemegenskaper = Ändra MeOS lokala systemegenskaper +Ändra X = Ändra X +Ingen parstart = Ingen parstart +Parvis (två och två) = Parvis (två och två) +X och Y[N by N] = X och Y +Lotta klasser med samma bana gemensamt = Lotta klasser med samma bana gemensamt +Lotta starttider = Lotta starttider +Lotta klasser med banan X = Lotta klasser med banan 'X' +MeOS Timing = MeOS Timing +Med resultat = Med resultat +Säkerhetskopiering = Säkerhetskopiering +Destination: X = Destination: X +Ogiltig destination X = Ogiltig destination X +Plats att exportera till = Plats att exportera till +Säkerhetskopierar om = Säkerhetskopierar om +Year of birth = Födelseår +Ogiltigt antal sekunder: X = Ogiltigt antal sekunder: X +Du kan använda en SI-enhet för att läsa in bricknummer = Du kan använda en SI-enhet för att läsa in bricknummer +Ignorera startstämpling = Ignorera startstämpling +Uppdatera inte starttiden vid startstämpling = Uppdatera inte starttiden vid startstämpling +Ändra lokala inställningar = Ändra lokala inställningar +Gafflingsnyckel = Gafflingsnyckel +Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD) = Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD) +Felaktigt tidsformat 'X' (Använd TT:MM:SS) = Felaktigt tidsformat 'X' (Använd TT:MM:SS) +Hämta inställningar från föregående lottning = Hämta inställningar från föregående lottning +Ej startstämpling = Ej startstämpling +Extraplatser = Extraplatser +Fritt = Fritt +Från lag = Från lag +Lag + sträcka = Lag + sträcka +Nummerlappshantering = Nummerlappshantering +Oordnade parallella = Oordnade parallella +Spara starttider = Spara starttider +X platser. Startar Y = X platser. Startar Y +övriga = övriga +RunnerStartZero = Deltagares starttid efter nolltid +TeamStartZero = Lags starttid efter nolltid +Datumfilter = Datumfilter +Inget filter = Inget filter +Inlästa stämplar = Inlästa stämplar +Löpare saknas = Löpare saknas +Klasserna X och Y har samma externa id. Använd tabelläget för att ändra id = Klasserna X och Y har samma externa id. Använd tabelläget för att ändra id +Vill du koppla isär X från inläst bricka Y? = Vill du koppla isär X från inläst bricka Y? +RunnerRogainingPointGross = Rogainingpoäng före avdrag +Samlade poäng = Samlade poäng +Tidsavdrag = Tidsavdrag +Total/team result at a control = Totalt-/lagresultat vid kontroll +X p = X p +Bricka X används också av = Bricka X används också av +reused card = återanvänd bricka +Varning: Brickan X används redan av Y = Varning: Brickan X används redan av Y +Invalid filter X = Invalid filter X +Invalid font X = Invalid font X +help:long_times = Tävlingsdatum avser det datum då alla klasser startar. Nolltiden är 00:00:00. +Aktivera stöd för tider över 24 timmar = Aktivera stöd för tider över 24 timmar +Inkludera information om flera lopp per löpare = Inkludera information om flera lopp per löpare +Alla uthyrda brickor har bockats av = Alla uthyrda brickor har bockats av +Avbockade brickor = Avbockade brickor +Avstämning hyrbrickor = Avstämning av hyrbrickor +Brickor markerade som både uthyrda och egna: X = Brickor markerade som både uthyrda och egna: X +Nollställ = Nollställ +Nollställ minnet; markera alla brickor som icke avbockade = Nollställ minnet; markera alla brickor som icke avbockade +Rapport = Rapport +Totalt antal unika avbockade brickor: X = Totalt antal unika avbockade brickor: X +Uthyrda brickor som inte avbockats = Uthyrda brickor som inte avbockats +Uthyrda: X, Egna: Y, Avbockade uthyrda: Z = Uthyrda: X, Egna: Y, Avbockade uthyrda: Z +Vill du göra om avbockningen från början igen? = Vill du göra om avstämningen från början igen? +help:checkcards = Använd den här funktionen för att räkna och kontrollera att alla hyrbrickor har återlämnats efter tävlingen. Anslut en SI enhet (förslagsvis programmerad som kontroll eller mål, eftersom det är snabbare än avläsning), och stämpla alla återlämnade brickor. Välj därefter rapport för att så om någon fattas.\n\n Kontrollen görs lokalt på den här datorn och ändrar inte i tävlingen. +Betalningsmetoder = Betalningsmetoder +help:paymentmodes = Du kan lägga till olika betalningsmetoder, utöver fakturering, för att kunna skilja dessa åt i bokföringen. +Betalsätt = Betalsätt +Förväntat antal besökare: X = Förväntat antal besökare: X +Starttiden är definerad genom klassen eller löparens startstämpling = Starttiden är definierad genom klassen eller löparens startstämpling +leder med X; har tappat Y = leder med X; har tappat Y +leder med X = leder med X +sekunder = sekunder +är X före Y = är X före Y +var först i mål med tiden X = var först i mål med tiden X +var först vid X med tiden Y = var först vid X med tiden Y +var först vid växeln med tiden X = var först vid växeln med tiden X +är nu på X plats med tiden Y = är nu på X plats med tiden Y +är nu på delad X plats med tiden Y = är nu på delad X plats med tiden Y +är X efter = är X efter +är X efter Y = är X efter Y +är X efter; har tappat Y = är X efter; har tappat Y +är X efter; har tagit in Y = är X efter; har tagit in Y +leder med X; har tappat Y = leder med X; har tappat Y +leder med X; sprang Y snabbare än de jagande = leder med X; sprang Y snabbare än de jagande +delar placering med X = delar placering med X +sekund = sekund +skickar ut X = skickar ut X +Export language = Exportspråk +Export split times = Exportera sträcktider +Climb (m) = Stigning (m) +Utrymme: X = Utrymme: X +[Radera] = [Radera] +prefsNumSplitsOnePage = Antal sträcktidsutskrifter per sida +prefsPayModes = Betalningsalternativ +prefsSplitPrintMaxWait = Längsta tid att vänta på sträcktider +prefsWideSplitFormat = Skriv sträcktider på brett papper +ClassTeamLegResult = Klass och sträckresultat +SortLastNameOnly = Efternamn +Databaskälla = Databaskälla +Filnamn IOF (xml) eller OE (csv) med löpare = Filnamn IOF (xml) eller OE (csv) med löpare +Importinställning = Importinställning +prefsExportCSVSplits = Inkludera sträcktider vid csv export +prefsExportFormat = Förvalt exportformat +prefsImportOptions = Förvalt importformat +prefsSplitLateFees = Dela upp tävlingsavgift i normal och sen del för IOF XML export +Längsta tid i sekunder att vänta med utskrift = Längsta tid i sekunder att vänta med utskrift +Max antal brickor per sida = Max antal brickor per sida +Sträcktider i kolumner (för standardpapper) = Sträcktider i kolumner (för standardpapper) +Spara inmatade tider i tävlingen utan att tilldela starttider = Spara inmatade tider i tävlingen utan att tilldela starttider +SRR Dongle = SRR Dongle +red channel = röd kanal +blue channel = blå kanal +Printing failed (X: Y) Z = Utskrift misslyckades (X: Y) Z +prefsNameMode = Namnformat: 0 = 'Förnamn Efternamn', 1 = 'Efternamn, Förnamn' diff --git a/code/testmeos.cpp b/code/testmeos.cpp new file mode 100644 index 0000000..4c51294 --- /dev/null +++ b/code/testmeos.cpp @@ -0,0 +1,453 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include +#include "testmeos.h" + +#include "gdioutput.h" +#include "meosexception.h" +#include "gdistructures.h" +#include "meos_util.h" +#include "localizer.h" +#include "oEvent.h" +#include "TabSI.h" +#include "SportIdent.h" +#include "metalist.h" +#include "Table.h" + +void registerTests(TestMeOS &tm); + +TestMeOS::TestMeOS(oEvent *oe, const string &test) : oe_main(oe), + gdi_main(&oe->gdibase), + test(test), status(NORUN) { + testId = 0; + testIdMain = &testId; + registerTests(*this); + testId = 0; +} + +TestMeOS::TestMeOS(TestMeOS &tmIn, const char *test) : oe_main(tmIn.oe_main), + gdi_main(tmIn.gdi_main), + test(test), status(NORUN) { + testIdMain = 0; + testId = 0; +} + +TestMeOS::TestMeOS(const TestMeOS &tmIn, gdioutput &newWindow) : oe_main(tmIn.oe_main), + gdi_main(&newWindow), + status(NORUN) { + testIdMain = 0; + testId = 0; +} + + +TestMeOS::~TestMeOS() { + for (size_t k = 0; k < subTests.size(); k++) { + delete subTests[k]; + } + subTests.clear(); +} + +TestMeOS * TestMeOS::newInstance() const { + throw meosException("Unsupported"); +} + +void TestMeOS::publishChildren(gdioutput &gdi, pair &passFail) const { + if (status == FAILED) { + ++passFail.second; + gdi.addStringUT(1, "FAILED " + test).setColor(colorRed); + if (!message.empty()) + gdi.addStringUT(0, message); + } + else if (status == NORUN) { + gdi.addStringUT(1, "DNS: " + test).setColor(colorDarkBlue); + } + else if (status == RUNNING) { + gdi.addStringUT(1, "Running: " + test).setColor(colorDarkBlue); + } + else if (status == PASSED) { + ++passFail.first; + gdi.addStringUT(1, "PASSED " + test).setColor(colorGreen); + } + + if (!subTests.empty()) { + gdi.dropLine(0.5); + int cx = gdi.getCX(); + gdi.setCX(cx + gdi.scaleLength(10)); + for (size_t j = 0; j < subTests.size(); j++) { + subTests[j]->publishChildren(gdi, passFail); + } + gdi.setCX(cx); + } +} + +void TestMeOS::publish(gdioutput &gdi) const { + gdi.clearPage(true); + gdi.addStringUT(boldLarge, "Test Results"); + gdi.dropLine(); + pair passFail; + for (size_t j = 0; j < subTests.size(); j++) { + subTests[j]->publishChildren(gdi, passFail); + } + + gdi.dropLine(); + gdi.addString("", 1, "X tests failed, Y tests passed.#" + itos(passFail.second) + + "#" + itos(passFail.first)); + + gdi.refresh(); +} + +void TestMeOS::run() const { +} + +void TestMeOS::runProtected(bool protect) const { + cleanup(); + gdi_main->setOnClearCb(0); + gdi_main->setPostClearCb(0); + gdi_main->clearPage(false, false); + subWindows.clear(); + oe_main->clear(); + gdi_main->isTestMode = true; + showTab(TCmpTab); + string tp = oe_main->getPropertyString("TestPath", ""); + oe_main->useDefaultProperties(true); + oe_main->setProperty("FirstTime", 0); + oe_main->setProperty("TestPath", tp); + oe_main->getPropertyInt("UseEventor", 1); + + //string pmOrig = oe_main->getPropertyString("PayModes", ""); + //oe_main->setProperty("PayModes", ""); + try { + status = RUNNING; + run(); + gdi_main->clearDialogAnswers(true); + status = PASSED; + if (protect) { + gdi_main->setOnClearCb(0); + gdi_main->setPostClearCb(0); + gdi_main->clearPage(false, false); + oe_main->clear(); + showTab(TCmpTab); + } + gdi_main->isTestMode = false; + } + catch (const meosAssertionFailure & ex) { + status = FAILED; + oe_main->useDefaultProperties(false); + gdi_main->clearDialogAnswers(false); + gdi_main->isTestMode = false; + subWindows.clear(); + message = ex.message; + //oe_main->setProperty("PayModes", pmOrig); + if (!protect) + throw meosException(message); + } + catch (const std::exception &ex) { + status = FAILED; + oe_main->useDefaultProperties(false); + gdi_main->clearDialogAnswers(false); + gdi_main->isTestMode = false; + subWindows.clear(); + //oe_main->setProperty("PayModes", pmOrig); + message = ex.what(); + if (!protect) + throw; + } + catch (...) { + status = FAILED; + oe_main->useDefaultProperties(false); + gdi_main->clearDialogAnswers(false); + gdi_main->isTestMode = false; + subWindows.clear(); + //oe_main->setProperty("PayModes", pmOrig); + message = "Unknown Exception"; + cleanup(); + if (!protect) + throw; + } + //oe_main->setProperty("PayModes", pmOrig); + oe_main->useDefaultProperties(false); + + for (size_t k = 0; k < tmpFiles.size(); k++) + removeTempFile(tmpFiles[k]); + tmpFiles.clear(); + + if (protect) { + cleanup(); + } +} + +void TestMeOS::runAll() const { + runInternal(true); +} + +void TestMeOS::runInternal(bool protect) const { + runProtected(protect); + for (size_t k = 0; k < subTests.size(); k++) + subTests[k]->runInternal(protect); +} + +bool TestMeOS::runSpecific(int id) const { + if (id == testId) { + runInternal(false); + return true; + } + else { + for (size_t k = 0; k < subTests.size(); k++) { + if (subTests[k]->runSpecific(id)) + return true; + } + } + return false; +} + +void TestMeOS::getTests(vector< pair > &tl) const { + tl.push_back(make_pair(test, testId)); + for (size_t k = 0; k < subTests.size(); k++) { + subTests[k]->getTests(tl); + } +} + +TestMeOS &TestMeOS::registerTest(const TestMeOS &test) { + subTests.push_back(test.newInstance()); + subTests.back()->testId = ++(*testIdMain); + subTests.back()->testIdMain = testIdMain; + return *subTests.back(); +} + +void mainMessageLoop(HACCEL hAccelTable, DWORD time); + +void TestMeOS::showTab(TabType type) const { + if (gdi_main->canClear()) { + gdi_main->getTabs().get(type)->loadPage(*gdi_main); + mainMessageLoop(0, 50); + } +} + +void TestMeOS::press(const char *btn) const { + gdi_main->dbPress(btn, -65536); + mainMessageLoop(0, 50); +} + +void TestMeOS::press(const char *btn, int extra) const { + gdi_main->dbPress(btn, extra); + mainMessageLoop(0, 50); +} + +void TestMeOS::press(const char *btn, const char *extra) const { + gdi_main->dbPress(btn, extra); + mainMessageLoop(0, 50); +} + +string TestMeOS::selectString(const char *id, const char *data) const { + int d = gdi_main->getItemDataByName(id, data); + if (d == -1) + throw meosException(string(data) + string(" not found in ") + id); + string res = gdi_main->dbSelect(id, d); + mainMessageLoop(0, 50); + return res; +} + +string TestMeOS::select(const char *id, size_t data) const { + string res = gdi_main->dbSelect(id, data); + mainMessageLoop(0, 50); + return res; +} + +void TestMeOS::dblclick(const char *id, size_t data) const { + gdi_main->dbDblClick(id, data); +} + +void TestMeOS::input(const char *id, const char *data) const { + string arg; + while(*data) { + if (*data == '\n') { + arg.push_back('\r'); + arg.push_back('\n'); + } + else { + arg.push_back(*data); + } + data++; + } + gdi_main->dbInput(id, arg); + mainMessageLoop(0, 50); +} + +void TestMeOS::click(const char *id) const { + gdi_main->dbClick(id, -65536); + mainMessageLoop(0, 50); +} + +void TestMeOS::click(const char *id, int extra) const { + gdi_main->dbClick(id, extra); + mainMessageLoop(0, 50); +} + + +string TestMeOS::getText(const char *ctrl) const { + return gdi_main->getText(ctrl, false); +} + +bool TestMeOS::isChecked(const char *ctrl) const { + return gdi_main->isChecked(ctrl); +} + +void TestMeOS::assertEquals(const string &expected, + const string &value) const { + if (expected != value) + throw meosAssertionFailure("Expected " + expected + " but got " + value); +} + +void TestMeOS::assertEquals(int expected, int value) const { + assertEquals(itos(expected), itos(value)); +} + +void TestMeOS::assertTrue(const char *message, bool condition) const { + assertEquals(message, "true", condition ? "true" : "false"); +} + +void TestMeOS::assertEquals(const string &message, + const string &expected, + const string &value) const { + if (expected != value) + throw meosAssertionFailure(message + ": Expected " + expected + " but got " + value); +} + +void TestMeOS::assertEquals(const char *message, + const char *expected, + const string &value) const { + assertEquals(string(message), string(expected), value); +} + +void TestMeOS::checkString(const char *str, int count) const { + int c = gdi_main->dbGetStringCount(str, false); + assertEquals("String " + string(str) + " not found", itos(count), itos(c)); +} + +void TestMeOS::checkSubString(const char *str, int count) const { + int c = gdi_main->dbGetStringCount(str, true); + assertEquals("String " + string(str) + " not found", itos(count), itos(c)); +} + + +void TestMeOS::checkStringRes(const char *str, int count) const { + int c = gdi_main->dbGetStringCount(lang.tl(str), false); + assertEquals("String " + string(str) + " not found", itos(count), itos(c)); +} + + +void TestMeOS::insertCard(int cardNo, const char *ser) const { + SICard sic; + sic.CardNumber = cardNo; + sic.deserializePunches(ser); + TabSI::getSI(*gdi_main).addCard(sic); + mainMessageLoop(0, 100); +} + +void TestMeOS::setAnswer(const char *ans) const { + gdi_main->dbPushDialogAnswer(ans); +} + +void TestMeOS::setFile(const string &file) const { + gdi_main->dbPushDialogAnswer("*" + file); +} + +void TestMeOS::cleanup() const { +} + +int TestMeOS::getResultModuleIndex(const char *tag) const { + vector< pair > > mol; + oe_main->getGeneralResults(false, mol, true); + for (size_t k = 0; k < mol.size(); k++) { + if (mol[k].second.first == tag) { + return mol[k].first; + } + } + throw meosException(string("Result module not found: ") + tag); +} + +int TestMeOS::getListIndex(const char *name) const { + vector< pair > lst; + oe_main->getListContainer().getLists(lst, false, false, false); + for (size_t k = 0; k < lst.size(); k++) { + if (lst[k].first == lang.tl(name)) + return lst[k].second; + } + throw meosException(string("List not found: ") + name); +} + +const string &getLastExtraWindow(); + +const string TestMeOS::getLastExtraWindow() const { + return ::getLastExtraWindow(); +} + +const TestMeOS &TestMeOS::getExtraWindow(const string &tag) const { + gdioutput *ge = ::getExtraWindow(tag, false); + if (ge == 0) + throw meosException(string("Window not found: ") + tag); + + subWindows.push_back(TestMeOS(*this, *ge)); + return subWindows.back(); +} + +void TestMeOS::pressEscape() const { + gdi_main->doEscape(); +} + +void TestMeOS::closeWindow() const { + gdi_main->closeWindow(); +} + +string TestMeOS::getTestFile(const char *relPath) const { + string tp = oe_main->getPropertyString("TestPath", ""); + if (tp.length() == 0) + return relPath; + else if (*tp.rbegin() == '\\') + return tp + relPath; + else + return tp + "\\" + relPath; +} + +string TestMeOS::getTempFile() const { + string fn = ::getTempFile(); + tmpFiles.push_back(fn); + return fn; +} + +void TestMeOS::tableCmd(const char *id) const { + gdi_main->processToolbarMessage(id, &gdi_main->getTable()); + mainMessageLoop(0, 50); +} + +void TestMeOS::setTableText(int editRow, int editCol, const string &text) const { + Table &t = gdi_main->getTable(); + t.setTableText(*gdi_main, editRow, editCol, text); + mainMessageLoop(0, 50); +} + +string TestMeOS::getTableText(int editRow, int editCol) const { + Table &t = gdi_main->getTable(); + return t.getTableText(*gdi_main, editRow, editCol); +} diff --git a/code/testmeos.h b/code/testmeos.h new file mode 100644 index 0000000..1299e2b --- /dev/null +++ b/code/testmeos.h @@ -0,0 +1,147 @@ +#pragma once + +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +class gdioutput; +class oEvent; +class BaseInfo; + +#include +#include "TabBase.h" + +enum GDICOLOR; +enum PropertyType; + +enum TestStatus { + PASSED, + FAILED, + NORUN, + RUNNING, +}; + +struct meosAssertionFailure { + meosAssertionFailure() {message = "MeOS assertion failure";}; + meosAssertionFailure(const string &err) : message(err) {} + string message; +}; + +class TestMeOS { +private: + oEvent *oe_main; + gdioutput *gdi_main; + string test; + vector subTests; + void runProtected(bool protect) const; + mutable list subWindows; + mutable vector tmpFiles; + + mutable TestStatus status; + mutable string message; + int testId; + int *testIdMain; // Pointer to main test id + + // Subwindow constructor + TestMeOS(const TestMeOS &tmIn, gdioutput &newWindow); + +protected: + oEvent &oe() {return *oe_main;} + const oEvent &oe() const {return *oe_main;} + + TestMeOS ®isterTest(const TestMeOS &test); + + void showTab(TabType type) const; + + void insertCard(int cardNo, const char *ser) const; + + void assertEquals(int expected, int value) const; + void assertEquals(const string &expected, const string &value) const; + void assertEquals(const char *message, const char *expected, const string &value) const; + void assertEquals(const string &message, const string &expected, const string &value) const; + + void assertTrue(const char *message, bool condition) const; + + int getResultModuleIndex(const char *tag) const; + int getListIndex(const char *name) const; + int getResultListIndex(const char *name) const { + return 10 + getListIndex(name); + } + + virtual TestMeOS *newInstance() const; + + void publishChildren(gdioutput &gdi, pair &passFail) const; + + + const string getLastExtraWindow() const; + const TestMeOS &getExtraWindow(const string &tag) const; + + void runInternal(bool protect) const; + virtual void cleanup() const; +public: + gdioutput &gdi() const {return *gdi_main;} + + void pressEscape() const; + void closeWindow() const; + + void press(const char *btn) const; + void press(const char *btn, int extra) const; + void press(const char *btn, const char *extra) const; + + string selectString(const char *btn, const char *data) const; + string select(const char *btn, size_t data) const; + void input(const char *id, const char *data) const; + void click(const char *id) const; + void click(const char *id, int extra) const; + + void dblclick(const char *id, size_t data) const; + + void tableCmd(const char *id) const; + void setTableText(int editRow, int editCol, const string &text) const; + string getTableText(int editRow, int editCol) const; + + void setAnswer(const char *ans) const; + void setFile(const string &file) const; + + void checkString(const char *str, int count = 1) const; + void checkStringRes(const char *str, int count = 1) const; + void checkSubString(const char *str, int count = 1) const; + + string getText(const char *ctrl) const; + bool isChecked(const char *ctrl) const; + + void runAll() const; + bool runSpecific(int id) const; + + void publish(gdioutput &gdi) const; + void getTests(vector< pair > &tl) const; + + string getTestFile(const char *relPath) const; + string getTempFile() const; + + virtual void run() const; + + TestMeOS(oEvent *oe, const string &test); + TestMeOS(TestMeOS &tmIn, const char *test); + virtual ~TestMeOS(); + + friend void registerTests(TestMeOS &tm); +}; diff --git a/code/tests.cpp b/code/tests.cpp new file mode 100644 index 0000000..7207b4b --- /dev/null +++ b/code/tests.cpp @@ -0,0 +1,14 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ +#include "stdafx.h" + +#include "testmeos.h" + +void registerTests(TestMeOS &tm) { +} diff --git a/code/thirdpartylicense.txt b/code/thirdpartylicense.txt new file mode 100644 index 0000000..01b7dd5 --- /dev/null +++ b/code/thirdpartylicense.txt @@ -0,0 +1,114 @@ + +MySQL++: + +/*********************************************************************** + Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by + MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc. + Others may also hold copyrights on code in this file. See the CREDITS + file in the top directory of the distribution for details. + + This file is part of MySQL++. + + MySQL++ 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 of the License, or + (at your option) any later version. + + MySQL++ 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 MySQL++; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA +***********************************************************************/ + +CREDITS + +MySQL++ was created by Kevin Atkinson during 1998. From version 1.0 +(released in June 1999) through 1.7.9 (May 2001), the primary maintainer +was Sinisa Milivojevic . Neither Kevin nor Sinisa +are currently involved in MySQL++ development. The current maintainer +is Warren Young , starting with version 1.7.10 in +August of 2004. + +For a fuller account of the library's history, see the first chapter +of the user manual. For the nitty-gritty details, see the ChangeLog +in the root package directory. ChangeLog items since 1.7.9 that +aren't attributed to anyone else were done by Warren Young. + + +Other contributors of note since 1.7.10: + + Chris Frey : Lots of GCC warning fixes for + the bleeding-edge compiler versions, and Gentoo ebuild support. + Also, if there were a "steering committee" for MySQL++, he'd be + on it. + + Mark Meredino : Several fixes and + additions, including a lot of work on Microsoft Visual C++ + compatibility, and discoveries made while spelunking in the + library. + + Evan Wies : Contributed several C++ code + style cleanups. + + Arnon Jalon : Added the multi-query + result set handling features, and multiquery example to demonstrate + it. + + Korolyov Ilya has submitted several patches in many different + areas of the library. + + Remi Collet is maintaining offical + RPMs for Fedora, with other systems on the way. His work has + improved the RPM spec file we distribute greatly. + + Joel Fielder came up with the + original idea for Query::for_each() and Query::store_in(), + provided the basis for examples/for_each.cpp, and provided + a fix for exception flag propagation in Query. + + +Here are the personal credits from the old 1.7.9 documentation, +apparently written by Kevin Atkinson: + + Chris Halverson - For helping me get it to compile under Solaris. + + Fredric Fredricson - For a long talk about automatic conversions. + + Michael Widenius - MySQL developer who has been very supportive of + my efforts. + + Paul J. Lucas - For the original idea of treating the query object + like a stream. + + Scott Barron - For helping me with the shared libraries. + + Jools Enticknap - For giving me the Template Queries idea. + + M. S. Sriram - For a detailed dission of how the Template Queries + should be implemented, the suggestion to throw exceptions on bad + queries, and the idea of having a back-end independent query + object (ie SQLQuery). + + Sinisa Milivojevic - For becoming the new offical maintainer. + + D. Hawkins and E. Loic for their autoconf + automake contribution. + + +See the ChangeLog for further credits, and details about the differences +between the many versions of this library. + + +Please do not email any of these people with general questions about +MySQL++. All of us who are still active in MySQL++ development read the +mailing list, so questions sent there do get to us: + + http://lists.mysql.com/plusplus + +The mailing list is superior to private email because the answers are +archived for future questioners to find, and because you are likely to +get answers from more people. diff --git a/code/toolbar.cpp b/code/toolbar.cpp new file mode 100644 index 0000000..6ab3d52 --- /dev/null +++ b/code/toolbar.cpp @@ -0,0 +1,321 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "resource.h" +#include + +#include "oEvent.h" +#include "xmlparser.h" + +#include "gdioutput.h" +#include "commctrl.h" +#include "SportIdent.h" +#include "TabBase.h" +#include "TabCompetition.h" +#include "TabAuto.h" +#include "TabClass.h" +#include "TabCourse.h" +#include "TabControl.h" +#include "TabSI.h" +#include "TabList.h" +#include "TabTeam.h" +#include "TabSpeaker.h" +#include "TabMulti.h" +#include "TabRunner.h" +#include "TabClub.h" +#include "progress.h" +#include "inthashmap.h" +#include +#include "localizer.h" +#include "intkeymap.hpp" +#include "intkeymapimpl.hpp" +#include "download.h" +#include "meos_util.h" +#include "toolbar.h" + +const char *szToolClass = "MeOSToolClass"; + +LRESULT CALLBACK ToolProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +#define BASE_ID 1013 + + +const DWORD buttonStyles = BTNS_AUTOSIZE; +const int bitmapSize = 24; + +Toolbar::Toolbar(gdioutput &gdi_par) : gdi(gdi_par), data(0) +{ + hwndFloater = 0; + hwndToolbar = 0; + + isactivating = false; + // Create the imagelist. + hImageListDef = ImageList_Create(bitmapSize, bitmapSize, ILC_COLOR24 | ILC_MASK, 1, 15); + //hImageListMeOS = ImageList_Create(bitmapSize, bitmapSize, ILC_COLOR16 | ILC_MASK, 1, 10); + hImageListMeOS = ImageList_LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(BMP_TEST), + bitmapSize, 17, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION); + +} + + +Toolbar::~Toolbar() +{ + ImageList_Destroy(hImageListDef); + ImageList_Destroy(hImageListMeOS); +} + +void Toolbar::reset() +{ + btn.clear(); + tooltips.clear(); + btn_id.clear(); + toolbar_id.clear(); + DestroyWindow(hwndToolbar); + hwndToolbar = 0; +} + +void Toolbar::show() { + if (hwndFloater) + ShowWindow(hwndFloater, SW_NORMAL); +} + +void Toolbar::hide() { + if (hwndFloater) + ShowWindow(hwndFloater, SW_HIDE); +} + +void Toolbar::activate(bool active) { + if (!isactivating && isVisible()) { + isactivating = true; + //SendMessage(hwndFloater, WM_NCACTIVATE, active ? 1:0, 0); + DefWindowProc(hwndFloater, WM_NCACTIVATE, active ? 1:0, 0); + isactivating = false; + } +} + +void Toolbar::addButton(const string &id, int imgList, int icon, const string &tooltip) +{ + tooltips.push_back(lang.tl(tooltip)); + TBBUTTON tbButton = { MAKELONG(icon, imgList), btn_id.size() + BASE_ID, TBSTATE_ENABLED, + buttonStyles, {0}, 0, (INT_PTR)tooltips.back().c_str() }; + btn.push_back(tbButton); + btn_id.push_back(id); +} + + +void Toolbar::processCommand(int id, int code) +{ + size_t ix = id - BASE_ID; + if (ix < btn_id.size()) { + gdi.processToolbarMessage(btn_id[ix], data); + } +} + +void registerToolbar(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)ToolProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = 0; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = szToolClass; + wcex.hIconSm = 0; + + RegisterClassEx(&wcex); +} + +void Toolbar::createToolbar(const string &id, const string &title) +{ + if (id == toolbar_id) { + show(); + return; + } + + string t = lang.tl(title); + HWND hParent = gdi.getHWND(); + RECT rc; + GetWindowRect(hParent, &rc); + if (hwndFloater == 0) { + hwndFloater = CreateWindowEx(WS_EX_TOOLWINDOW, szToolClass, t.c_str(), + WS_POPUP | WS_THICKFRAME | WS_CAPTION, + rc.right-300, rc.top+10, 600, 64, hParent, NULL, GetModuleHandle(0), NULL); + + SetWindowLongPtr(hwndFloater, GWL_USERDATA, LONG_PTR(this)); + } + else { + SetWindowText(hwndFloater, t.c_str()); + } + + if (hwndToolbar != 0) + DestroyWindow(hwndToolbar); + + // Create the toolbar. + hwndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, + WS_CHILD | TBSTYLE_TOOLTIPS, + 0, 0, 0, 0, hwndFloater, NULL, GetModuleHandle(0), NULL); + + if (hwndToolbar == NULL) + return; + + toolbar_id = id; + + int ImageListID = 0; + + SendMessage(hwndToolbar, CCM_SETVERSION, 5, 0); + + // Set the image list. + SendMessage(hwndToolbar, TB_SETIMAGELIST, (WPARAM)ImageListID, + (LPARAM)hImageListDef); + + // Load the button images. + SendMessage(hwndToolbar, TB_LOADIMAGES, (WPARAM)IDB_STD_LARGE_COLOR, + (LPARAM)HINST_COMMCTRL); + + ImageListID = 1; + // Set the image list. + SendMessage(hwndToolbar, TB_SETIMAGELIST, (WPARAM)ImageListID, + (LPARAM)hImageListMeOS); + + // Add buttons. + SendMessage(hwndToolbar, TB_BUTTONSTRUCTSIZE, + (WPARAM)sizeof(TBBUTTON), 0); + TBBUTTON *bt_ptr = &btn.at(0); + SendMessage(hwndToolbar, TB_ADDBUTTONS, (WPARAM)btn.size(), + (LPARAM)bt_ptr); + + SendMessage(hwndToolbar, TB_SETMAXTEXTROWS, 0, 0); + // Tell the toolbar to resize itself, and show it. + SendMessage(hwndToolbar, TB_AUTOSIZE, 0, 0); + + DWORD bsize = SendMessage(hwndToolbar, TB_GETBUTTONSIZE, 0,0); + int bw = LOWORD(bsize); + int bh = HIWORD(bsize); + + int tw = bw * btn.size(); + + // Resize floater + GetClientRect(hwndFloater, &rc); + + int dx = rc.right - rc.left - tw; + int dy = rc.bottom - rc.top - bh - 5; + + WINDOWPLACEMENT wpl; + wpl.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(hwndFloater, &wpl); + + wpl.rcNormalPosition.right -= dx; + wpl.rcNormalPosition.bottom -= dy; + + HWND desktop = GetDesktopWindow(); + GetClientRect(desktop, &rc); + dx = 0; + dy = 0; + if (wpl.rcNormalPosition.right > rc.right) + dx = wpl.rcNormalPosition.right - rc.right + 10; + else if (wpl.rcNormalPosition.left < 0) + dx = wpl.rcNormalPosition.left - 10; + + if (wpl.rcNormalPosition.bottom > rc.bottom) + dy = wpl.rcNormalPosition.bottom - rc.bottom + 10; + else if (wpl.rcNormalPosition.top < 0) + dy = wpl.rcNormalPosition.top - 30; + + if (dx != 0 || dy != 0) { + OffsetRect(&wpl.rcNormalPosition, -dx, -dy); + } + + SetWindowPlacement(hwndFloater, &wpl); + + SendMessage(hwndToolbar, TB_AUTOSIZE, 0, 0); + + ShowWindow(hwndFloater, SW_SHOW); + ShowWindow(hwndToolbar, TRUE); +} + +LRESULT CALLBACK ToolProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + + switch (message) + { + case WM_CREATE: + break; + + case WM_SIZE: + break; + + case WM_WINDOWPOSCHANGED: + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_ACTIVATE: + return DefWindowProc(hWnd, message, wParam, lParam); + + case WM_NCACTIVATE: { + Toolbar *tb = (Toolbar *)GetWindowLongPtr(hWnd, GWL_USERDATA); + if (tb) { + //DefWindowProc(tb->gdi.getHWND(), message, wParam, lParam); + SendMessage(tb->gdi.getMain(), message, wParam, lParam); + } + return DefWindowProc(hWnd, message, wParam, lParam); + } + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + break; + + case WM_DESTROY: + break; + + case WM_COMMAND: { + Toolbar *tb = (Toolbar *)GetWindowLongPtr(hWnd, GWL_USERDATA); + int id = LOWORD(wParam); + int code = HIWORD(wParam); + if (tb) { + tb->processCommand(id, code); + } + } + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +HWND Toolbar::getFloater() const { + return hwndFloater; +} + +bool Toolbar::isVisible() const { + if (!hwndFloater) + return false; + return IsWindowVisible(hwndFloater) != 0; +} diff --git a/code/toolbar.h b/code/toolbar.h new file mode 100644 index 0000000..04d8126 --- /dev/null +++ b/code/toolbar.h @@ -0,0 +1,67 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include "stdafx.h" +#include "gdioutput.h" + + +#pragma warning( disable : 4512 ) +class Toolbar { + HWND hwndFloater; + HWND hwndToolbar; + + HIMAGELIST hImageListDef; + HIMAGELIST hImageListMeOS; + + gdioutput &gdi; + + vector btn; + vector btn_id; + list tooltips; + void *data; + + string toolbar_id; + + void processCommand(int id, int code); + bool isactivating; +public: + + void show(); + void hide(); + void activate(bool active); + + HWND getFloater() const; + bool isVisible() const; + + void setData(void *d) {data = d;} + + void reset(); + void addButton(const string &id, int imgList, int icon, const string &tooltip); + + void createToolbar(const string &id, const string &title); + bool isLoaded(const string &id) const {return toolbar_id == id;} + Toolbar(gdioutput &gdi_par); + virtual ~Toolbar(); + + friend LRESULT CALLBACK ToolProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +}; + diff --git a/code/xmlparser.cpp b/code/xmlparser.cpp new file mode 100644 index 0000000..21aa12b --- /dev/null +++ b/code/xmlparser.cpp @@ -0,0 +1,766 @@ +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +// xmlparser.cpp: implementation of the xmlparser class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "xmlparser.h" +#include "meos_util.h" +#include "progress.h" +#include "meosexception.h" +#include "gdioutput.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + +xmlparser::xmlparser(gdioutput *utfConverter_) : utfConverter(utfConverter_) +{ + progress = 0; + lastIndex = 0; + tagStackPointer=0; + isUTF = false; + cutMode = false; + toString = false; +} + +xmlparser::~xmlparser() +{ + delete progress; + fin.close(); + foutFile.close(); +} + +inline bool isBlankSpace(char b) { + return b == ' ' || b == '\t' || b == '\n' || b == '\r'; +} + +void xmlparser::setProgress(HWND hWnd) +{ + progress = new ProgressWindow(hWnd); +} + +void xmlparser::access(int index) { + if (progress && (index-lastIndex)>1000 ) { + lastIndex = index; + progress->setProgress(500 + int(500.0 * index/xmlinfo.size())); + } +} + + +xmlobject::xmlobject() +{ + parser = 0; +} + +xmlobject::~xmlobject() +{ + //MessageBox(NULL, name.c_str(), "Destroying: ", MB_OK); + +// if (objects) delete objects; +} + + +const string &xmlparser::encodeXML(const string &input) { + if (utfConverter) + return ::encodeXML(utfConverter->toUTF8(input)); + else + return ::encodeXML(input); +} + +void xmlparser::write(const char *tag, const string &Value) +{ + if (!cutMode || Value!="") { + fOut() << "<" << tag << ">" + << encodeXML(Value) + << "" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + +void xmlparser::write(const char *tag) +{ + fOut() << "<" << tag << "/>" << endl; + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + +void xmlparser::write(const char *tag, const char *Property, const string &Value) +{ + if (!cutMode || Value!="") { + fOut() << "<" << tag << " " << Property << "=\"" + << encodeXML(Value) << "\"/>" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + +void xmlparser::write(const char *tag, const char *prop, const char *value) +{ + write(tag, prop, string(value)); +} + +void xmlparser::write(const char *tag, const char *prop, bool value) +{ + if (!cutMode || value) + write(tag, prop, value ? "true" : "false"); +} + + +void xmlparser::write(const char *tag, const char *Property, const string &PropValue, const string &Value) +{ + if (!cutMode || Value != "" || PropValue != "") { + fOut() << "<" << tag << " " << Property << "=\"" + << encodeXML(PropValue) << "\">" << encodeXML(Value) + << "" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + +void xmlparser::write(const char *tag, const vector< pair > &propValue, const string &value) { + if (!cutMode || value != "" || !propValue.empty()) { + fOut() << "<" << tag; + for (size_t k = 0; k < propValue.size(); k++) { + fOut() << " " << propValue[k].first << "=\"" << encodeXML(propValue[k].second) << "\""; + } + if (!value.empty()) { + fOut() << ">" << encodeXML(value) + << "" << endl; + } + else + fOut() << "/>" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); + +} + + +void xmlparser::write(const char *tag, const char *prop, + bool propValue, const string &value) { + write(tag, prop, propValue ? "true" : "false", value); +} + +void xmlparser::write(const char *tag, const char *prop, + const char *propValue, const string &value) { + write(tag, prop, string(propValue), value); +} + + +void xmlparser::write(const char *tag, int Value) +{ + if (!cutMode || Value!=0) { + fOut() << "<" << tag << ">" + << Value + << "" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + +void xmlparser::writeBool(const char *tag, bool value) +{ + if (!cutMode || value) { + fOut() << "<" << tag << ">" + << (value ? "true" : "false") + << "" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + + +void xmlparser::write64(const char *tag, __int64 Value) +{ + if (!cutMode || Value!=0) { + fOut() << "<" << tag << ">" + << Value + << "" << endl; + } + if (!fOut().good()) + throw meosException("Writing to XML file failed."); +} + +void xmlparser::startTag(const char *tag, const char *prop, const string &Value) +{ + if (tagStackPointer<32) { + fOut() << "<" << tag << " " << prop << "=\"" << encodeXML(Value) << "\">" << endl; + tagStack[tagStackPointer++]=tag; + if (!fOut().good()) + throw meosException("Writing to XML file failed."); + } + else + throw meosException("Tag depth too large."); +} + +void xmlparser::startTag(const char *tag, const vector &propvalue) +{ + if (tagStackPointer<32) { + fOut() << "<" << tag << " "; + for (size_t k=0;k" << endl; + tagStack[tagStackPointer++]=tag; + if (!fOut().good()) + throw meosException("Writing to XML file failed."); + } + else + throw meosException("Tag depth too large."); +} + + +void xmlparser::startTag(const char *tag) +{ + if (tagStackPointer<32) { + fOut() << "<" << tag << ">" << endl; + tagStack[tagStackPointer++]=tag; + if (!fOut().good()) + throw meosException("Writing to XML file failed."); + } + else + throw meosException("Tag depth too large."); +} + +void xmlparser::endTag() +{ + if (tagStackPointer>0) { + fOut() << "" << endl; + if (!fOut().good()) + throw meosException("Writing to XML file failed."); + } + else throw std::exception("BAD XML CODE"); +} + +void xmlparser::openMemoryOutput(bool useCutMode) { + cutMode = useCutMode; + toString = true; + foutString.clear(); + if (utfConverter) + fOut() << "\n\n\n"; + else + fOut() << "\n\n\n"; + + string out = foutString.str(); +} + +void xmlparser::getMemoryOutput(string &res) { + res = foutString.str(); + foutString.clear(); +} + +void xmlparser::openOutput(const char *file, bool useCutMode) +{ + openOutputT(file, useCutMode, ""); +} + +void xmlparser::openOutputT(const char *file, bool useCutMode, const string &type) +{ + toString = false; + cutMode = useCutMode; + foutFile.open(file); + + tagStackPointer=0; + + if (foutFile.bad()) + throw meosException(string("Writing to XML file failed: ") + string(file)); + + if (utfConverter) + fOut() << "\n\n\n"; + else + fOut() << "\n\n\n"; + + if (!type.empty()) { + startTag(type.c_str()); + } + return; +} + +int xmlparser::closeOut() +{ + while(tagStackPointer>0) + endTag(); + + int len = foutFile.tellp(); + foutFile.close(); + + return len; +} + +xmldata::xmldata(const char *t, char *d) : tag(t), data(d) +{ + parent = -1; + next = 0; +} + +xmlattrib::xmlattrib(const char *t, char *d) : tag(t), data(d) {} + +void xmlparser::read(const string &file, int maxobj) +{ + fin.open(file.c_str(), ios::binary); + + if (!fin.good()) + throw meosException("Failed to open 'X' for reading.#" + string(file)); + + char bf[1024]; + bf[0]=0; + + do { + fin.getline(bf, 1024, '>'); + lineNumber++; + } + while(fin.good() && bf[0]==0); + + char *ptr=ltrim(bf); + isUTF = checkUTF(ptr); + int p1 = fin.tellg(); + + fin.seekg(0, ios::end); + int p2 = fin.tellg(); + fin.seekg(p1, ios::beg); + + int asize = p2-p1; + if (maxobj>0) + asize = min(asize, maxobj*256); + + if (progress && asize>80000) + progress->init(); + + xbf.resize(asize+1); + xmlinfo.clear(); + xbf.reserve(xbf.size() / 30); // Guess number of tags + + parseStack.clear(); + + fin.read(&xbf[0], xbf.size()); + xbf[asize] = 0; + + fin.close(); + + parse(maxobj); +} + +void xmlparser::readMemory(const string &mem, int maxobj) +{ + if (mem.empty()) + return; + + char bf[1024]; + bf[0] = mem[0]; + int i = 1; + int stop = min(1020, mem.length()); + while (i < stop && mem[i-1] != '>'){ + bf[i] = mem[i]; + i++; + } + bf[i] = 0; + + char *ptr=ltrim(bf); + isUTF = checkUTF(ptr); + int p1 = i; + int p2 = mem.size(); + + int asize = p2-p1; + if (maxobj>0) + asize = min(asize, maxobj*256); + + if (progress && asize>80000) + progress->init(); + + xbf.resize(asize+1); + xmlinfo.clear(); + xmlinfo.reserve(xbf.size() / 30); // Guess number of tags + + parseStack.clear(); + + memcpy(&xbf[0], mem.c_str() + p1, xbf.size()); + xbf[asize] = 0; + + parse(maxobj); +} + +bool xmlparser::checkUTF(const char *ptr) const { + bool utf = false; + + if (ptr[0] == -17 && ptr[1]==-69 && ptr[2]==-65) { + utf = true; + ptr+=3; //Windows UTF attribute + } + + if (memcmp(ptr, " 50000) { + progress->setProgress(int(500.0*pp/size)); + oldPrg = pp; + } + + // Found tag + if (xbf[pp] == '<') { + xbf[pp] = 0; + char *start = &xbf[pp+1]; + while (pp < size && xbf[pp] != '>') pp++; + + if (xbf[pp] == '>') { + xbf[pp] = 0; + } + if (*start=='!') + continue; //Comment + + processTag(start, &xbf[pp-1]); + } + + if (maxobj>0 && int(xmlinfo.size()) >= maxobj) { + xbf[pp+1] = 0; + return true; + } + pp++; + } + + lastIndex = 0; + return true; +} + +void inplaceDecodeXML(char *in); + +bool xmlparser::processTag(char *start, char *end) { + static char err[64]; + bool onlyAttrib = *end == '/'; + bool endTag = *start == '/'; + + char *tag = start; + + if (endTag) + tag++; + + while (start<=end && /**start!=' ' && *start!='\t'*/ !isBlankSpace(*start)) + start++; + + *start = 0; + + if (!endTag && !onlyAttrib) { + parseStack.push_back(xmlinfo.size()); + xmlinfo.push_back(xmldata(tag, end+2)); + int p = parseStack.size()-2; + xmlinfo.back().parent = p>=0 ? parseStack[p] : -1; + } + else if (endTag) { + if (!parseStack.empty()){ + xmldata &xd = xmlinfo[parseStack.back()]; + inplaceDecodeXML(xd.data); + if (strcmp(tag, xd.tag)== 0) { + parseStack.pop_back(); + xd.next = xmlinfo.size(); + } + else { + sprintf_s(err, "Unmatched tag '%s', expected '%s'.", tag, xd.tag); + throw std::exception(err); + } + } + else + { + sprintf_s(err, "Unmatched tag '%s'.", tag); + throw std::exception(err); + } + } + else if (onlyAttrib) { + *end = 0; + xmlinfo.push_back(xmldata(tag, 0)); + int p = parseStack.size() - 1; + xmlinfo.back().parent = p>=0 ? parseStack[p] : -1; + xmlinfo.back().next = xmlinfo.size(); + } + return true; +} + +char * xmlparser::ltrim(char *s) +{ + while(*s && isspace(BYTE(*s))) + s++; + + return s; +} + +const char * xmlparser::ltrim(const char *s) +{ + while(*s && isspace(BYTE(*s))) + s++; + + return s; +} +/* +const char * xmlparser::getError() +{ + return errorMessage.c_str(); +}*/ + +xmlobject xmlobject::getObject(const char *pname) const +{ + if (pname == 0) + return *this; + if (isnull()) + throw std::exception("Null pointer exception"); + + vector &xmlinfo = parser->xmlinfo; + + parser->access(index); + + unsigned child = index+1; + while (child < xmlinfo.size() && xmlinfo[child].parent == index) { + if (strcmp(xmlinfo[child].tag, pname)==0) + return xmlobject(parser, child); + else + child = xmlinfo[child].next; + } + return xmlobject(0); +} + + +void xmlobject::getObjects(xmlList &obj) const +{ + obj.clear(); + + if (isnull()) + throw std::exception("Null pointer exception"); + + vector &xmlinfo = parser->xmlinfo; + unsigned child = index+1; + parser->access(index); + + while (child < xmlinfo.size() && xmlinfo[child].parent == index) { + obj.push_back(xmlobject(parser, child)); + child = xmlinfo[child].next; + } +} + +void xmlobject::getObjects(const char *tag, xmlList &obj) const +{ + obj.clear(); + + if (isnull()) + throw std::exception("Null pointer exception"); + + vector &xmlinfo = parser->xmlinfo; + unsigned child = index+1; + parser->access(index); + + while (child < xmlinfo.size() && xmlinfo[child].parent == index) { + if (strcmp(tag, xmlinfo[child].tag) == 0) + obj.push_back(xmlobject(parser, child)); + child = xmlinfo[child].next; + } +} + + +const xmlobject xmlparser::getObject(const char *pname) const +{ + if (xmlinfo.size()>0){ + if (pname == 0 || strcmp(xmlinfo[0].tag, pname) == 0) + return xmlobject(const_cast(this), 0); + else return xmlobject(const_cast(this), 0).getObject(pname); + } + else return xmlobject(0); +} + +xmlattrib xmlobject::getAttrib(const char *pname) const +{ + if (pname != 0) { + char *start = const_cast(parser->xmlinfo[index].tag); + const char *end = parser->xmlinfo[index].data; + + if (end) + end-=2; + else { + if (size_t(index + 1) < parser->xmlinfo.size()) + end = parser->xmlinfo[index+1].tag; + else + end = &parser->xbf.back(); + } + + // Scan past tag. + while (start 0 || + _strcmpi(trim(tmp).c_str(), "true") == 0; +} + +string &xmlobject::getObjectString(const char *pname, string &out) const +{ + xmlobject x=getObject(pname); + if (x) { + const char *bf = x.get(); + if (bf) { + parser->convertString(x.get(), parser->strbuff, buff_pre_alloc); + out = parser->strbuff; + return out; + } + } + + xmlattrib xa(getAttrib(pname)); + if (xa && xa.data) { + parser->convertString(xa.get(), parser->strbuff, buff_pre_alloc); + out = parser->strbuff; + } + else + out = ""; + + return out; +} + +char *xmlobject::getObjectString(const char *pname, char *out, int maxlen) const +{ + xmlobject x=getObject(pname); + if (x) { + const char *bf = x.get(); + if (bf) { + parser->convertString(bf, out, maxlen); + return out; + } + } + else { + xmlattrib xa(getAttrib(pname)); + if (xa && xa.data) { + parser->convertString(xa.data, out, maxlen); + inplaceDecodeXML(out); + } else + out[0] = 0; + } + return out; +} + +const char *xmlattrib::get() const +{ + if (data) + return decodeXML(data); + else + return 0; +} diff --git a/code/xmlparser.h b/code/xmlparser.h new file mode 100644 index 0000000..8bc9732 --- /dev/null +++ b/code/xmlparser.h @@ -0,0 +1,223 @@ +// xmlparser.h: interface for the xmlparser class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_XMLPARSER_H__87834E6D_6AB1_471C_8E1C_E65D67A4F98A__INCLUDED_) +#define AFX_XMLPARSER_H__87834E6D_6AB1_471C_8E1C_E65D67A4F98A__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +/************************************************************************ + MeOS - Orienteering Software + Copyright (C) 2009-2017 Melin Software HB + + 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 3 of the License, 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, see . + + Melin Software HB - software@melin.nu - www.melin.nu + Eksoppsvägen 16, SE-75646 UPPSALA, Sweden + +************************************************************************/ + +#include +#include +class xmlobject; + +typedef vector xmlList; +class xmlparser; +class gdioutput; + +const int buff_pre_alloc = 1024 * 10; + +struct xmldata +{ + xmldata(const char *t, char *d); + const char *tag; + char *data; + int parent; + int next; +}; + +struct xmlattrib +{ + xmlattrib(const char *t, char *d); + const char *tag; + char *data; + operator bool() const {return data!=0;} + + int getInt() const {if (data) return atoi(data); else return 0;} + const char *get() const; +}; + +class ProgressWindow; + +class xmlparser +{ +protected: + static char *ltrim(char *s); + static const char *ltrim(const char *s); + + string tagStack[32]; + int tagStackPointer; + + bool toString; + ofstream foutFile; + ostringstream foutString; + + ifstream fin; + + std::ostream &fOut() { + if (toString) + return foutString; + else + return foutFile; + } + + int lineNumber; + string doctype; + + vector parseStack; + vector xmlinfo; + vector xbf; + + bool processTag(char *start, char *end); + + bool checkUTF(const char *ptr) const; + bool parse(int maxobj); + + void convertString(const char *in, char *out, int maxlen) const; + + // True if empty/zero values are excluded when writing + bool cutMode; + + bool isUTF; + char strbuff[buff_pre_alloc]; // Temporary buffer for processing (no threading allowed) + + ProgressWindow *progress; + int lastIndex; + + gdioutput *utfConverter; + +public: + void access(int index); + + void setProgress(HWND hWnd); + +// bool failed(){return errorMessage.length()>0;} + + const xmlobject getObject(const char *pname) const; +// const char *getError(); + + void read(const string &file, int maxobj = 0); + void readMemory(const string &mem, int maxobj); + + void write(const char *tag, const char *prop, + const string &value); + void write(const char *tag); // Empty case + void write(const char *tag, const char *prop, + const char *value); + void write(const char *tag, const char *prop, + const bool value); + void write(const char *tag, const char *prop, + const string &propValue, const string &value); + void write(const char *tag, const char *prop, + bool propValue, const string &value); + void write(const char *tag, const char *prop, + const char *propValue, const string &value); + void write(const char *tag, const vector< pair > &propValue, const string &value); + + void write(const char *tag, const string &value); + void write(const char *tag, int value); + + void writeBool(const char *tag, bool value); + void write64(const char *tag, __int64); + + void startTag(const char *tag); + void startTag(const char *tag, const char *Property, + const string &Value); + void startTag(const char *tag, const vector &propvalue); + + void endTag(); + int closeOut(); + void openOutput(const char *file, bool useCutMode); + void openOutputT(const char *file, bool useCutMode, const string &type); + + void openMemoryOutput(bool useCutMode); + void getMemoryOutput(string &res); + + + const string &encodeXML(const string &input); + + xmlparser(gdioutput *utfConverter); + virtual ~xmlparser(); + + friend class xmlobject; +}; + +class xmlobject +{ +protected: + xmlobject(xmlparser *p) {parser = p;} + xmlobject(xmlparser *p, int i) {parser = p; index = i;} + + xmlparser *parser; + int index; +public: + const char *getName() const {return parser->xmlinfo[index].tag;} + xmlobject getObject(const char *pname) const; + xmlattrib getAttrib(const char *pname) const; + + int getObjectInt(const char *pname) const + { + xmlobject x(getObject(pname)); + if (x) + return x.getInt(); + else { + xmlattrib xa(getAttrib(pname)); + if (xa) + return xa.getInt(); + } + return 0; + } + + bool getObjectBool(const char *pname) const; + + string &getObjectString(const char *pname, string &out) const; + char *getObjectString(const char *pname, char *out, int maxlen) const; + + void getObjects(xmlList &objects) const; + void getObjects(const char *tag, xmlList &objects) const; + + bool is(const char *pname) const { + const char *n = getName(); + return n[0] == pname[0] && strcmp(n, pname)==0; + } + + const char *get() const {return parser->xmlinfo[index].data;} + int getInt() const {const char *d = parser->xmlinfo[index].data; + return d ? atoi(d) : 0;} + __int64 getInt64() const {const char *d = parser->xmlinfo[index].data; + return d ? _atoi64(d) : 0;} + + bool isnull() const {return parser==0;} + + operator bool() const {return parser!=0;} + + xmlobject(); + virtual ~xmlobject(); + friend class xmlparser; +}; + + +#endif // !defined(AFX_XMLPARSER_H__87834E6D_6AB1_471C_8E1C_E65D67A4F98A__INCLUDED_) \ No newline at end of file diff --git a/code/zip.cpp b/code/zip.cpp new file mode 100644 index 0000000..cac1e46 --- /dev/null +++ b/code/zip.cpp @@ -0,0 +1,460 @@ +/* +Code is based on mini unzip, demo of unzip package. + +Ported to C++ and modified to suite MeOS. + +*/ + +#include "stdafx.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "meos_util.h" +#include "minizip/unzip.h" +#include "minizip/zip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (1024 * 256) +#define MAXFILENAME (260) + +#define USEWIN32IOAPI +#include "minizip/iowin32.h" + +const char *zipError = "Error processing zip-file"; + +/* change_file_date : change the date/time of a file +filename : the filename of the file where date/time must be modified +dosdate : the new date at the MSDos format (4 bytes) +tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) { + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +} + + +/* mymkdir and change_file_date are not 100 % portable +As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(const char *dirname) +{ + int ret=0; + ret = _mkdir(dirname); + return ret; +} + +int makedir (const char *newdir) +{ + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + string buffer = newdir; + + if (buffer[len-1] == '/') { + buffer = buffer.substr(0, len-1); + } + + if (mymkdir(buffer.c_str()) == 0) { + return 1; + } + + size_t index = 1; + while (index byteBuff; + byteBuff.resize(size_buf); + buf = (void *)&byteBuff[0]; + + p = filename_withoutpath = filename_inzip; + while ((*p) != '\0') { + if (((*p)=='/') || ((*p)=='\\')) + filename_withoutpath = p+1; + p++; + } + + if ((*filename_withoutpath)=='\0') { + if (createSubdir) + mymkdir(filename_inzip); + } + else { + + if (createSubdir) + write_filename = baseDir + filename_inzip; + else + write_filename = baseDir + filename_withoutpath; + + err = unzOpenCurrentFilePassword(uf,password); + if (err!=UNZ_OK) + throw std::exception(zipError); + + fout = fopen64(write_filename.c_str(),"wb"); + + // some zipfile doesn't contain directory alone before file + if ((fout==NULL) && createSubdir && + (filename_withoutpath!=(char*)filename_inzip)) { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename.c_str()); + *(filename_withoutpath-1)=c; + fout=fopen64(write_filename.c_str(),"wb"); + } + + if (fout==NULL) { + string err = "Error opening" + write_filename; + throw std::exception(err.c_str()); + } + + do { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + throw std::exception(zipError); + + if (err>0) + if (fwrite(buf,err,1,fout)!=1) { + throw std::exception("Error writing extracted file."); + } + } + while (err>0); + + if (fout) + fclose(fout); + + change_file_date(write_filename.c_str(),file_info.dosDate, file_info.tmu_date); + + + err = unzCloseCurrentFile (uf); + if (err != UNZ_OK) + throw std::exception(zipError); + } + + return write_filename; +} + + +void do_extract(unzFile uf, const char *basePath, const char* password, vector &extractedFiles) +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err != UNZ_OK) + throw std::exception(zipError); + + for (i=0;i &extractedFiles) +{ + extractedFiles.clear(); + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + unzFile uf = unzOpen2_64(zipfilename,&ffunc); + + if (uf==NULL) + throw std::exception("Cannot open zip file"); + + string base = getTempPath(); + char end = base[base.length()-1]; + if (end != '\\' && end != '/') + base += "\\"; + + int id = rand(); + string target; + do { + target = base + "zip" + itos(id) + "\\"; + id++; + } + while ( access( target.c_str(), 0 ) == 0 ); + + if (CreateDirectory(target.c_str(), NULL) == 0) + throw std::exception("Failed to create temporary folder"); + + registerTempFile(target); + + do_extract(uf, target.c_str(), password, extractedFiles); + + unzClose(uf); +} + + + +uLong filetime(const char *f, uLong *dt) { + int ret = 0; + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + return ret; +} + +int check_exist_file(const char* filename) +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen64(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +/* calculate the CRC32 of a file, because to encrypt a file, we need known the CRC32 of the file before */ +/*int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen64(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +}*/ + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = fopen64(filename, "rb"); + + if (pFile != NULL) { + fseeko64(pFile, 0, SEEK_END); + pos = ftello64(pFile); + if (pos >= 0xffffffff) + largeFile = 1; + fclose(pFile); + } + + return largeFile; +} + +int zip(const char *zipfilename, const char *password, const vector &files) { + int opt_compress_level=Z_DEFAULT_COMPRESSION; + const int opt_exclude_path = 1; + char filename_try[MAXFILENAME+16]; + int err=0; + int size_buf=0; + char eb[256]; + + size_buf = WRITEBUFFERSIZE; + vector vbuff(size_buf, 0); + void * buf = (void*)&vbuff[0]; + + zipFile zf; + int errclose; + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + strcpy(filename_try, zipfilename); + zf = zipOpen2_64(filename_try, 0,NULL, &ffunc); + + if (zf == NULL) { + sprintf_s(eb, "Error opening %s.",filename_try); + throw std::exception(eb); + } + + for (size_t i=0; i < files.size(); i++) { + FILE * fin; + int size_read; + const char* filenameinzip = files[i].c_str(); + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip, &zi.dosDate); + +/* + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + */ + zip64 = isLargeFile(filenameinzip); + + /* The path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if ( opt_exclude_path ) { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) { + if ( *tmpptr == '\\' || *tmpptr == '/') + lastslash = tmpptr; + } + if ( lastslash != NULL ) { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) { + sprintf_s(eb, "Error opening %s in zipfile",filenameinzip); + throw std::exception(eb); + } + else { + fin = fopen64(filenameinzip,"rb"); + if (fin==NULL) { + sprintf_s(eb, "Error opening %s for reading",filenameinzip); + throw std::exception(eb); + } + } + + if (err == ZIP_OK) + do { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) { + if (feof(fin)==0) { + sprintf_s(eb, "Error reading %s",filenameinzip); + throw std::exception(eb); + } + } + + if (size_read > 0) { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) { + sprintf_s(eb, "Error in writing %s in the zipfile",filenameinzip); + throw std::exception(eb); + } + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) { + sprintf_s(eb, "Error closing %s in the zipfile", filenameinzip); + throw std::exception(eb); + } + } + } + + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) { + sprintf_s(eb, "Error closing %s",filename_try); + throw std::exception(eb); + } + + return 0; +}